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;
16
17 import org.htmlunit.SgmlPage;
18 import org.htmlunit.WebAssert;
19 import org.htmlunit.html.xpath.XPathHelper;
20 import org.htmlunit.javascript.host.dom.Document;
21 import org.htmlunit.util.StringUtils;
22
23 /**
24 * Intermediate base class for DOM Nodes that have namespaces. That includes HtmlElement and HtmlAttr.
25 *
26 * @author David K. Taylor
27 * @author Ahmed Ashour
28 * @author Ronald Brill
29 * @author Frank Danek
30 */
31 public abstract class DomNamespaceNode extends DomNode {
32
33 private String namespaceURI_;
34 private String qualifiedName_;
35 private final String localName_;
36 private final String localNameLC_;
37 private String prefix_;
38
39 /**
40 * Creates an instance of a DOM node that can have a namespace.
41 *
42 * @param namespaceURI the URI that identifies an XML namespace
43 * @param qualifiedName the qualified name of the element type to instantiate
44 * @param page the page that contains this element
45 */
46 protected DomNamespaceNode(final String namespaceURI, final String qualifiedName, final SgmlPage page) {
47 super(page);
48 WebAssert.notNull("qualifiedName", qualifiedName);
49 qualifiedName_ = qualifiedName;
50 namespaceURI_ = namespaceURI;
51
52 final int colonPosition = qualifiedName_.indexOf(':');
53 if (colonPosition == -1) {
54 localName_ = qualifiedName_;
55 prefix_ = null;
56 }
57 else {
58 localName_ = qualifiedName_.substring(colonPosition + 1);
59 prefix_ = qualifiedName_.substring(0, colonPosition);
60 }
61
62 localNameLC_ = StringUtils.toRootLowerCase(localName_);
63 }
64
65 /**
66 * {@inheritDoc}
67 */
68 @Override
69 public String getNamespaceURI() {
70 if (getPage().isHtmlPage()
71 && !(getPage() instanceof XHtmlPage)
72 && Html.XHTML_NAMESPACE.equals(namespaceURI_)
73 && XPathHelper.isProcessingXPath()) {
74 // for xpath processing we have to strip the 'default' XHTML namespace for HTML pages to be able to find
75 // the elements by XPath without needing to add the namespace to it
76 return null;
77 }
78 return namespaceURI_;
79 }
80
81 /**
82 * {@inheritDoc}
83 */
84 @Override
85 public String getLocalName() {
86 final boolean caseSensitive = getPage().hasCaseSensitiveTagNames();
87 if (!caseSensitive
88 && XPathHelper.isProcessingXPath()) { // and this method was called from xpath processor
89 return localNameLC_;
90 }
91 return localName_;
92 }
93
94 /**
95 * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
96 * @return the element name as lowercase
97 */
98 public String getLowercaseName() {
99 return localNameLC_;
100 }
101
102 /**
103 * {@inheritDoc}
104 */
105 @Override
106 public String getPrefix() {
107 return prefix_;
108 }
109
110 /**
111 * {@inheritDoc}
112 */
113 @Override
114 public void setPrefix(final String prefix) {
115 prefix_ = prefix;
116 if (prefix_ != null && localName_ != null) {
117 qualifiedName_ = prefix_ + ":" + localName_;
118 }
119 }
120
121 /**
122 * Returns this node's qualified name.
123 * @return this node's qualified name
124 */
125 public String getQualifiedName() {
126 return qualifiedName_;
127 }
128
129 /**
130 * {@inheritDoc}
131 */
132 @Override
133 public void processImportNode(final Document doc) {
134 super.processImportNode(doc);
135
136 // if we are importing from a namespace-aware source
137 // we have to drop the XHtmlNamespace because we did this already
138 // for the HTML document itself
139 final SgmlPage page = (SgmlPage) doc.getDomNodeOrDie();
140 if (page.isHtmlPage() && !(page instanceof XHtmlPage) && Html.XHTML_NAMESPACE.equals(namespaceURI_)) {
141 namespaceURI_ = null;
142 }
143 }
144 }