2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
19 * $Id: DOM2DTMdefaultNamespaceDeclarationNode.java 468653 2006-10-28 07:07:05Z minchau $
22 package org.apache.xml.dtm.ref.dom2dtm;
24 import org.apache.xml.dtm.DTMException;
26 import org.w3c.dom.Attr;
27 import org.w3c.dom.Document;
28 import org.w3c.dom.Element;
29 import org.w3c.dom.NamedNodeMap;
30 import org.w3c.dom.Node;
31 import org.w3c.dom.NodeList;
32 import org.w3c.dom.TypeInfo;
33 import org.w3c.dom.UserDataHandler;
34 import org.w3c.dom.DOMException;
36 /** This is a kluge to let us shove a declaration for xml: into the
37 * DOM2DTM model. Basically, it creates a proxy node in DOM space to
38 * carry the additional information. This is _NOT_ a full DOM
39 * implementation, and shouldn't be one since it sits alongside the
40 * DOM rather than becoming part of the DOM model.
42 * (This used to be an internal class within DOM2DTM. Moved out because
43 * I need to perform an instanceof operation on it to support a temporary
44 * workaround in DTMManagerDefault.)
46 * %REVIEW% What if the DOM2DTM was built around a DocumentFragment and
47 * there isn't a single root element? I think this fails that case...
49 * %REVIEW% An alternative solution would be to create the node _only_
50 * in DTM space, but given how DOM2DTM is currently written I think
53 public class DOM2DTMdefaultNamespaceDeclarationNode implements Attr,TypeInfo
55 final String NOT_SUPPORTED_ERR="Unsupported operation on pseudonode";
58 String prefix,uri,nodename;
60 DOM2DTMdefaultNamespaceDeclarationNode(Element pseudoparent,String prefix,String uri,int handle)
62 this.pseudoparent=pseudoparent;
66 this.nodename="xmlns:"+prefix;
68 public String getNodeName() {return nodename;}
69 public String getName() {return nodename;}
70 public String getNamespaceURI() {return "http://www.w3.org/2000/xmlns/";}
71 public String getPrefix() {return prefix;}
72 public String getLocalName() {return prefix;}
73 public String getNodeValue() {return uri;}
74 public String getValue() {return uri;}
75 public Element getOwnerElement() {return pseudoparent;}
77 public boolean isSupported(String feature, String version) {return false;}
78 public boolean hasChildNodes() {return false;}
79 public boolean hasAttributes() {return false;}
80 public Node getParentNode() {return null;}
81 public Node getFirstChild() {return null;}
82 public Node getLastChild() {return null;}
83 public Node getPreviousSibling() {return null;}
84 public Node getNextSibling() {return null;}
85 public boolean getSpecified() {return false;}
86 public void normalize() {return;}
87 public NodeList getChildNodes() {return null;}
88 public NamedNodeMap getAttributes() {return null;}
89 public short getNodeType() {return Node.ATTRIBUTE_NODE;}
90 public void setNodeValue(String value) {throw new DTMException(NOT_SUPPORTED_ERR);}
91 public void setValue(String value) {throw new DTMException(NOT_SUPPORTED_ERR);}
92 public void setPrefix(String value) {throw new DTMException(NOT_SUPPORTED_ERR);}
93 public Node insertBefore(Node a, Node b) {throw new DTMException(NOT_SUPPORTED_ERR);}
94 public Node replaceChild(Node a, Node b) {throw new DTMException(NOT_SUPPORTED_ERR);}
95 public Node appendChild(Node a) {throw new DTMException(NOT_SUPPORTED_ERR);}
96 public Node removeChild(Node a) {throw new DTMException(NOT_SUPPORTED_ERR);}
97 public Document getOwnerDocument() {return pseudoparent.getOwnerDocument();}
98 public Node cloneNode(boolean deep) {throw new DTMException(NOT_SUPPORTED_ERR);}
100 /** Non-DOM method, part of the temporary kluge
101 * %REVIEW% This would be a pruning problem, but since it will always be
102 * added to the root element and we prune on elements, we shouldn't have
105 public int getHandleOfNode()
110 //RAMESH: PENDING=> Add proper implementation for the below DOM L3 additions
113 * @see org.w3c.dom.TypeInfo#getTypeName()
115 public String getTypeName() {return null; }
118 * @see org.w3c.dom.TypeInfo#getTypeNamespace()
120 public String getTypeNamespace() { return null;}
123 * @see or.gw3c.dom.TypeInfo#isDerivedFrom(String,String,int)
125 public boolean isDerivedFrom( String ns, String localName, int derivationMethod ) {
129 public TypeInfo getSchemaTypeInfo() { return this; }
131 public boolean isId( ) { return false; }
134 * Associate an object to a key on this node. The object can later be
135 * retrieved from this node by calling <code>getUserData</code> with the
137 * @param key The key to associate the object to.
138 * @param data The object to associate to the given key, or
139 * <code>null</code> to remove any existing association to that key.
140 * @param handler The handler to associate to that key, or
142 * @return Returns the <code>DOMObject</code> previously associated to
143 * the given key on this node, or <code>null</code> if there was none.
146 public Object setUserData(String key,
148 UserDataHandler handler) {
149 return getOwnerDocument().setUserData( key, data, handler);
153 * Retrieves the object associated to a key on a this node. The object
154 * must first have been set to this node by calling
155 * <code>setUserData</code> with the same key.
156 * @param key The key the object is associated to.
157 * @return Returns the <code>DOMObject</code> associated to the given key
158 * on this node, or <code>null</code> if there was none.
161 public Object getUserData(String key) {
162 return getOwnerDocument().getUserData( key);
166 * This method returns a specialized object which implements the
167 * specialized APIs of the specified feature and version. The
168 * specialized object may also be obtained by using binding-specific
169 * casting methods but is not necessarily expected to, as discussed in Mixed DOM implementations.
170 * @param feature The name of the feature requested (case-insensitive).
171 * @param version This is the version number of the feature to test. If
172 * the version is <code>null</code> or the empty string, supporting
173 * any version of the feature will cause the method to return an
174 * object that supports at least one version of the feature.
175 * @return Returns an object which implements the specialized APIs of
176 * the specified feature and version, if any, or <code>null</code> if
177 * there is no object which implements interfaces associated with that
178 * feature. If the <code>DOMObject</code> returned by this method
179 * implements the <code>Node</code> interface, it must delegate to the
180 * primary core <code>Node</code> and not return results inconsistent
181 * with the primary core <code>Node</code> such as attributes,
185 public Object getFeature(String feature, String version) {
186 // we don't have any alternate node, either this node does the job
187 // or we don't have anything that does
188 return isSupported(feature, version) ? this : null;
192 * Tests whether two nodes are equal.
193 * <br>This method tests for equality of nodes, not sameness (i.e.,
194 * whether the two nodes are references to the same object) which can be
195 * tested with <code>Node.isSameNode</code>. All nodes that are the same
196 * will also be equal, though the reverse may not be true.
197 * <br>Two nodes are equal if and only if the following conditions are
198 * satisfied: The two nodes are of the same type.The following string
199 * attributes are equal: <code>nodeName</code>, <code>localName</code>,
200 * <code>namespaceURI</code>, <code>prefix</code>, <code>nodeValue</code>
201 * , <code>baseURI</code>. This is: they are both <code>null</code>, or
202 * they have the same length and are character for character identical.
203 * The <code>attributes</code> <code>NamedNodeMaps</code> are equal.
204 * This is: they are both <code>null</code>, or they have the same
205 * length and for each node that exists in one map there is a node that
206 * exists in the other map and is equal, although not necessarily at the
207 * same index.The <code>childNodes</code> <code>NodeLists</code> are
208 * equal. This is: they are both <code>null</code>, or they have the
209 * same length and contain equal nodes at the same index. This is true
210 * for <code>Attr</code> nodes as for any other type of node. Note that
211 * normalization can affect equality; to avoid this, nodes should be
212 * normalized before being compared.
213 * <br>For two <code>DocumentType</code> nodes to be equal, the following
214 * conditions must also be satisfied: The following string attributes
215 * are equal: <code>publicId</code>, <code>systemId</code>,
216 * <code>internalSubset</code>.The <code>entities</code>
217 * <code>NamedNodeMaps</code> are equal.The <code>notations</code>
218 * <code>NamedNodeMaps</code> are equal.
219 * <br>On the other hand, the following do not affect equality: the
220 * <code>ownerDocument</code> attribute, the <code>specified</code>
221 * attribute for <code>Attr</code> nodes, the
222 * <code>isWhitespaceInElementContent</code> attribute for
223 * <code>Text</code> nodes, as well as any user data or event listeners
224 * registered on the nodes.
225 * @param arg The node to compare equality with.
226 * @param deep If <code>true</code>, recursively compare the subtrees; if
227 * <code>false</code>, compare only the nodes themselves (and its
228 * attributes, if it is an <code>Element</code>).
229 * @return If the nodes, and possibly subtrees are equal,
230 * <code>true</code> otherwise <code>false</code>.
233 public boolean isEqualNode(Node arg) {
237 if (arg.getNodeType() != getNodeType()) {
240 // in theory nodeName can't be null but better be careful
241 // who knows what other implementations may be doing?...
242 if (getNodeName() == null) {
243 if (arg.getNodeName() != null) {
247 else if (!getNodeName().equals(arg.getNodeName())) {
251 if (getLocalName() == null) {
252 if (arg.getLocalName() != null) {
256 else if (!getLocalName().equals(arg.getLocalName())) {
260 if (getNamespaceURI() == null) {
261 if (arg.getNamespaceURI() != null) {
265 else if (!getNamespaceURI().equals(arg.getNamespaceURI())) {
269 if (getPrefix() == null) {
270 if (arg.getPrefix() != null) {
274 else if (!getPrefix().equals(arg.getPrefix())) {
278 if (getNodeValue() == null) {
279 if (arg.getNodeValue() != null) {
283 else if (!getNodeValue().equals(arg.getNodeValue())) {
287 if (getBaseURI() == null) {
288 if (((NodeImpl) arg).getBaseURI() != null) {
292 else if (!getBaseURI().equals(((NodeImpl) arg).getBaseURI())) {
301 * DOM Level 3 - Experimental:
302 * Look up the namespace URI associated to the given prefix, starting from this node.
303 * Use lookupNamespaceURI(null) to lookup the default namespace
305 * @param namespaceURI
306 * @return th URI for the namespace
309 public String lookupNamespaceURI(String specifiedPrefix) {
310 short type = this.getNodeType();
312 case Node.ELEMENT_NODE : {
314 String namespace = this.getNamespaceURI();
315 String prefix = this.getPrefix();
316 if (namespace !=null) {
317 // REVISIT: is it possible that prefix is empty string?
318 if (specifiedPrefix== null && prefix==specifiedPrefix) {
319 // looking for default namespace
321 } else if (prefix != null && prefix.equals(specifiedPrefix)) {
322 // non default namespace
326 if (this.hasAttributes()) {
327 NamedNodeMap map = this.getAttributes();
328 int length = map.getLength();
329 for (int i=0;i<length;i++) {
330 Node attr = map.item(i);
331 String attrPrefix = attr.getPrefix();
332 String value = attr.getNodeValue();
333 namespace = attr.getNamespaceURI();
334 if (namespace !=null && namespace.equals("http://www.w3.org/2000/xmlns/")) {
335 // at this point we are dealing with DOM Level 2 nodes only
336 if (specifiedPrefix == null &&
337 attr.getNodeName().equals("xmlns")) {
340 } else if (attrPrefix !=null &&
341 attrPrefix.equals("xmlns") &&
342 attr.getLocalName().equals(specifiedPrefix)) {
343 // non default namespace
350 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
351 if (ancestor != null) {
352 return ancestor.lookupNamespaceURI(specifiedPrefix);
361 case Node.DOCUMENT_NODE : {
362 return((NodeImpl)((Document)this).getDocumentElement()).lookupNamespaceURI(specifiedPrefix) ;
365 case Node.ENTITY_NODE :
366 case Node.NOTATION_NODE:
367 case Node.DOCUMENT_FRAGMENT_NODE:
368 case Node.DOCUMENT_TYPE_NODE:
371 case Node.ATTRIBUTE_NODE:{
372 if (this.getOwnerElement().getNodeType() == Node.ELEMENT_NODE) {
373 return getOwnerElement().lookupNamespaceURI(specifiedPrefix);
380 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
381 if (ancestor != null) {
382 return ancestor.lookupNamespaceURI(specifiedPrefix);
392 * DOM Level 3: Experimental
393 * This method checks if the specified <code>namespaceURI</code> is the
394 * default namespace or not.
395 * @param namespaceURI The namespace URI to look for.
396 * @return <code>true</code> if the specified <code>namespaceURI</code>
397 * is the default namespace, <code>false</code> otherwise.
400 public boolean isDefaultNamespace(String namespaceURI){
402 // REVISIT: remove casts when DOM L3 becomes REC.
403 short type = this.getNodeType();
405 case Node.ELEMENT_NODE: {
406 String namespace = this.getNamespaceURI();
407 String prefix = this.getPrefix();
409 // REVISIT: is it possible that prefix is empty string?
410 if (prefix == null || prefix.length() == 0) {
411 if (namespaceURI == null) {
412 return (namespace == namespaceURI);
414 return namespaceURI.equals(namespace);
416 if (this.hasAttributes()) {
417 ElementImpl elem = (ElementImpl)this;
418 NodeImpl attr = (NodeImpl)elem.getAttributeNodeNS("http://www.w3.org/2000/xmlns/", "xmlns");
420 String value = attr.getNodeValue();
421 if (namespaceURI == null) {
422 return (namespace == value);
424 return namespaceURI.equals(value);
428 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
429 if (ancestor != null) {
430 return ancestor.isDefaultNamespace(namespaceURI);
434 case Node.DOCUMENT_NODE:{
435 return((NodeImpl)((Document)this).getDocumentElement()).isDefaultNamespace(namespaceURI);
438 case Node.ENTITY_NODE :
439 case Node.NOTATION_NODE:
440 case Node.DOCUMENT_FRAGMENT_NODE:
441 case Node.DOCUMENT_TYPE_NODE:
444 case Node.ATTRIBUTE_NODE:{
445 if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
446 return ownerNode.isDefaultNamespace(namespaceURI);
452 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
453 if (ancestor != null) {
454 return ancestor.isDefaultNamespace(namespaceURI);
468 * DOM Level 3 - Experimental:
469 * Look up the prefix associated to the given namespace URI, starting from this node.
471 * @param namespaceURI
472 * @return the prefix for the namespace
474 public String lookupPrefix(String namespaceURI){
476 // REVISIT: When Namespaces 1.1 comes out this may not be true
477 // Prefix can't be bound to null namespace
478 if (namespaceURI == null) {
482 short type = this.getNodeType();
486 case Node.ELEMENT_NODE: {
488 String namespace = this.getNamespaceURI(); // to flip out children
489 return lookupNamespacePrefix(namespaceURI, (ElementImpl)this);
492 case Node.DOCUMENT_NODE:{
493 return((NodeImpl)((Document)this).getDocumentElement()).lookupPrefix(namespaceURI);
496 case Node.ENTITY_NODE :
497 case Node.NOTATION_NODE:
498 case Node.DOCUMENT_FRAGMENT_NODE:
499 case Node.DOCUMENT_TYPE_NODE:
502 case Node.ATTRIBUTE_NODE:{
503 if (this.getOwnerElement().getNodeType() == Node.ELEMENT_NODE) {
504 return getOwnerElement().lookupPrefix(namespaceURI);
511 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
512 if (ancestor != null) {
513 return ancestor.lookupPrefix(namespaceURI);
522 * Returns whether this node is the same node as the given one.
523 * <br>This method provides a way to determine whether two
524 * <code>Node</code> references returned by the implementation reference
525 * the same object. When two <code>Node</code> references are references
526 * to the same object, even if through a proxy, the references may be
527 * used completely interchangably, such that all attributes have the
528 * same values and calling the same DOM method on either reference
529 * always has exactly the same effect.
530 * @param other The node to test against.
531 * @return Returns <code>true</code> if the nodes are the same,
532 * <code>false</code> otherwise.
535 public boolean isSameNode(Node other) {
536 // we do not use any wrapper so the answer is obvious
537 return this == other;
541 * This attribute returns the text content of this node and its
542 * descendants. When it is defined to be null, setting it has no effect.
543 * When set, any possible children this node may have are removed and
544 * replaced by a single <code>Text</code> node containing the string
545 * this attribute is set to. On getting, no serialization is performed,
546 * the returned string does not contain any markup. No whitespace
547 * normalization is performed, the returned string does not contain the
548 * element content whitespaces . Similarly, on setting, no parsing is
549 * performed either, the input string is taken as pure textual content.
550 * <br>The string returned is made of the text content of this node
551 * depending on its type, as defined below:
558 * <td valign='top' rowspan='1' colspan='1'>
559 * ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
560 * DOCUMENT_FRAGMENT_NODE</td>
561 * <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
562 * attribute value of every child node, excluding COMMENT_NODE and
563 * PROCESSING_INSTRUCTION_NODE nodes</td>
566 * <td valign='top' rowspan='1' colspan='1'>ATTRIBUTE_NODE, TEXT_NODE,
567 * CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE</td>
568 * <td valign='top' rowspan='1' colspan='1'>
569 * <code>nodeValue</code></td>
572 * <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
573 * <td valign='top' rowspan='1' colspan='1'>
577 * @exception DOMException
578 * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
579 * @exception DOMException
580 * DOMSTRING_SIZE_ERR: Raised when it would return more characters than
581 * fit in a <code>DOMString</code> variable on the implementation
585 public void setTextContent(String textContent)
586 throws DOMException {
587 setNodeValue(textContent);
591 * This attribute returns the text content of this node and its
592 * descendants. When it is defined to be null, setting it has no effect.
593 * When set, any possible children this node may have are removed and
594 * replaced by a single <code>Text</code> node containing the string
595 * this attribute is set to. On getting, no serialization is performed,
596 * the returned string does not contain any markup. No whitespace
597 * normalization is performed, the returned string does not contain the
598 * element content whitespaces . Similarly, on setting, no parsing is
599 * performed either, the input string is taken as pure textual content.
600 * <br>The string returned is made of the text content of this node
601 * depending on its type, as defined below:
608 * <td valign='top' rowspan='1' colspan='1'>
609 * ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
610 * DOCUMENT_FRAGMENT_NODE</td>
611 * <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
612 * attribute value of every child node, excluding COMMENT_NODE and
613 * PROCESSING_INSTRUCTION_NODE nodes</td>
616 * <td valign='top' rowspan='1' colspan='1'>ATTRIBUTE_NODE, TEXT_NODE,
617 * CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE</td>
618 * <td valign='top' rowspan='1' colspan='1'>
619 * <code>nodeValue</code></td>
622 * <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
623 * <td valign='top' rowspan='1' colspan='1'>
627 * @exception DOMException
628 * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
629 * @exception DOMException
630 * DOMSTRING_SIZE_ERR: Raised when it would return more characters than
631 * fit in a <code>DOMString</code> variable on the implementation
635 public String getTextContent() throws DOMException {
636 return getNodeValue(); // overriden in some subclasses
640 * Compares a node with this node with regard to their position in the
642 * @param other The node to compare against this node.
643 * @return Returns how the given node is positioned relatively to this
647 public short compareDocumentPosition(Node other) throws DOMException {
652 * The absolute base URI of this node or <code>null</code> if undefined.
653 * This value is computed according to . However, when the
654 * <code>Document</code> supports the feature "HTML" , the base URI is
655 * computed using first the value of the href attribute of the HTML BASE
656 * element if any, and the value of the <code>documentURI</code>
657 * attribute from the <code>Document</code> interface otherwise.
658 * <br> When the node is an <code>Element</code>, a <code>Document</code>
659 * or a a <code>ProcessingInstruction</code>, this attribute represents
660 * the properties [base URI] defined in . When the node is a
661 * <code>Notation</code>, an <code>Entity</code>, or an
662 * <code>EntityReference</code>, this attribute represents the
663 * properties [declaration base URI] in the . How will this be affected
664 * by resolution of relative namespace URIs issue?It's not.Should this
665 * only be on Document, Element, ProcessingInstruction, Entity, and
666 * Notation nodes, according to the infoset? If not, what is it equal to
667 * on other nodes? Null? An empty string? I think it should be the
668 * parent's.No.Should this be read-only and computed or and actual
669 * read-write attribute?Read-only and computed (F2F 19 Jun 2000 and
670 * teleconference 30 May 2001).If the base HTML element is not yet
671 * attached to a document, does the insert change the Document.baseURI?
672 * Yes. (F2F 26 Sep 2001)
675 public String getBaseURI() {