2
* The Apache Software License, Version 1.1
5
* Copyright (c) 1999-2002 The Apache Software Foundation. All rights
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in
17
* the documentation and/or other materials provided with the
20
* 3. The end-user documentation included with the redistribution,
21
* if any, must include the following acknowledgment:
22
* "This product includes software developed by the
23
* Apache Software Foundation (http://www.apache.org/)."
24
* Alternately, this acknowledgment may appear in the software itself,
25
* if and wherever such third-party acknowledgments normally appear.
27
* 4. The names "Xerces" and "Apache Software Foundation" must
28
* not be used to endorse or promote products derived from this
29
* software without prior written permission. For written
30
* permission, please contact apache@apache.org.
32
* 5. Products derived from this software may not be called "Apache",
33
* nor may "Apache" appear in their name, without prior written
34
* permission of the Apache Software Foundation.
36
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48
* ====================================================================
50
* This software consists of voluntary contributions made by many
51
* individuals on behalf of the Apache Software Foundation and was
52
* originally based on software copyright (c) 1999, International
53
* Business Machines, Inc., http://www.apache.org. For more
54
* information on the Apache Software Foundation, please see
55
* <http://www.apache.org/>.
58
package org.apache.xerces.dom;
60
import java.io.IOException;
61
import java.io.ObjectOutputStream;
62
import java.io.Serializable;
64
import org.apache.xerces.dom3.UserDataHandler;
65
import org.w3c.dom.DOMException;
66
import org.w3c.dom.Document;
67
import org.w3c.dom.DocumentType;
68
import org.w3c.dom.NamedNodeMap;
69
import org.w3c.dom.Node;
70
import org.w3c.dom.NodeList;
71
import org.w3c.dom.events.Event;
72
import org.w3c.dom.events.EventListener;
73
import org.w3c.dom.events.EventTarget;
76
* NodeImpl provides the basic structure of a DOM tree. It is never used
77
* directly, but instead is subclassed to add type and data
78
* information, and additional methods, appropriate to each node of
79
* the tree. Only its subclasses should be instantiated -- and those,
80
* with the exception of Document itself, only through a specific
81
* Document's factory methods.
83
* The Node interface provides shared behaviors such as siblings and
84
* children, both for consistancy and so that the most common tree
85
* operations may be performed without constantly having to downcast
86
* to specific node types. When there is no obvious mapping for one of
87
* these queries, it will respond with null.
88
* Note that the default behavior is that children are forbidden. To
89
* permit them, the subclass ParentNode overrides several methods.
91
* NodeImpl also implements NodeList, so it can return itself in
92
* response to the getChildNodes() query. This eliminiates the need
93
* for a separate ChildNodeList object. Note that this is an
94
* IMPLEMENTATION DETAIL; applications should _never_ assume that
95
* this identity exists.
97
* All nodes in a single document must originate
98
* in that document. (Note that this is much tighter than "must be
99
* same implementation") Nodes are all aware of their ownerDocument,
100
* and attempts to mismatch will throw WRONG_DOCUMENT_ERR.
102
* However, to save memory not all nodes always have a direct reference
103
* to their ownerDocument. When a node is owned by another node it relies
104
* on its owner to store its ownerDocument. Parent nodes always store it
105
* though, so there is never more than one level of indirection.
106
* And when a node doesn't have an owner, ownerNode refers to its
109
* This class doesn't directly support mutation events, however, it still
110
* implements the EventTarget interface and forward all related calls to the
111
* document so that the document class do so.
113
* @author Arnaud Le Hors, IBM
114
* @author Joe Kesselman, IBM
115
* @version $Id: NodeImpl.java,v 1.71 2004/01/16 16:23:50 elena Exp $
116
* @since PR-DOM-Level-1-19980818.
118
public abstract class NodeImpl
119
implements Node, NodeList, EventTarget, Cloneable, Serializable{
126
// TreePosition Constants.
127
// Taken from DOM L3 Node interface.
129
* The node precedes the reference node.
131
public static final short TREE_POSITION_PRECEDING = 0x01;
133
* The node follows the reference node.
135
public static final short TREE_POSITION_FOLLOWING = 0x02;
137
* The node is an ancestor of the reference node.
139
public static final short TREE_POSITION_ANCESTOR = 0x04;
141
* The node is a descendant of the reference node.
143
public static final short TREE_POSITION_DESCENDANT = 0x08;
145
* The two nodes have an equivalent position. This is the case of two
146
* attributes that have the same <code>ownerElement</code>, and two
147
* nodes that are the same.
149
public static final short TREE_POSITION_EQUIVALENT = 0x10;
151
* The two nodes are the same. Two nodes that are the same have an
152
* equivalent position, though the reverse may not be true.
154
public static final short TREE_POSITION_SAME_NODE = 0x20;
156
* The two nodes are disconnected, they do not have any common ancestor.
157
* This is the case of two nodes that are not in the same document.
159
public static final short TREE_POSITION_DISCONNECTED = 0x00;
163
public static final short DOCUMENT_POSITION_DISCONNECTED = 0x01;
164
public static final short DOCUMENT_POSITION_PRECEDING = 0x02;
165
public static final short DOCUMENT_POSITION_FOLLOWING = 0x04;
166
public static final short DOCUMENT_POSITION_CONTAINS = 0x08;
167
public static final short DOCUMENT_POSITION_IS_CONTAINED = 0x10;
168
public static final short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
170
/** Serialization version. */
171
static final long serialVersionUID = -6316591992167219696L;
175
/** Element definition node type. */
176
public static final short ELEMENT_DEFINITION_NODE = 21;
184
protected NodeImpl ownerNode; // typically the parent but not always!
188
protected short flags;
190
protected final static short READONLY = 0x1<<0;
191
protected final static short SYNCDATA = 0x1<<1;
192
protected final static short SYNCCHILDREN = 0x1<<2;
193
protected final static short OWNED = 0x1<<3;
194
protected final static short FIRSTCHILD = 0x1<<4;
195
protected final static short SPECIFIED = 0x1<<5;
196
protected final static short IGNORABLEWS = 0x1<<6;
197
protected final static short HASSTRING = 0x1<<7;
198
protected final static short NORMALIZED = 0x1<<8;
199
protected final static short ID = 0x1<<9;
206
* No public constructor; only subclasses of Node should be
207
* instantiated, and those normally via a Document's factory methods
209
* Every Node knows what Document it belongs to.
211
protected NodeImpl(CoreDocumentImpl ownerDocument) {
212
// as long as we do not have any owner, ownerNode is our ownerDocument
213
ownerNode = ownerDocument;
214
} // <init>(CoreDocumentImpl)
216
/** Constructor for serialization. */
224
* A short integer indicating what type of node this is. The named
225
* constants for this value are defined in the org.w3c.dom.Node interface.
227
public abstract short getNodeType();
230
* the name of this node.
232
public abstract String getNodeName();
235
* Returns the node value.
236
* @throws DOMException(DOMSTRING_SIZE_ERR)
238
public String getNodeValue()
239
throws DOMException {
240
return null; // overridden in some subclasses
244
* Sets the node value.
245
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR)
247
public void setNodeValue(String x)
248
throws DOMException {
249
// Default behavior is to do nothing, overridden in some subclasses
253
* Adds a child node to the end of the list of children for this node.
254
* Convenience shorthand for insertBefore(newChild,null).
255
* @see #insertBefore(Node, Node)
257
* By default we do not accept any children, ParentNode overrides this.
260
* @return newChild, in its new state (relocated, or emptied in the case of
263
* @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
264
* type that shouldn't be a child of this node.
266
* @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
267
* different owner document than we do.
269
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
272
public Node appendChild(Node newChild) throws DOMException {
273
return insertBefore(newChild, null);
277
* Returns a duplicate of a given node. You can consider this a
278
* generic "copy constructor" for nodes. The newly returned object should
279
* be completely independent of the source object's subtree, so changes
280
* in one after the clone has been made will not affect the other.
282
* Note: since we never have any children deep is meaningless here,
283
* ParentNode overrides this behavior.
287
* Example: Cloning a Text node will copy both the node and the text it
290
* Example: Cloning something that has children -- Element or Attr, for
291
* example -- will _not_ clone those children unless a "deep clone"
292
* has been requested. A shallow clone of an Attr node will yield an
293
* empty Attr of the same name.
295
* NOTE: Clones will always be read/write, even if the node being cloned
296
* is read-only, to permit applications using only the DOM API to obtain
297
* editable copies of locked portions of the tree.
299
public Node cloneNode(boolean deep) {
301
if (needsSyncData()) {
307
newnode = (NodeImpl)clone();
309
catch (CloneNotSupportedException e) {
310
// if we get here we have an error in our program we may as well
311
// be vocal about it, so that people can take appropriate action.
312
throw new RuntimeException("**Internal Error**" + e);
315
// Need to break the association w/ original kids
316
newnode.ownerNode = ownerDocument();
317
newnode.isOwned(false);
319
// By default we make all clones readwrite,
320
// this is overriden in readonly subclasses
321
newnode.isReadOnly(false);
323
ownerDocument().callUserDataHandlers(this, newnode,
324
UserDataHandler.NODE_CLONED);
328
} // cloneNode(boolean):Node
331
* Find the Document that this Node belongs to (the document in
332
* whose context the Node was created). The Node may or may not
333
* currently be part of that Document's actual contents.
335
public Document getOwnerDocument() {
336
// if we have an owner simply forward the request
337
// otherwise ownerNode is our ownerDocument
339
return ownerNode.ownerDocument();
341
return (Document) ownerNode;
346
* same as above but returns internal type and this one is not overridden
347
* by CoreDocumentImpl to return null
349
CoreDocumentImpl ownerDocument() {
350
// if we have an owner simply forward the request
351
// otherwise ownerNode is our ownerDocument
353
return ownerNode.ownerDocument();
355
return (CoreDocumentImpl) ownerNode;
361
* set the ownerDocument of this node
363
void setOwnerDocument(CoreDocumentImpl doc) {
364
if (needsSyncData()) {
367
// if we have an owner we rely on it to have it right
368
// otherwise ownerNode is our ownerDocument
375
* Returns the node number
377
protected int getNodeNumber() {
379
CoreDocumentImpl cd = (CoreDocumentImpl)(this.getOwnerDocument());
380
nodeNumber = cd.getNodeNumber(this);
385
* Obtain the DOM-tree parent of this node, or null if it is not
386
* currently active in the DOM tree (perhaps because it has just been
387
* created or removed). Note that Document, DocumentFragment, and
388
* Attribute will never have parents.
390
public Node getParentNode() {
391
return null; // overriden by ChildNode
395
* same as above but returns internal type
397
NodeImpl parentNode() {
401
/** The next child of this node's parent, or null if none */
402
public Node getNextSibling() {
403
return null; // default behavior, overriden in ChildNode
406
/** The previous child of this node's parent, or null if none */
407
public Node getPreviousSibling() {
408
return null; // default behavior, overriden in ChildNode
411
ChildNode previousSibling() {
412
return null; // default behavior, overriden in ChildNode
416
* Return the collection of attributes associated with this node,
417
* or null if none. At this writing, Element is the only type of node
418
* which will ever have attributes.
422
public NamedNodeMap getAttributes() {
423
return null; // overridden in ElementImpl
427
* Returns whether this node (if it is an element) has any attributes.
428
* @return <code>true</code> if this node has any attributes,
429
* <code>false</code> otherwise.
433
public boolean hasAttributes() {
434
return false; // overridden in ElementImpl
438
* Test whether this node has any children. Convenience shorthand
439
* for (Node.getFirstChild()!=null)
441
* By default we do not have any children, ParentNode overrides this.
444
public boolean hasChildNodes() {
449
* Obtain a NodeList enumerating all children of this node. If there
450
* are none, an (initially) empty NodeList is returned.
452
* NodeLists are "live"; as children are added/removed the NodeList
453
* will immediately reflect those changes. Also, the NodeList refers
454
* to the actual nodes, so changes to those nodes made via the DOM tree
455
* will be reflected in the NodeList and vice versa.
457
* In this implementation, Nodes implement the NodeList interface and
458
* provide their own getChildNodes() support. Other DOMs may solve this
461
public NodeList getChildNodes() {
465
/** The first child of this Node, or null if none.
467
* By default we do not have any children, ParentNode overrides this.
470
public Node getFirstChild() {
474
/** The first child of this Node, or null if none.
476
* By default we do not have any children, ParentNode overrides this.
479
public Node getLastChild() {
484
* Move one or more node(s) to our list of children. Note that this
485
* implicitly removes them from their previous parent.
487
* By default we do not accept any children, ParentNode overrides this.
490
* @param newChild The Node to be moved to our subtree. As a
491
* convenience feature, inserting a DocumentNode will instead insert
494
* @param refChild Current child which newChild should be placed
495
* immediately before. If refChild is null, the insertion occurs
496
* after all existing Nodes, like appendChild().
498
* @return newChild, in its new state (relocated, or emptied in the case of
501
* @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
502
* type that shouldn't be a child of this node, or if newChild is an
503
* ancestor of this node.
505
* @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
506
* different owner document than we do.
508
* @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of
511
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
514
public Node insertBefore(Node newChild, Node refChild)
515
throws DOMException {
516
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
517
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
518
"HIERARCHY_REQUEST_ERR", null));
522
* Remove a child from this Node. The removed child's subtree
523
* remains intact so it may be re-inserted elsewhere.
525
* By default we do not have any children, ParentNode overrides this.
528
* @return oldChild, in its new state (removed).
530
* @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
533
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
536
public Node removeChild(Node oldChild)
537
throws DOMException {
538
throw new DOMException(DOMException.NOT_FOUND_ERR,
539
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
540
"NOT_FOUND_ERR", null));
544
* Make newChild occupy the location that oldChild used to
545
* have. Note that newChild will first be removed from its previous
546
* parent, if any. Equivalent to inserting newChild before oldChild,
547
* then removing oldChild.
549
* By default we do not have any children, ParentNode overrides this.
552
* @return oldChild, in its new state (removed).
554
* @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
555
* type that shouldn't be a child of this node, or if newChild is
556
* one of our ancestors.
558
* @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
559
* different owner document than we do.
561
* @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
564
* @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
567
public Node replaceChild(Node newChild, Node oldChild)
568
throws DOMException {
569
throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
570
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
571
"HIERARCHY_REQUEST_ERR", null));
579
* NodeList method: Count the immediate children of this node
581
* By default we do not have any children, ParentNode overrides this.
586
public int getLength() {
591
* NodeList method: Return the Nth immediate child of this node, or
592
* null if the index is out of bounds.
594
* By default we do not have any children, ParentNode overrides this.
597
* @return org.w3c.dom.Node
600
public Node item(int index) {
605
// DOM2: methods, getters, setters
609
* Puts all <code>Text</code> nodes in the full depth of the sub-tree
610
* underneath this <code>Node</code>, including attribute nodes, into a
611
* "normal" form where only markup (e.g., tags, comments, processing
612
* instructions, CDATA sections, and entity references) separates
613
* <code>Text</code> nodes, i.e., there are no adjacent <code>Text</code>
614
* nodes. This can be used to ensure that the DOM view of a document is
615
* the same as if it were saved and re-loaded, and is useful when
616
* operations (such as XPointer lookups) that depend on a particular
617
* document tree structure are to be used.In cases where the document
618
* contains <code>CDATASections</code>, the normalize operation alone may
619
* not be sufficient, since XPointers do not differentiate between
620
* <code>Text</code> nodes and <code>CDATASection</code> nodes.
622
* Note that this implementation simply calls normalize() on this Node's
623
* children. It is up to implementors or Node to override normalize()
626
public void normalize() {
627
/* by default we do not have any children,
628
ParentNode overrides this behavior */
632
* Introduced in DOM Level 2. <p>
633
* Tests whether the DOM implementation implements a specific feature and
634
* that feature is supported by this node.
635
* @param feature The package name of the feature to test. This is the same
636
* name as what can be passed to the method hasFeature on
638
* @param version This is the version number of the package name to
639
* test. In Level 2, version 1, this is the string "2.0". If the version is
640
* not specified, supporting any version of the feature will cause the
641
* method to return true.
642
* @return boolean Returns true if this node defines a subtree within which
643
* the specified feature is supported, false otherwise.
644
* @since WD-DOM-Level-2-19990923
646
public boolean isSupported(String feature, String version)
648
return ownerDocument().getImplementation().hasFeature(feature,
653
* Introduced in DOM Level 2. <p>
655
* The namespace URI of this node, or null if it is unspecified. When this
656
* node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE, this is
657
* always null and setting it has no effect. <p>
659
* This is not a computed value that is the result of a namespace lookup
660
* based on an examination of the namespace declarations in scope. It is
661
* merely the namespace URI given at creation time.<p>
663
* For nodes created with a DOM Level 1 method, such as createElement
664
* from the Document interface, this is null.
665
* @since WD-DOM-Level-2-19990923
669
public String getNamespaceURI()
675
* Introduced in DOM Level 2. <p>
677
* The namespace prefix of this node, or null if it is unspecified. When
678
* this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE this
679
* is always null and setting it has no effect.<p>
681
* For nodes created with a DOM Level 1 method, such as createElement
682
* from the Document interface, this is null. <p>
684
* @since WD-DOM-Level-2-19990923
688
public String getPrefix()
694
* Introduced in DOM Level 2. <p>
696
* The namespace prefix of this node, or null if it is unspecified. When
697
* this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE
698
* this is always null and setting it has no effect.<p>
700
* For nodes created with a DOM Level 1 method, such as createElement from
701
* the Document interface, this is null.<p>
703
* Note that setting this attribute changes the nodeName attribute, which
704
* holds the qualified name, as well as the tagName and name attributes of
705
* the Element and Attr interfaces, when applicable.<p>
707
* @throws INVALID_CHARACTER_ERR Raised if the specified
708
* prefix contains an invalid character.
710
* @since WD-DOM-Level-2-19990923
714
public void setPrefix(String prefix)
717
throw new DOMException(DOMException.NAMESPACE_ERR,
718
DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
719
"NAMESPACE_ERR", null));
723
* Introduced in DOM Level 2. <p>
725
* Returns the local part of the qualified name of this node.
726
* For nodes created with a DOM Level 1 method, such as createElement
727
* from the Document interface, and for nodes of any type other than
728
* ELEMENT_NODE and ATTRIBUTE_NODE this is the same as the nodeName
730
* @since WD-DOM-Level-2-19990923
734
public String getLocalName()
740
// EventTarget support
743
public void addEventListener(String type, EventListener listener,
744
boolean useCapture) {
745
// simply forward to Document
746
ownerDocument().addEventListener(this, type, listener, useCapture);
749
public void removeEventListener(String type, EventListener listener,
750
boolean useCapture) {
751
// simply forward to Document
752
ownerDocument().removeEventListener(this, type, listener, useCapture);
755
public boolean dispatchEvent(Event event) {
756
// simply forward to Document
757
return ownerDocument().dispatchEvent(this, event);
761
// Public DOM Level 3 methods
765
* The absolute base URI of this node or <code>null</code> if undefined.
766
* This value is computed according to . However, when the
767
* <code>Document</code> supports the feature "HTML" , the base URI is
768
* computed using first the value of the href attribute of the HTML BASE
769
* element if any, and the value of the <code>documentURI</code>
770
* attribute from the <code>Document</code> interface otherwise.
771
* <br> When the node is an <code>Element</code>, a <code>Document</code>
772
* or a a <code>ProcessingInstruction</code>, this attribute represents
773
* the properties [base URI] defined in . When the node is a
774
* <code>Notation</code>, an <code>Entity</code>, or an
775
* <code>EntityReference</code>, this attribute represents the
776
* properties [declaration base URI] in the . How will this be affected
777
* by resolution of relative namespace URIs issue?It's not.Should this
778
* only be on Document, Element, ProcessingInstruction, Entity, and
779
* Notation nodes, according to the infoset? If not, what is it equal to
780
* on other nodes? Null? An empty string? I think it should be the
781
* parent's.No.Should this be read-only and computed or and actual
782
* read-write attribute?Read-only and computed (F2F 19 Jun 2000 and
783
* teleconference 30 May 2001).If the base HTML element is not yet
784
* attached to a document, does the insert change the Document.baseURI?
785
* Yes. (F2F 26 Sep 2001)
788
public String getBaseURI() {
793
* Compares a node with this node with regard to their position in the
794
* tree and according to the document order. This order can be extended
795
* by module that define additional types of nodes.
796
* @param other The node to compare against this node.
797
* @return Returns how the given node is positioned relatively to this
802
public short compareTreePosition(Node other) {
803
// Questions of clarification for this method - to be answered by the
804
// DOM WG. Current assumptions listed - LM
806
// 1. How do ENTITY nodes compare?
807
// Current assumption: TREE_POSITION_DISCONNECTED, as ENTITY nodes
808
// aren't really 'in the tree'
810
// 2. How do NOTATION nodes compare?
811
// Current assumption: TREE_POSITION_DISCONNECTED, as NOTATION nodes
812
// aren't really 'in the tree'
814
// 3. Are TREE_POSITION_ANCESTOR and TREE_POSITION_DESCENDANT
815
// only relevant for nodes that are "part of the document tree"?
817
// <inner myattr="true"/>
819
// Is the element node "outer" considered an ancestor of "myattr"?
820
// Current assumption: No.
822
// 4. How do children of ATTRIBUTE nodes compare (with eachother, or
823
// with children of other attribute nodes with the same element)
824
// Current assumption: Children of ATTRIBUTE nodes are treated as if
825
// they they are the attribute node itself, unless the 2 nodes
826
// are both children of the same attribute.
828
// 5. How does an ENTITY_REFERENCE node compare with it's children?
829
// Given the DOM, it should precede its children as an ancestor.
830
// Given "document order", does it represent the same position?
831
// Current assumption: An ENTITY_REFERENCE node is an ancestor of its
834
// 6. How do children of a DocumentFragment compare?
835
// Current assumption: If both nodes are part of the same document
836
// fragment, there are compared as if they were part of a document.
839
// If the nodes are the same...
841
return (TREE_POSITION_SAME_NODE | TREE_POSITION_EQUIVALENT);
843
// If either node is of type ENTITY or NOTATION, compare as disconnected
844
short thisType = this.getNodeType();
845
short otherType = other.getNodeType();
847
// If either node is of type ENTITY or NOTATION, compare as disconnected
848
if (thisType == Node.ENTITY_NODE ||
849
thisType == Node.NOTATION_NODE ||
850
otherType == Node.ENTITY_NODE ||
851
otherType == Node.NOTATION_NODE ) {
852
return TREE_POSITION_DISCONNECTED;
855
// Find the ancestor of each node, and the distance each node is from
857
// During this traversal, look for ancestor/descendent relationships
858
// between the 2 nodes in question.
859
// We do this now, so that we get this info correct for attribute nodes
860
// and their children.
863
Node thisAncestor = this;
864
Node otherAncestor = other;
867
for (node=this; node != null; node = node.getParentNode()) {
870
// The other node is an ancestor of this one.
871
return (TREE_POSITION_ANCESTOR | TREE_POSITION_PRECEDING);
875
for (node=other; node!=null; node=node.getParentNode()) {
878
// The other node is a descendent of the reference node.
879
return (TREE_POSITION_DESCENDANT | TREE_POSITION_FOLLOWING);
880
otherAncestor = node;
884
Node thisNode = this;
885
Node otherNode = other;
887
int thisAncestorType = thisAncestor.getNodeType();
888
int otherAncestorType = otherAncestor.getNodeType();
890
// if the ancestor is an attribute, get owning element.
891
// we are now interested in the owner to determine position.
893
if (thisAncestorType == Node.ATTRIBUTE_NODE) {
894
thisNode = ((AttrImpl)thisAncestor).getOwnerElement();
896
if (otherAncestorType == Node.ATTRIBUTE_NODE) {
897
otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
900
// Before proceeding, we should check if both ancestor nodes turned
901
// out to be attributes for the same element
902
if (thisAncestorType == Node.ATTRIBUTE_NODE &&
903
otherAncestorType == Node.ATTRIBUTE_NODE &&
905
return TREE_POSITION_EQUIVALENT;
907
// Now, find the ancestor of the owning element, if the original
908
// ancestor was an attribute
910
// Note: the following 2 loops are quite close to the ones above.
911
// May want to common them up. LM.
912
if (thisAncestorType == Node.ATTRIBUTE_NODE) {
914
for (node=thisNode; node != null; node=node.getParentNode()) {
916
if (node == otherNode)
917
// The other node is an ancestor of the owning element
919
return TREE_POSITION_PRECEDING;
925
// Now, find the ancestor of the owning element, if the original
926
// ancestor was an attribute
927
if (otherAncestorType == Node.ATTRIBUTE_NODE) {
929
for (node=otherNode; node != null; node=node.getParentNode()) {
931
if (node == thisNode)
932
// The other node is a descendent of the reference
934
return TREE_POSITION_FOLLOWING;
935
otherAncestor = node;
939
// thisAncestor and otherAncestor must be the same at this point,
940
// otherwise, we are not in the same tree or document fragment
941
if (thisAncestor != otherAncestor)
942
return TREE_POSITION_DISCONNECTED;
945
// Go up the parent chain of the deeper node, until we find a node
946
// with the same depth as the shallower node
948
if (thisDepth > otherDepth) {
949
for (int i=0; i<thisDepth - otherDepth; i++)
950
thisNode = thisNode.getParentNode();
951
// Check if the node we have reached is in fact "otherNode". This can
952
// happen in the case of attributes. In this case, otherNode
954
if (thisNode == otherNode)
955
return TREE_POSITION_PRECEDING;
959
for (int i=0; i<otherDepth - thisDepth; i++)
960
otherNode = otherNode.getParentNode();
961
// Check if the node we have reached is in fact "thisNode". This can
962
// happen in the case of attributes. In this case, otherNode
964
if (otherNode == thisNode)
965
return TREE_POSITION_FOLLOWING;
968
// We now have nodes at the same depth in the tree. Find a common
970
Node thisNodeP, otherNodeP;
971
for (thisNodeP=thisNode.getParentNode(),
972
otherNodeP=otherNode.getParentNode();
973
thisNodeP!=otherNodeP;) {
974
thisNode = thisNodeP;
975
otherNode = otherNodeP;
976
thisNodeP = thisNodeP.getParentNode();
977
otherNodeP = otherNodeP.getParentNode();
980
// At this point, thisNode and otherNode are direct children of
981
// the common ancestor.
982
// See whether thisNode or otherNode is the leftmost
984
for (Node current=thisNodeP.getFirstChild();
986
current=current.getNextSibling()) {
987
if (current==otherNode) {
988
return TREE_POSITION_PRECEDING;
990
else if (current==thisNode) {
991
return TREE_POSITION_FOLLOWING;
994
// REVISIT: shouldn't get here. Should probably throw an
1000
* Compares a node with this node with regard to their position in the
1002
* @param other The node to compare against this node.
1003
* @return Returns how the given node is positioned relatively to this
1005
* @since DOM Level 3
1007
public short compareDocumentPosition(Node other) throws DOMException {
1009
// If the nodes are the same, no flags should be set
1013
// check if other is from a different implementation
1015
NodeImpl node = (NodeImpl) other;
1016
} catch (ClassCastException e) {
1017
// other comes from a different implementation
1018
String msg = DOMMessageFormatter.formatMessage(
1019
DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1020
throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1023
Document thisOwnerDoc, otherOwnerDoc;
1024
// get the respective Document owners.
1025
if (this.getNodeType() == Node.DOCUMENT_NODE)
1026
thisOwnerDoc = (Document)this;
1028
thisOwnerDoc = this.getOwnerDocument();
1029
if (other.getNodeType() == Node.DOCUMENT_NODE)
1030
otherOwnerDoc = (Document)other;
1032
otherOwnerDoc = other.getOwnerDocument();
1034
// If from different documents, we know they are disconnected.
1035
// and have an implementation dependent order
1036
if (thisOwnerDoc != otherOwnerDoc &&
1037
thisOwnerDoc !=null &&
1038
otherOwnerDoc !=null)
1040
int otherDocNum = ((CoreDocumentImpl)otherOwnerDoc).getNodeNumber();
1041
int thisDocNum = ((CoreDocumentImpl)thisOwnerDoc).getNodeNumber();
1042
if (otherDocNum > thisDocNum)
1043
return DOCUMENT_POSITION_DISCONNECTED |
1044
DOCUMENT_POSITION_FOLLOWING |
1045
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1047
return DOCUMENT_POSITION_DISCONNECTED |
1048
DOCUMENT_POSITION_PRECEDING |
1049
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1053
// Find the ancestor of each node, and the distance each node is from
1055
// During this traversal, look for ancestor/descendent relationships
1056
// between the 2 nodes in question.
1057
// We do this now, so that we get this info correct for attribute nodes
1058
// and their children.
1061
Node thisAncestor = this;
1062
Node otherAncestor = other;
1066
for (node=this; node != null; node = node.getParentNode()) {
1069
// The other node is an ancestor of this one.
1070
return (DOCUMENT_POSITION_CONTAINS |
1071
DOCUMENT_POSITION_PRECEDING);
1072
thisAncestor = node;
1075
for (node=other; node!=null; node=node.getParentNode()) {
1078
// The other node is a descendent of the reference node.
1079
return (DOCUMENT_POSITION_IS_CONTAINED |
1080
DOCUMENT_POSITION_FOLLOWING);
1081
otherAncestor = node;
1086
int thisAncestorType = thisAncestor.getNodeType();
1087
int otherAncestorType = otherAncestor.getNodeType();
1088
Node thisNode = this;
1089
Node otherNode = other;
1091
// Special casing for ENTITY, NOTATION, DOCTYPE and ATTRIBUTES
1092
// LM: should rewrite this.
1093
switch (thisAncestorType) {
1094
case Node.NOTATION_NODE:
1095
case Node.ENTITY_NODE: {
1096
DocumentType container = thisOwnerDoc.getDoctype();
1097
if (container == otherAncestor) return
1098
(DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_PRECEDING);
1099
switch (otherAncestorType) {
1100
case Node.NOTATION_NODE:
1101
case Node.ENTITY_NODE: {
1102
if (thisAncestorType != otherAncestorType)
1103
// the nodes are of different types
1104
return ((thisAncestorType>otherAncestorType) ?
1105
DOCUMENT_POSITION_PRECEDING:DOCUMENT_POSITION_FOLLOWING);
1107
// the nodes are of the same type. Find order.
1108
if (thisAncestorType == Node.NOTATION_NODE)
1110
if (((NamedNodeMapImpl)container.getNotations()).precedes(otherAncestor,thisAncestor))
1111
return (DOCUMENT_POSITION_PRECEDING |
1112
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1114
return (DOCUMENT_POSITION_FOLLOWING |
1115
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1117
if (((NamedNodeMapImpl)container.getEntities()).precedes(otherAncestor,thisAncestor))
1118
return (DOCUMENT_POSITION_PRECEDING |
1119
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1121
return (DOCUMENT_POSITION_FOLLOWING |
1122
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1126
thisNode = thisAncestor = thisOwnerDoc;
1129
case Node.DOCUMENT_TYPE_NODE: {
1130
if (otherNode == thisOwnerDoc)
1131
return (DOCUMENT_POSITION_PRECEDING |
1132
DOCUMENT_POSITION_CONTAINS);
1133
else if (thisOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc)
1134
return (DOCUMENT_POSITION_FOLLOWING);
1137
case Node.ATTRIBUTE_NODE: {
1138
thisNode = ((AttrImpl)thisAncestor).getOwnerElement();
1139
if (otherAncestorType==Node.ATTRIBUTE_NODE) {
1140
otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
1141
if (otherNode == thisNode) {
1142
if (((NamedNodeMapImpl)thisNode.getAttributes()).precedes(other,this))
1143
return (DOCUMENT_POSITION_PRECEDING |
1144
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1146
return (DOCUMENT_POSITION_FOLLOWING |
1147
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1151
// Now, find the ancestor of the element
1153
for (node=thisNode; node != null; node=node.getParentNode()) {
1155
if (node == otherNode)
1157
// The other node is an ancestor of the owning element
1158
return (DOCUMENT_POSITION_CONTAINS |
1159
DOCUMENT_POSITION_PRECEDING);
1161
thisAncestor = node;
1165
switch (otherAncestorType) {
1166
case Node.NOTATION_NODE:
1167
case Node.ENTITY_NODE: {
1168
DocumentType container = thisOwnerDoc.getDoctype();
1169
if (container == this) return (DOCUMENT_POSITION_IS_CONTAINED |
1170
DOCUMENT_POSITION_FOLLOWING);
1171
otherNode = otherAncestor = thisOwnerDoc;
1174
case Node.DOCUMENT_TYPE_NODE: {
1175
if (thisNode == otherOwnerDoc)
1176
return (DOCUMENT_POSITION_FOLLOWING |
1177
DOCUMENT_POSITION_IS_CONTAINED);
1178
else if (otherOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc)
1179
return (DOCUMENT_POSITION_PRECEDING);
1182
case Node.ATTRIBUTE_NODE: {
1184
otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
1185
for (node=otherNode; node != null; node=node.getParentNode()) {
1187
if (node == thisNode)
1188
// The other node is a descendent of the reference
1190
return DOCUMENT_POSITION_FOLLOWING |
1191
DOCUMENT_POSITION_IS_CONTAINED;
1192
otherAncestor = node;
1198
// thisAncestor and otherAncestor must be the same at this point,
1199
// otherwise, the original nodes are disconnected
1200
if (thisAncestor != otherAncestor) {
1201
int thisAncestorNum, otherAncestorNum;
1202
thisAncestorNum = ((NodeImpl)thisAncestor).getNodeNumber();
1203
otherAncestorNum = ((NodeImpl)otherAncestor).getNodeNumber();
1205
if (thisAncestorNum > otherAncestorNum)
1206
return DOCUMENT_POSITION_DISCONNECTED |
1207
DOCUMENT_POSITION_FOLLOWING |
1208
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1210
return DOCUMENT_POSITION_DISCONNECTED |
1211
DOCUMENT_POSITION_PRECEDING |
1212
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1216
// Go up the parent chain of the deeper node, until we find a node
1217
// with the same depth as the shallower node
1219
if (thisDepth > otherDepth) {
1220
for (int i=0; i<thisDepth - otherDepth; i++)
1221
thisNode = thisNode.getParentNode();
1222
// Check if the node we have reached is in fact "otherNode". This can
1223
// happen in the case of attributes. In this case, otherNode
1225
if (thisNode == otherNode)
1227
return DOCUMENT_POSITION_PRECEDING;
1232
for (int i=0; i<otherDepth - thisDepth; i++)
1233
otherNode = otherNode.getParentNode();
1234
// Check if the node we have reached is in fact "thisNode". This can
1235
// happen in the case of attributes. In this case, otherNode
1237
if (otherNode == thisNode)
1238
return DOCUMENT_POSITION_FOLLOWING;
1241
// We now have nodes at the same depth in the tree. Find a common
1243
Node thisNodeP, otherNodeP;
1244
for (thisNodeP=thisNode.getParentNode(),
1245
otherNodeP=otherNode.getParentNode();
1246
thisNodeP!=otherNodeP;) {
1247
thisNode = thisNodeP;
1248
otherNode = otherNodeP;
1249
thisNodeP = thisNodeP.getParentNode();
1250
otherNodeP = otherNodeP.getParentNode();
1253
// At this point, thisNode and otherNode are direct children of
1254
// the common ancestor.
1255
// See whether thisNode or otherNode is the leftmost
1257
for (Node current=thisNodeP.getFirstChild();
1259
current=current.getNextSibling()) {
1260
if (current==otherNode) {
1261
return DOCUMENT_POSITION_PRECEDING;
1263
else if (current==thisNode) {
1264
return DOCUMENT_POSITION_FOLLOWING;
1267
// REVISIT: shouldn't get here. Should probably throw an
1274
* This attribute returns the text content of this node and its
1275
* descendants. When it is defined to be null, setting it has no effect.
1276
* When set, any possible children this node may have are removed and
1277
* replaced by a single <code>Text</code> node containing the string
1278
* this attribute is set to. On getting, no serialization is performed,
1279
* the returned string does not contain any markup. No whitespace
1280
* normalization is performed, the returned string does not contain the
1281
* element content whitespaces . Similarly, on setting, no parsing is
1282
* performed either, the input string is taken as pure textual content.
1283
* <br>The string returned is made of the text content of this node
1284
* depending on its type, as defined below:
1285
* <table border='1'>
1287
* <th>Node type</th>
1292
* This attribute returns the text content of this node and its
1293
* descendants. When it is defined to be null, setting it has no effect.
1294
* When set, any possible children this node may have are removed and
1295
* replaced by a single <code>Text</code> node containing the string
1296
* this attribute is set to. On getting, no serialization is performed,
1297
* the returned string does not contain any markup. No whitespace
1298
* normalization is performed, the returned string does not contain the
1299
* element content whitespaces . Similarly, on setting, no parsing is
1300
* performed either, the input string is taken as pure textual content.
1301
* <br>The string returned is made of the text content of this node
1302
* depending on its type, as defined below:
1303
* <table border='1'>
1305
* <th>Node type</th>
1309
* <td valign='top' rowspan='1' colspan='1'>
1310
* ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
1311
* DOCUMENT_FRAGMENT_NODE</td>
1312
* <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
1313
* attribute value of every child node, excluding COMMENT_NODE and
1314
* PROCESSING_INSTRUCTION_NODE nodes</td>
1317
* <td valign='top' rowspan='1' colspan='1'>ATTRIBUTE_NODE, TEXT_NODE,
1318
* CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE</td>
1319
* <td valign='top' rowspan='1' colspan='1'>
1320
* <code>nodeValue</code></td>
1323
* <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
1324
* <td valign='top' rowspan='1' colspan='1'>
1328
* @exception DOMException
1329
* NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
1330
* @exception DOMException
1331
* DOMSTRING_SIZE_ERR: Raised when it would return more characters than
1332
* fit in a <code>DOMString</code> variable on the implementation
1334
* @since DOM Level 3
1336
public String getTextContent() throws DOMException {
1337
return getNodeValue(); // overriden in some subclasses
1340
// internal method taking a StringBuffer in parameter
1341
void getTextContent(StringBuffer buf) throws DOMException {
1342
String content = getNodeValue();
1343
if (content != null) {
1344
buf.append(content);
1349
* This attribute returns the text content of this node and its
1350
* descendants. When it is defined to be null, setting it has no effect.
1351
* When set, any possible children this node may have are removed and
1352
* replaced by a single <code>Text</code> node containing the string
1353
* this attribute is set to. On getting, no serialization is performed,
1354
* the returned string does not contain any markup. No whitespace
1355
* normalization is performed, the returned string does not contain the
1356
* element content whitespaces . Similarly, on setting, no parsing is
1357
* performed either, the input string is taken as pure textual content.
1358
* <br>The string returned is made of the text content of this node
1359
* depending on its type, as defined below:
1360
* <table border='1'>
1362
* <th>Node type</th>
1366
* <td valign='top' rowspan='1' colspan='1'>
1367
* ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
1368
* DOCUMENT_FRAGMENT_NODE</td>
1369
* <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
1370
* attribute value of every child node, excluding COMMENT_NODE and
1371
* PROCESSING_INSTRUCTION_NODE nodes</td>
1374
* <td valign='top' rowspan='1' colspan='1'>ATTRIBUTE_NODE, TEXT_NODE,
1375
* CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE</td>
1376
* <td valign='top' rowspan='1' colspan='1'>
1377
* <code>nodeValue</code></td>
1380
* <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
1381
* <td valign='top' rowspan='1' colspan='1'>
1385
* @exception DOMException
1386
* NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
1387
* @exception DOMException
1388
* DOMSTRING_SIZE_ERR: Raised when it would return more characters than
1389
* fit in a <code>DOMString</code> variable on the implementation
1391
* @since DOM Level 3
1393
public void setTextContent(String textContent)
1394
throws DOMException {
1395
setNodeValue(textContent);
1399
* Returns whether this node is the same node as the given one.
1400
* <br>This method provides a way to determine whether two
1401
* <code>Node</code> references returned by the implementation reference
1402
* the same object. When two <code>Node</code> references are references
1403
* to the same object, even if through a proxy, the references may be
1404
* used completely interchangably, such that all attributes have the
1405
* same values and calling the same DOM method on either reference
1406
* always has exactly the same effect.
1407
* @param other The node to test against.
1408
* @return Returns <code>true</code> if the nodes are the same,
1409
* <code>false</code> otherwise.
1410
* @since DOM Level 3
1412
public boolean isSameNode(Node other) {
1413
// we do not use any wrapper so the answer is obvious
1414
return this == other;
1421
* DOM Level 3: Experimental
1422
* This method checks if the specified <code>namespaceURI</code> is the
1423
* default namespace or not.
1424
* @param namespaceURI The namespace URI to look for.
1425
* @return <code>true</code> if the specified <code>namespaceURI</code>
1426
* is the default namespace, <code>false</code> otherwise.
1427
* @since DOM Level 3
1429
public boolean isDefaultNamespace(String namespaceURI){
1430
// REVISIT: remove casts when DOM L3 becomes REC.
1431
short type = this.getNodeType();
1433
case Node.ELEMENT_NODE: {
1434
String namespace = this.getNamespaceURI();
1435
String prefix = this.getPrefix();
1437
// REVISIT: is it possible that prefix is empty string?
1438
if (prefix == null || prefix.length() == 0) {
1439
if (namespaceURI == null) {
1440
return (namespace == namespaceURI);
1442
return namespaceURI.equals(namespace);
1444
if (this.hasAttributes()) {
1445
ElementImpl elem = (ElementImpl)this;
1446
NodeImpl attr = (NodeImpl)elem.getAttributeNodeNS("http://www.w3.org/2000/xmlns/", "xmlns");
1448
String value = attr.getNodeValue();
1449
if (namespaceURI == null) {
1450
return (namespace == value);
1452
return namespaceURI.equals(value);
1456
NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1457
if (ancestor != null) {
1458
return ancestor.isDefaultNamespace(namespaceURI);
1462
case Node.DOCUMENT_NODE:{
1463
return((NodeImpl)((Document)this).getDocumentElement()).isDefaultNamespace(namespaceURI);
1466
case Node.ENTITY_NODE :
1467
case Node.NOTATION_NODE:
1468
case Node.DOCUMENT_FRAGMENT_NODE:
1469
case Node.DOCUMENT_TYPE_NODE:
1472
case Node.ATTRIBUTE_NODE:{
1473
if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1474
return ownerNode.isDefaultNamespace(namespaceURI);
1480
NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1481
if (ancestor != null) {
1482
return ancestor.isDefaultNamespace(namespaceURI);
1495
* DOM Level 3 - Experimental:
1496
* Look up the prefix associated to the given namespace URI, starting from this node.
1498
* @param namespaceURI
1499
* @return the prefix for the namespace
1501
public String lookupPrefix(String namespaceURI){
1503
// REVISIT: When Namespaces 1.1 comes out this may not be true
1504
// Prefix can't be bound to null namespace
1505
if (namespaceURI == null) {
1509
short type = this.getNodeType();
1512
case Node.ELEMENT_NODE: {
1514
String namespace = this.getNamespaceURI(); // to flip out children
1515
return lookupNamespacePrefix(namespaceURI, (ElementImpl)this);
1517
case Node.DOCUMENT_NODE:{
1518
return((NodeImpl)((Document)this).getDocumentElement()).lookupPrefix(namespaceURI);
1521
case Node.ENTITY_NODE :
1522
case Node.NOTATION_NODE:
1523
case Node.DOCUMENT_FRAGMENT_NODE:
1524
case Node.DOCUMENT_TYPE_NODE:
1527
case Node.ATTRIBUTE_NODE:{
1528
if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1529
return ownerNode.lookupPrefix(namespaceURI);
1535
NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1536
if (ancestor != null) {
1537
return ancestor.lookupPrefix(namespaceURI);
1545
* DOM Level 3 - Experimental:
1546
* Look up the namespace URI associated to the given prefix, starting from this node.
1547
* Use lookupNamespaceURI(null) to lookup the default namespace
1549
* @param namespaceURI
1550
* @return th URI for the namespace
1551
* @since DOM Level 3
1553
public String lookupNamespaceURI(String specifiedPrefix) {
1554
short type = this.getNodeType();
1556
case Node.ELEMENT_NODE : {
1558
String namespace = this.getNamespaceURI();
1559
String prefix = this.getPrefix();
1560
if (namespace !=null) {
1561
// REVISIT: is it possible that prefix is empty string?
1562
if (specifiedPrefix== null && prefix==specifiedPrefix) {
1563
// looking for default namespace
1565
} else if (prefix != null && prefix.equals(specifiedPrefix)) {
1566
// non default namespace
1570
if (this.hasAttributes()) {
1571
NamedNodeMap map = this.getAttributes();
1572
int length = map.getLength();
1573
for (int i=0;i<length;i++) {
1574
Node attr = map.item(i);
1575
String attrPrefix = attr.getPrefix();
1576
String value = attr.getNodeValue();
1577
namespace = attr.getNamespaceURI();
1578
if (namespace !=null && namespace.equals("http://www.w3.org/2000/xmlns/")) {
1579
// at this point we are dealing with DOM Level 2 nodes only
1580
if (specifiedPrefix == null &&
1581
attr.getNodeName().equals("xmlns")) {
1582
// default namespace
1584
} else if (attrPrefix !=null &&
1585
attrPrefix.equals("xmlns") &&
1586
attr.getLocalName().equals(specifiedPrefix)) {
1587
// non default namespace
1593
NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1594
if (ancestor != null) {
1595
return ancestor.lookupNamespaceURI(specifiedPrefix);
1602
case Node.DOCUMENT_NODE : {
1603
return((NodeImpl)((Document)this).getDocumentElement()).lookupNamespaceURI(specifiedPrefix);
1605
case Node.ENTITY_NODE :
1606
case Node.NOTATION_NODE:
1607
case Node.DOCUMENT_FRAGMENT_NODE:
1608
case Node.DOCUMENT_TYPE_NODE:
1611
case Node.ATTRIBUTE_NODE:{
1612
if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1613
return ownerNode.lookupNamespaceURI(specifiedPrefix);
1619
NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1620
if (ancestor != null) {
1621
return ancestor.lookupNamespaceURI(specifiedPrefix);
1630
Node getElementAncestor (Node currentNode){
1631
Node parent = currentNode.getParentNode();
1632
if (parent != null) {
1633
short type = parent.getNodeType();
1634
if (type == Node.ELEMENT_NODE) {
1637
return getElementAncestor(parent);
1642
String lookupNamespacePrefix(String namespaceURI, ElementImpl el){
1643
String namespace = this.getNamespaceURI();
1644
// REVISIT: if no prefix is available is it null or empty string, or
1646
String prefix = this.getPrefix();
1648
if (namespace!=null && namespace.equals(namespaceURI)) {
1649
if (prefix != null) {
1650
String foundNamespace = el.lookupNamespaceURI(prefix);
1651
if (foundNamespace !=null && foundNamespace.equals(namespaceURI)) {
1657
if (this.hasAttributes()) {
1658
NamedNodeMap map = this.getAttributes();
1659
int length = map.getLength();
1660
for (int i=0;i<length;i++) {
1661
Node attr = map.item(i);
1662
String attrPrefix = attr.getPrefix();
1663
String value = attr.getNodeValue();
1664
namespace = attr.getNamespaceURI();
1665
if (namespace !=null && namespace.equals("http://www.w3.org/2000/xmlns/")) {
1666
// DOM Level 2 nodes
1667
if (((attr.getNodeName().equals("xmlns")) ||
1668
(attrPrefix !=null && attrPrefix.equals("xmlns")) &&
1669
value.equals(namespaceURI))) {
1671
String localname= attr.getLocalName();
1672
String foundNamespace = el.lookupNamespaceURI(localname);
1673
if (foundNamespace !=null && foundNamespace.equals(namespaceURI)) {
1682
NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1684
if (ancestor != null) {
1685
return ancestor.lookupNamespacePrefix(namespaceURI, el);
1691
* Tests whether two nodes are equal.
1692
* <br>This method tests for equality of nodes, not sameness (i.e.,
1693
* whether the two nodes are references to the same object) which can be
1694
* tested with <code>Node.isSameNode</code>. All nodes that are the same
1695
* will also be equal, though the reverse may not be true.
1696
* <br>Two nodes are equal if and only if the following conditions are
1697
* satisfied: The two nodes are of the same type.The following string
1698
* attributes are equal: <code>nodeName</code>, <code>localName</code>,
1699
* <code>namespaceURI</code>, <code>prefix</code>, <code>nodeValue</code>
1700
* , <code>baseURI</code>. This is: they are both <code>null</code>, or
1701
* they have the same length and are character for character identical.
1702
* The <code>attributes</code> <code>NamedNodeMaps</code> are equal.
1703
* This is: they are both <code>null</code>, or they have the same
1704
* length and for each node that exists in one map there is a node that
1705
* exists in the other map and is equal, although not necessarily at the
1706
* same index.The <code>childNodes</code> <code>NodeLists</code> are
1707
* equal. This is: they are both <code>null</code>, or they have the
1708
* same length and contain equal nodes at the same index. This is true
1709
* for <code>Attr</code> nodes as for any other type of node. Note that
1710
* normalization can affect equality; to avoid this, nodes should be
1711
* normalized before being compared.
1712
* <br>For two <code>DocumentType</code> nodes to be equal, the following
1713
* conditions must also be satisfied: The following string attributes
1714
* are equal: <code>publicId</code>, <code>systemId</code>,
1715
* <code>internalSubset</code>.The <code>entities</code>
1716
* <code>NamedNodeMaps</code> are equal.The <code>notations</code>
1717
* <code>NamedNodeMaps</code> are equal.
1718
* <br>On the other hand, the following do not affect equality: the
1719
* <code>ownerDocument</code> attribute, the <code>specified</code>
1720
* attribute for <code>Attr</code> nodes, the
1721
* <code>isWhitespaceInElementContent</code> attribute for
1722
* <code>Text</code> nodes, as well as any user data or event listeners
1723
* registered on the nodes.
1724
* @param arg The node to compare equality with.
1725
* @param deep If <code>true</code>, recursively compare the subtrees; if
1726
* <code>false</code>, compare only the nodes themselves (and its
1727
* attributes, if it is an <code>Element</code>).
1728
* @return If the nodes, and possibly subtrees are equal,
1729
* <code>true</code> otherwise <code>false</code>.
1730
* @since DOM Level 3
1732
public boolean isEqualNode(Node arg) {
1736
if (arg.getNodeType() != getNodeType()) {
1739
// in theory nodeName can't be null but better be careful
1740
// who knows what other implementations may be doing?...
1741
if (getNodeName() == null) {
1742
if (arg.getNodeName() != null) {
1746
else if (!getNodeName().equals(arg.getNodeName())) {
1750
if (getLocalName() == null) {
1751
if (arg.getLocalName() != null) {
1755
else if (!getLocalName().equals(arg.getLocalName())) {
1759
if (getNamespaceURI() == null) {
1760
if (arg.getNamespaceURI() != null) {
1764
else if (!getNamespaceURI().equals(arg.getNamespaceURI())) {
1768
if (getPrefix() == null) {
1769
if (arg.getPrefix() != null) {
1773
else if (!getPrefix().equals(arg.getPrefix())) {
1777
if (getNodeValue() == null) {
1778
if (arg.getNodeValue() != null) {
1782
else if (!getNodeValue().equals(arg.getNodeValue())) {
1791
* @since DOM Level 3
1793
public Object getFeature(String feature, String version) {
1794
// we don't have any alternate node, either this node does the job
1795
// or we don't have anything that does
1796
return isSupported(feature, version) ? this : null;
1800
* Associate an object to a key on this node. The object can later be
1801
* retrieved from this node by calling <code>getUserData</code> with the
1803
* @param key The key to associate the object to.
1804
* @param data The object to associate to the given key, or
1805
* <code>null</code> to remove any existing association to that key.
1806
* @param handler The handler to associate to that key, or
1807
* <code>null</code>.
1808
* @return Returns the <code>DOMObject</code> previously associated to
1809
* the given key on this node, or <code>null</code> if there was none.
1810
* @since DOM Level 3
1812
public Object setUserData(String key,
1814
UserDataHandler handler) {
1815
return ownerDocument().setUserData(this, key, data, handler);
1819
* Retrieves the object associated to a key on a this node. The object
1820
* must first have been set to this node by calling
1821
* <code>setUserData</code> with the same key.
1822
* @param key The key the object is associated to.
1823
* @return Returns the <code>DOMObject</code> associated to the given key
1824
* on this node, or <code>null</code> if there was none.
1825
* @since DOM Level 3
1827
public Object getUserData(String key) {
1828
return ownerDocument().getUserData(this, key);
1837
* NON-DOM: PR-DOM-Level-1-19980818 mentions readonly nodes in conjunction
1838
* with Entities, but provides no API to support this.
1840
* Most DOM users should not touch this method. Its anticpated use
1841
* is during construction of EntityRefernces, where it will be used to
1842
* lock the contents replicated from Entity so they can't be casually
1843
* altered. It _could_ be published as a DOM extension, if desired.
1845
* Note: since we never have any children deep is meaningless here,
1846
* ParentNode overrides this behavior.
1849
* @param readOnly True or false as desired.
1850
* @param deep If true, children are also toggled. Note that this will
1851
* not change the state of an EntityReference or its children,
1852
* which are always read-only.
1854
public void setReadOnly(boolean readOnly, boolean deep) {
1856
if (needsSyncData()) {
1859
isReadOnly(readOnly);
1861
} // setReadOnly(boolean,boolean)
1864
* NON-DOM: Returns true if this node is read-only. This is a
1867
public boolean getReadOnly() {
1869
if (needsSyncData()) {
1872
return isReadOnly();
1874
} // getReadOnly():boolean
1877
* NON-DOM: As an alternative to subclassing the DOM, this implementation
1878
* has been extended with the ability to attach an object to each node.
1879
* (If you need multiple objects, you can attach a collection such as a
1880
* vector or hashtable, then attach your application information to that.)
1881
* <p><b>Important Note:</b> You are responsible for removing references
1882
* to your data on nodes that are no longer used. Failure to do so will
1883
* prevent the nodes, your data is attached to, to be garbage collected
1884
* until the whole document is.
1886
* @param data the object to store or null to remove any existing reference
1888
public void setUserData(Object data) {
1889
ownerDocument().setUserData(this, data);
1894
* Returns the user data associated to this node.
1896
public Object getUserData() {
1897
return ownerDocument().getUserData(this);
1901
// Protected methods
1905
* Denotes that this node has changed.
1907
protected void changed() {
1908
// we do not actually store this information on every node, we only
1909
// have a global indicator on the Document. Doing otherwise cost us too
1910
// much for little gain.
1911
ownerDocument().changed();
1915
* Returns the number of changes to this node.
1917
protected int changes() {
1918
// we do not actually store this information on every node, we only
1919
// have a global indicator on the Document. Doing otherwise cost us too
1920
// much for little gain.
1921
return ownerDocument().changes();
1925
* Override this method in subclass to hook in efficient
1926
* internal data structure.
1928
protected void synchronizeData() {
1929
// By default just change the flag to avoid calling this method again
1930
needsSyncData(false);
1934
* For non-child nodes, the node which "points" to this node.
1935
* For example, the owning element for an attribute
1937
protected Node getContainer() {
1943
* Flags setters and getters
1946
final boolean isReadOnly() {
1947
return (flags & READONLY) != 0;
1950
final void isReadOnly(boolean value) {
1951
flags = (short) (value ? flags | READONLY : flags & ~READONLY);
1954
final boolean needsSyncData() {
1955
return (flags & SYNCDATA) != 0;
1958
final void needsSyncData(boolean value) {
1959
flags = (short) (value ? flags | SYNCDATA : flags & ~SYNCDATA);
1962
final boolean needsSyncChildren() {
1963
return (flags & SYNCCHILDREN) != 0;
1966
public final void needsSyncChildren(boolean value) {
1967
flags = (short) (value ? flags | SYNCCHILDREN : flags & ~SYNCCHILDREN);
1970
final boolean isOwned() {
1971
return (flags & OWNED) != 0;
1974
final void isOwned(boolean value) {
1975
flags = (short) (value ? flags | OWNED : flags & ~OWNED);
1978
final boolean isFirstChild() {
1979
return (flags & FIRSTCHILD) != 0;
1982
final void isFirstChild(boolean value) {
1983
flags = (short) (value ? flags | FIRSTCHILD : flags & ~FIRSTCHILD);
1986
final boolean isSpecified() {
1987
return (flags & SPECIFIED) != 0;
1990
final void isSpecified(boolean value) {
1991
flags = (short) (value ? flags | SPECIFIED : flags & ~SPECIFIED);
1994
// inconsistent name to avoid clash with public method on TextImpl
1995
final boolean internalIsIgnorableWhitespace() {
1996
return (flags & IGNORABLEWS) != 0;
1999
final void isIgnorableWhitespace(boolean value) {
2000
flags = (short) (value ? flags | IGNORABLEWS : flags & ~IGNORABLEWS);
2003
final boolean hasStringValue() {
2004
return (flags & HASSTRING) != 0;
2007
final void hasStringValue(boolean value) {
2008
flags = (short) (value ? flags | HASSTRING : flags & ~HASSTRING);
2011
final boolean isNormalized() {
2012
return (flags & NORMALIZED) != 0;
2015
final void isNormalized(boolean value) {
2016
// See if flag should propagate to parent.
2017
if (!value && isNormalized() && ownerNode != null) {
2018
ownerNode.isNormalized(false);
2020
flags = (short) (value ? flags | NORMALIZED : flags & ~NORMALIZED);
2023
final boolean isIdAttribute() {
2024
return (flags & ID) != 0;
2027
final void isIdAttribute(boolean value) {
2028
flags = (short) (value ? flags | ID : flags & ~ID);
2035
/** NON-DOM method for debugging convenience. */
2036
public String toString() {
2037
return "["+getNodeName()+": "+getNodeValue()+"]";
2041
// Serialization methods
2044
/** Serialize object. */
2045
private void writeObject(ObjectOutputStream out) throws IOException {
2048
if (needsSyncData()) {
2052
out.defaultWriteObject();
2054
} // writeObject(ObjectOutputStream)