View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html.xpath;
16  
17  import java.util.Map;
18  
19  import org.htmlunit.html.DomAttr;
20  import org.htmlunit.html.DomElement;
21  import org.htmlunit.html.DomNode;
22  import org.htmlunit.xml.XmlPage;
23  import org.htmlunit.xpath.xml.utils.PrefixResolverDefault;
24  import org.w3c.dom.Node;
25  
26  /**
27   * Custom {@link PrefixResolverDefault} extension.
28   *
29   * @author Ahmed Ashour
30   * @author Ronald Brill
31   */
32  public final class HtmlUnitPrefixResolver extends PrefixResolverDefault {
33  
34      /**
35       * Creates a new instance.
36       * @param xpathExpressionContext the context from which XPath expression prefixes will be resolved
37       */
38      public HtmlUnitPrefixResolver(final Node xpathExpressionContext) {
39          super(xpathExpressionContext);
40      }
41  
42      /**
43       * {@inheritDoc}
44       */
45      @Override
46      public String getNamespaceForPrefix(final String prefix, final Node namespaceContext) {
47          String namespace = super.getNamespaceForPrefix(prefix, namespaceContext);
48          if (namespace == null) {
49              if (namespaceContext instanceof XmlPage) {
50                  final DomElement documentElement = ((XmlPage) namespaceContext).getDocumentElement();
51                  if (documentElement != null) {
52                      namespace = getNamespace(documentElement, prefix);
53                  }
54              }
55              else if (namespaceContext instanceof DomElement) {
56                  namespace = getNamespace((DomElement) namespaceContext, prefix);
57              }
58          }
59          return namespace;
60      }
61  
62      private String getNamespace(final DomElement element, final String prefix) {
63          final Map<String, DomAttr> attributes = element.getAttributesMap();
64          final String xmlns = "xmlns:";
65          final int xmlnsLength = xmlns.length();
66  
67          for (final Map.Entry<String, DomAttr> entry : attributes.entrySet()) {
68              final String name = entry.getKey();
69              if (name.startsWith(xmlns) && name.regionMatches(xmlnsLength, prefix, 0, prefix.length())) {
70                  return entry.getValue().getValue();
71              }
72          }
73          for (final DomNode child : element.getChildren()) {
74              if (child instanceof DomElement) {
75                  final String namespace = getNamespace((DomElement) child, prefix);
76                  if (namespace != null) {
77                      return namespace;
78                  }
79              }
80          }
81          return null;
82      }
83  }