1 /*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5 /*
6 * Copyright 1999-2002,2004 The Apache Software Foundation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 package com.sun.org.apache.xerces.internal.dom;
22
23 import java.io.IOException;
24 import java.io.ObjectOutputStream;
25 import java.io.Serializable;
26 import java.util.Hashtable;
27
28 import org.w3c.dom.UserDataHandler;
29 import org.w3c.dom.DOMException;
30 import org.w3c.dom.Document;
31 import org.w3c.dom.DocumentType;
32 import org.w3c.dom.NamedNodeMap;
33 import org.w3c.dom.Node;
34 import org.w3c.dom.NodeList;
35 import org.w3c.dom.events.Event;
36 import org.w3c.dom.events.EventListener;
37 import org.w3c.dom.events.EventTarget;
38
39 /**
40 * NodeImpl provides the basic structure of a DOM tree. It is never used
41 * directly, but instead is subclassed to add type and data
42 * information, and additional methods, appropriate to each node of
43 * the tree. Only its subclasses should be instantiated -- and those,
44 * with the exception of Document itself, only through a specific
45 * Document's factory methods.
46 * <P>
47 * The Node interface provides shared behaviors such as siblings and
48 * children, both for consistancy and so that the most common tree
49 * operations may be performed without constantly having to downcast
50 * to specific node types. When there is no obvious mapping for one of
51 * these queries, it will respond with null.
52 * Note that the default behavior is that children are forbidden. To
53 * permit them, the subclass ParentNode overrides several methods.
54 * <P>
55 * NodeImpl also implements NodeList, so it can return itself in
56 * response to the getChildNodes() query. This eliminiates the need
57 * for a separate ChildNodeList object. Note that this is an
58 * IMPLEMENTATION DETAIL; applications should _never_ assume that
59 * this identity exists.
60 * <P>
61 * All nodes in a single document must originate
62 * in that document. (Note that this is much tighter than "must be
63 * same implementation") Nodes are all aware of their ownerDocument,
64 * and attempts to mismatch will throw WRONG_DOCUMENT_ERR.
65 * <P>
66 * However, to save memory not all nodes always have a direct reference
67 * to their ownerDocument. When a node is owned by another node it relies
68 * on its owner to store its ownerDocument. Parent nodes always store it
69 * though, so there is never more than one level of indirection.
70 * And when a node doesn't have an owner, ownerNode refers to its
71 * ownerDocument.
72 * <p>
73 * This class doesn't directly support mutation events, however, it still
74 * implements the EventTarget interface and forward all related calls to the
75 * document so that the document class do so.
76 *
77 * @xerces.internal
78 *
79 * @author Arnaud Le Hors, IBM
80 * @author Joe Kesselman, IBM
81 * @since PR-DOM-Level-1-19980818.
82 */
83 public abstract class NodeImpl
84 implements Node, NodeList, EventTarget, Cloneable, Serializable{
85
86 //
87 // Constants
88 //
89
90
91 // TreePosition Constants.
92 // Taken from DOM L3 Node interface.
93 /**
94 * The node precedes the reference node.
95 */
96 public static final short TREE_POSITION_PRECEDING = 0x01;
97 /**
98 * The node follows the reference node.
99 */
100 public static final short TREE_POSITION_FOLLOWING = 0x02;
101 /**
102 * The node is an ancestor of the reference node.
103 */
104 public static final short TREE_POSITION_ANCESTOR = 0x04;
105 /**
106 * The node is a descendant of the reference node.
107 */
108 public static final short TREE_POSITION_DESCENDANT = 0x08;
109 /**
110 * The two nodes have an equivalent position. This is the case of two
111 * attributes that have the same <code>ownerElement</code>, and two
112 * nodes that are the same.
113 */
114 public static final short TREE_POSITION_EQUIVALENT = 0x10;
115 /**
116 * The two nodes are the same. Two nodes that are the same have an
117 * equivalent position, though the reverse may not be true.
118 */
119 public static final short TREE_POSITION_SAME_NODE = 0x20;
120 /**
121 * The two nodes are disconnected, they do not have any common ancestor.
122 * This is the case of two nodes that are not in the same document.
123 */
124 public static final short TREE_POSITION_DISCONNECTED = 0x00;
125
126
127 // DocumentPosition
128 public static final short DOCUMENT_POSITION_DISCONNECTED = 0x01;
129 public static final short DOCUMENT_POSITION_PRECEDING = 0x02;
130 public static final short DOCUMENT_POSITION_FOLLOWING = 0x04;
131 public static final short DOCUMENT_POSITION_CONTAINS = 0x08;
132 public static final short DOCUMENT_POSITION_IS_CONTAINED = 0x10;
133 public static final short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
134
135 /** Serialization version. */
136 static final long serialVersionUID = -6316591992167219696L;
137
138 // public
139
140 /** Element definition node type. */
141 public static final short ELEMENT_DEFINITION_NODE = 21;
142
143 //
144 // Data
145 //
146
147 // links
148
149 protected NodeImpl ownerNode; // typically the parent but not always!
150
151 // data
152
153 protected short flags;
154
155 protected final static short READONLY = 0x1<<0;
156 protected final static short SYNCDATA = 0x1<<1;
157 protected final static short SYNCCHILDREN = 0x1<<2;
158 protected final static short OWNED = 0x1<<3;
159 protected final static short FIRSTCHILD = 0x1<<4;
160 protected final static short SPECIFIED = 0x1<<5;
161 protected final static short IGNORABLEWS = 0x1<<6;
162 protected final static short HASSTRING = 0x1<<7;
163 protected final static short NORMALIZED = 0x1<<8;
164 protected final static short ID = 0x1<<9;
165
166 //
167 // Constructors
168 //
169
170 /**
171 * No public constructor; only subclasses of Node should be
172 * instantiated, and those normally via a Document's factory methods
173 * <p>
174 * Every Node knows what Document it belongs to.
175 */
176 protected NodeImpl(CoreDocumentImpl ownerDocument) {
177 // as long as we do not have any owner, ownerNode is our ownerDocument
178 ownerNode = ownerDocument;
179 } // <init>(CoreDocumentImpl)
180
181 /** Constructor for serialization. */
182 public NodeImpl() {}
183
184 //
185 // Node methods
186 //
187
188 /**
189 * A short integer indicating what type of node this is. The named
190 * constants for this value are defined in the org.w3c.dom.Node interface.
191 */
192 public abstract short getNodeType();
193
194 /**
195 * the name of this node.
196 */
197 public abstract String getNodeName();
198
199 /**
200 * Returns the node value.
201 * @throws DOMException(DOMSTRING_SIZE_ERR)
202 */
203 public String getNodeValue()
204 throws DOMException {
205 return null; // overridden in some subclasses
206 }
207
208 /**
209 * Sets the node value.
210 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR)
211 */
212 public void setNodeValue(String x)
213 throws DOMException {
214 // Default behavior is to do nothing, overridden in some subclasses
215 }
216
217 /**
218 * Adds a child node to the end of the list of children for this node.
219 * Convenience shorthand for insertBefore(newChild,null).
220 * @see #insertBefore(Node, Node)
221 * <P>
222 * By default we do not accept any children, ParentNode overrides this.
223 * @see ParentNode
224 *
225 * @return newChild, in its new state (relocated, or emptied in the case of
226 * DocumentNode.)
227 *
228 * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
229 * type that shouldn't be a child of this node.
230 *
231 * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
232 * different owner document than we do.
233 *
234 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
235 * read-only.
236 */
237 public Node appendChild(Node newChild) throws DOMException {
238 return insertBefore(newChild, null);
239 }
240
241 /**
242 * Returns a duplicate of a given node. You can consider this a
243 * generic "copy constructor" for nodes. The newly returned object should
244 * be completely independent of the source object's subtree, so changes
245 * in one after the clone has been made will not affect the other.
246 * <P>
247 * Note: since we never have any children deep is meaningless here,
248 * ParentNode overrides this behavior.
249 * @see ParentNode
250 *
251 * <p>
252 * Example: Cloning a Text node will copy both the node and the text it
253 * contains.
254 * <p>
255 * Example: Cloning something that has children -- Element or Attr, for
256 * example -- will _not_ clone those children unless a "deep clone"
257 * has been requested. A shallow clone of an Attr node will yield an
258 * empty Attr of the same name.
259 * <p>
260 * NOTE: Clones will always be read/write, even if the node being cloned
261 * is read-only, to permit applications using only the DOM API to obtain
262 * editable copies of locked portions of the tree.
263 */
264 public Node cloneNode(boolean deep) {
265
266 if (needsSyncData()) {
267 synchronizeData();
268 }
269
270 NodeImpl newnode;
271 try {
272 newnode = (NodeImpl)clone();
273 }
274 catch (CloneNotSupportedException e) {
275 // if we get here we have an error in our program we may as well
276 // be vocal about it, so that people can take appropriate action.
277 throw new RuntimeException("**Internal Error**" + e);
278 }
279
280 // Need to break the association w/ original kids
281 newnode.ownerNode = ownerDocument();
282 newnode.isOwned(false);
283
284 // By default we make all clones readwrite,
285 // this is overriden in readonly subclasses
286 newnode.isReadOnly(false);
287
288 ownerDocument().callUserDataHandlers(this, newnode,
289 UserDataHandler.NODE_CLONED);
290
291 return newnode;
292
293 } // cloneNode(boolean):Node
294
295 /**
296 * Find the Document that this Node belongs to (the document in
297 * whose context the Node was created). The Node may or may not
298 * currently be part of that Document's actual contents.
299 */
300 public Document getOwnerDocument() {
301 // if we have an owner simply forward the request
302 // otherwise ownerNode is our ownerDocument
303 if (isOwned()) {
304 return ownerNode.ownerDocument();
305 } else {
306 return (Document) ownerNode;
307 }
308 }
309
310 /**
311 * same as above but returns internal type and this one is not overridden
312 * by CoreDocumentImpl to return null
313 */
314 CoreDocumentImpl ownerDocument() {
315 // if we have an owner simply forward the request
316 // otherwise ownerNode is our ownerDocument
317 if (isOwned()) {
318 return ownerNode.ownerDocument();
319 } else {
320 return (CoreDocumentImpl) ownerNode;
321 }
322 }
323
324 /**
325 * NON-DOM
326 * set the ownerDocument of this node
327 */
328 void setOwnerDocument(CoreDocumentImpl doc) {
329 if (needsSyncData()) {
330 synchronizeData();
331 }
332 // if we have an owner we rely on it to have it right
333 // otherwise ownerNode is our ownerDocument
334 if (!isOwned()) {
335 ownerNode = doc;
336 }
337 }
338
339 /**
340 * Returns the node number
341 */
342 protected int getNodeNumber() {
343 int nodeNumber;
344 CoreDocumentImpl cd = (CoreDocumentImpl)(this.getOwnerDocument());
345 nodeNumber = cd.getNodeNumber(this);
346 return nodeNumber;
347 }
348
349 /**
350 * Obtain the DOM-tree parent of this node, or null if it is not
351 * currently active in the DOM tree (perhaps because it has just been
352 * created or removed). Note that Document, DocumentFragment, and
353 * Attribute will never have parents.
354 */
355 public Node getParentNode() {
356 return null; // overriden by ChildNode
357 }
358
359 /*
360 * same as above but returns internal type
361 */
362 NodeImpl parentNode() {
363 return null;
364 }
365
366 /** The next child of this node's parent, or null if none */
367 public Node getNextSibling() {
368 return null; // default behavior, overriden in ChildNode
369 }
370
371 /** The previous child of this node's parent, or null if none */
372 public Node getPreviousSibling() {
373 return null; // default behavior, overriden in ChildNode
374 }
375
376 ChildNode previousSibling() {
377 return null; // default behavior, overriden in ChildNode
378 }
379
380 /**
381 * Return the collection of attributes associated with this node,
382 * or null if none. At this writing, Element is the only type of node
383 * which will ever have attributes.
384 *
385 * @see ElementImpl
386 */
387 public NamedNodeMap getAttributes() {
388 return null; // overridden in ElementImpl
389 }
390
391 /**
392 * Returns whether this node (if it is an element) has any attributes.
393 * @return <code>true</code> if this node has any attributes,
394 * <code>false</code> otherwise.
395 * @since DOM Level 2
396 * @see ElementImpl
397 */
398 public boolean hasAttributes() {
399 return false; // overridden in ElementImpl
400 }
401
402 /**
403 * Test whether this node has any children. Convenience shorthand
404 * for (Node.getFirstChild()!=null)
405 * <P>
406 * By default we do not have any children, ParentNode overrides this.
407 * @see ParentNode
408 */
409 public boolean hasChildNodes() {
410 return false;
411 }
412
413 /**
414 * Obtain a NodeList enumerating all children of this node. If there
415 * are none, an (initially) empty NodeList is returned.
416 * <p>
417 * NodeLists are "live"; as children are added/removed the NodeList
418 * will immediately reflect those changes. Also, the NodeList refers
419 * to the actual nodes, so changes to those nodes made via the DOM tree
420 * will be reflected in the NodeList and vice versa.
421 * <p>
422 * In this implementation, Nodes implement the NodeList interface and
423 * provide their own getChildNodes() support. Other DOMs may solve this
424 * differently.
425 */
426 public NodeList getChildNodes() {
427 return this;
428 }
429
430 /** The first child of this Node, or null if none.
431 * <P>
432 * By default we do not have any children, ParentNode overrides this.
433 * @see ParentNode
434 */
435 public Node getFirstChild() {
436 return null;
437 }
438
439 /** The first child of this Node, or null if none.
440 * <P>
441 * By default we do not have any children, ParentNode overrides this.
442 * @see ParentNode
443 */
444 public Node getLastChild() {
445 return null;
446 }
447
448 /**
449 * Move one or more node(s) to our list of children. Note that this
450 * implicitly removes them from their previous parent.
451 * <P>
452 * By default we do not accept any children, ParentNode overrides this.
453 * @see ParentNode
454 *
455 * @param newChild The Node to be moved to our subtree. As a
456 * convenience feature, inserting a DocumentNode will instead insert
457 * all its children.
458 *
459 * @param refChild Current child which newChild should be placed
460 * immediately before. If refChild is null, the insertion occurs
461 * after all existing Nodes, like appendChild().
462 *
463 * @return newChild, in its new state (relocated, or emptied in the case of
464 * DocumentNode.)
465 *
466 * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
467 * type that shouldn't be a child of this node, or if newChild is an
468 * ancestor of this node.
469 *
470 * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
471 * different owner document than we do.
472 *
473 * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of
474 * this node.
475 *
476 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
477 * read-only.
478 */
479 public Node insertBefore(Node newChild, Node refChild)
480 throws DOMException {
481 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
482 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
483 "HIERARCHY_REQUEST_ERR", null));
484 }
485
486 /**
487 * Remove a child from this Node. The removed child's subtree
488 * remains intact so it may be re-inserted elsewhere.
489 * <P>
490 * By default we do not have any children, ParentNode overrides this.
491 * @see ParentNode
492 *
493 * @return oldChild, in its new state (removed).
494 *
495 * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
496 * this node.
497 *
498 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
499 * read-only.
500 */
501 public Node removeChild(Node oldChild)
502 throws DOMException {
503 throw new DOMException(DOMException.NOT_FOUND_ERR,
504 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
505 "NOT_FOUND_ERR", null));
506 }
507
508 /**
509 * Make newChild occupy the location that oldChild used to
510 * have. Note that newChild will first be removed from its previous
511 * parent, if any. Equivalent to inserting newChild before oldChild,
512 * then removing oldChild.
513 * <P>
514 * By default we do not have any children, ParentNode overrides this.
515 * @see ParentNode
516 *
517 * @return oldChild, in its new state (removed).
518 *
519 * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
520 * type that shouldn't be a child of this node, or if newChild is
521 * one of our ancestors.
522 *
523 * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
524 * different owner document than we do.
525 *
526 * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
527 * this node.
528 *
529 * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
530 * read-only.
531 */
532 public Node replaceChild(Node newChild, Node oldChild)
533 throws DOMException {
534 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
535 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
536 "HIERARCHY_REQUEST_ERR", null));
537 }
538
539 //
540 // NodeList methods
541 //
542
543 /**
544 * NodeList method: Count the immediate children of this node
545 * <P>
546 * By default we do not have any children, ParentNode overrides this.
547 * @see ParentNode
548 *
549 * @return int
550 */
551 public int getLength() {
552 return 0;
553 }
554
555 /**
556 * NodeList method: Return the Nth immediate child of this node, or
557 * null if the index is out of bounds.
558 * <P>
559 * By default we do not have any children, ParentNode overrides this.
560 * @see ParentNode
561 *
562 * @return org.w3c.dom.Node
563 * @param Index int
564 */
565 public Node item(int index) {
566 return null;
567 }
568
569 //
570 // DOM2: methods, getters, setters
571 //
572
573 /**
574 * Puts all <code>Text</code> nodes in the full depth of the sub-tree
575 * underneath this <code>Node</code>, including attribute nodes, into a
576 * "normal" form where only markup (e.g., tags, comments, processing
577 * instructions, CDATA sections, and entity references) separates
578 * <code>Text</code> nodes, i.e., there are no adjacent <code>Text</code>
579 * nodes. This can be used to ensure that the DOM view of a document is
580 * the same as if it were saved and re-loaded, and is useful when
581 * operations (such as XPointer lookups) that depend on a particular
582 * document tree structure are to be used.In cases where the document
583 * contains <code>CDATASections</code>, the normalize operation alone may
584 * not be sufficient, since XPointers do not differentiate between
585 * <code>Text</code> nodes and <code>CDATASection</code> nodes.
586 * <p>
587 * Note that this implementation simply calls normalize() on this Node's
588 * children. It is up to implementors or Node to override normalize()
589 * to take action.
590 */
591 public void normalize() {
592 /* by default we do not have any children,
593 ParentNode overrides this behavior */
594 }
595
596 /**
597 * Introduced in DOM Level 2. <p>
598 * Tests whether the DOM implementation implements a specific feature and
599 * that feature is supported by this node.
600 * @param feature The package name of the feature to test. This is the same
601 * name as what can be passed to the method hasFeature on
602 * DOMImplementation.
603 * @param version This is the version number of the package name to
604 * test. In Level 2, version 1, this is the string "2.0". If the version is
605 * not specified, supporting any version of the feature will cause the
606 * method to return true.
607 * @return boolean Returns true if this node defines a subtree within which
608 * the specified feature is supported, false otherwise.
609 * @since WD-DOM-Level-2-19990923
610 */
611 public boolean isSupported(String feature, String version)
612 {
613 return ownerDocument().getImplementation().hasFeature(feature,
614 version);
615 }
616
617 /**
618 * Introduced in DOM Level 2. <p>
619 *
620 * The namespace URI of this node, or null if it is unspecified. When this
621 * node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE, this is
622 * always null and setting it has no effect. <p>
623 *
624 * This is not a computed value that is the result of a namespace lookup
625 * based on an examination of the namespace declarations in scope. It is
626 * merely the namespace URI given at creation time.<p>
627 *
628 * For nodes created with a DOM Level 1 method, such as createElement
629 * from the Document interface, this is null.
630 * @since WD-DOM-Level-2-19990923
631 * @see AttrNSImpl
632 * @see ElementNSImpl
633 */
634 public String getNamespaceURI()
635 {
636 return null;
637 }
638
639 /**
640 * Introduced in DOM Level 2. <p>
641 *
642 * The namespace prefix of this node, or null if it is unspecified. When
643 * this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE this
644 * is always null and setting it has no effect.<p>
645 *
646 * For nodes created with a DOM Level 1 method, such as createElement
647 * from the Document interface, this is null. <p>
648 *
649 * @since WD-DOM-Level-2-19990923
650 * @see AttrNSImpl
651 * @see ElementNSImpl
652 */
653 public String getPrefix()
654 {
655 return null;
656 }
657
658 /**
659 * Introduced in DOM Level 2. <p>
660 *
661 * The namespace prefix of this node, or null if it is unspecified. When
662 * this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE
663 * this is always null and setting it has no effect.<p>
664 *
665 * For nodes created with a DOM Level 1 method, such as createElement from
666 * the Document interface, this is null.<p>
667 *
668 * Note that setting this attribute changes the nodeName attribute, which
669 * holds the qualified name, as well as the tagName and name attributes of
670 * the Element and Attr interfaces, when applicable.<p>
671 *
672 * @throws INVALID_CHARACTER_ERR Raised if the specified
673 * prefix contains an invalid character.
674 *
675 * @since WD-DOM-Level-2-19990923
676 * @see AttrNSImpl
677 * @see ElementNSImpl
678 */
679 public void setPrefix(String prefix)
680 throws DOMException
681 {
682 throw new DOMException(DOMException.NAMESPACE_ERR,
683 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
684 "NAMESPACE_ERR", null));
685 }
686
687 /**
688 * Introduced in DOM Level 2. <p>
689 *
690 * Returns the local part of the qualified name of this node.
691 * For nodes created with a DOM Level 1 method, such as createElement
692 * from the Document interface, and for nodes of any type other than
693 * ELEMENT_NODE and ATTRIBUTE_NODE this is the same as the nodeName
694 * attribute.
695 * @since WD-DOM-Level-2-19990923
696 * @see AttrNSImpl
697 * @see ElementNSImpl
698 */
699 public String getLocalName()
700 {
701 return null;
702 }
703
704 //
705 // EventTarget support
706 //
707
708 public void addEventListener(String type, EventListener listener,
709 boolean useCapture) {
710 // simply forward to Document
711 ownerDocument().addEventListener(this, type, listener, useCapture);
712 }
713
714 public void removeEventListener(String type, EventListener listener,
715 boolean useCapture) {
716 // simply forward to Document
717 ownerDocument().removeEventListener(this, type, listener, useCapture);
718 }
719
720 public boolean dispatchEvent(Event event) {
721 // simply forward to Document
722 return ownerDocument().dispatchEvent(this, event);
723 }
724
725 //
726 // Public DOM Level 3 methods
727 //
728
729 /**
730 * The absolute base URI of this node or <code>null</code> if undefined.
731 * This value is computed according to . However, when the
732 * <code>Document</code> supports the feature "HTML" , the base URI is
733 * computed using first the value of the href attribute of the HTML BASE
734 * element if any, and the value of the <code>documentURI</code>
735 * attribute from the <code>Document</code> interface otherwise.
736 * <br> When the node is an <code>Element</code>, a <code>Document</code>
737 * or a a <code>ProcessingInstruction</code>, this attribute represents
738 * the properties [base URI] defined in . When the node is a
739 * <code>Notation</code>, an <code>Entity</code>, or an
740 * <code>EntityReference</code>, this attribute represents the
741 * properties [declaration base URI] in the . How will this be affected
742 * by resolution of relative namespace URIs issue?It's not.Should this
743 * only be on Document, Element, ProcessingInstruction, Entity, and
744 * Notation nodes, according to the infoset? If not, what is it equal to
745 * on other nodes? Null? An empty string? I think it should be the
746 * parent's.No.Should this be read-only and computed or and actual
747 * read-write attribute?Read-only and computed (F2F 19 Jun 2000 and
748 * teleconference 30 May 2001).If the base HTML element is not yet
749 * attached to a document, does the insert change the Document.baseURI?
750 * Yes. (F2F 26 Sep 2001)
751 * @since DOM Level 3
752 */
753 public String getBaseURI() {
754 return null;
755 }
756
757 /**
758 * Compares a node with this node with regard to their position in the
759 * tree and according to the document order. This order can be extended
760 * by module that define additional types of nodes.
761 * @param other The node to compare against this node.
762 * @return Returns how the given node is positioned relatively to this
763 * node.
764 * @since DOM Level 3
765 * @deprecated
766 */
767 public short compareTreePosition(Node other) {
768 // Questions of clarification for this method - to be answered by the
769 // DOM WG. Current assumptions listed - LM
770 //
771 // 1. How do ENTITY nodes compare?
772 // Current assumption: TREE_POSITION_DISCONNECTED, as ENTITY nodes
773 // aren't really 'in the tree'
774 //
775 // 2. How do NOTATION nodes compare?
776 // Current assumption: TREE_POSITION_DISCONNECTED, as NOTATION nodes
777 // aren't really 'in the tree'
778 //
779 // 3. Are TREE_POSITION_ANCESTOR and TREE_POSITION_DESCENDANT
780 // only relevant for nodes that are "part of the document tree"?
781 // <outer>
782 // <inner myattr="true"/>
783 // </outer>
784 // Is the element node "outer" considered an ancestor of "myattr"?
785 // Current assumption: No.
786 //
787 // 4. How do children of ATTRIBUTE nodes compare (with eachother, or
788 // with children of other attribute nodes with the same element)
789 // Current assumption: Children of ATTRIBUTE nodes are treated as if
790 // they they are the attribute node itself, unless the 2 nodes
791 // are both children of the same attribute.
792 //
793 // 5. How does an ENTITY_REFERENCE node compare with it's children?
794 // Given the DOM, it should precede its children as an ancestor.
795 // Given "document order", does it represent the same position?
796 // Current assumption: An ENTITY_REFERENCE node is an ancestor of its
797 // children.
798 //
799 // 6. How do children of a DocumentFragment compare?
800 // Current assumption: If both nodes are part of the same document
801 // fragment, there are compared as if they were part of a document.
802
803
804 // If the nodes are the same...
805 if (this==other)
806 return (TREE_POSITION_SAME_NODE | TREE_POSITION_EQUIVALENT);
807
808 // If either node is of type ENTITY or NOTATION, compare as disconnected
809 short thisType = this.getNodeType();
810 short otherType = other.getNodeType();
811
812 // If either node is of type ENTITY or NOTATION, compare as disconnected
813 if (thisType == Node.ENTITY_NODE ||
814 thisType == Node.NOTATION_NODE ||
815 otherType == Node.ENTITY_NODE ||
816 otherType == Node.NOTATION_NODE ) {
817 return TREE_POSITION_DISCONNECTED;
818 }
819
820 // Find the ancestor of each node, and the distance each node is from
821 // its ancestor.
822 // During this traversal, look for ancestor/descendent relationships
823 // between the 2 nodes in question.
824 // We do this now, so that we get this info correct for attribute nodes
825 // and their children.
826
827 Node node;
828 Node thisAncestor = this;
829 Node otherAncestor = other;
830 int thisDepth=0;
831 int otherDepth=0;
832 for (node=this; node != null; node = node.getParentNode()) {
833 thisDepth +=1;
834 if (node == other)
835 // The other node is an ancestor of this one.
836 return (TREE_POSITION_ANCESTOR | TREE_POSITION_PRECEDING);
837 thisAncestor = node;
838 }
839
840 for (node=other; node!=null; node=node.getParentNode()) {
841 otherDepth +=1;
842 if (node == this)
843 // The other node is a descendent of the reference node.
844 return (TREE_POSITION_DESCENDANT | TREE_POSITION_FOLLOWING);
845 otherAncestor = node;
846 }
847
848
849 Node thisNode = this;
850 Node otherNode = other;
851
852 int thisAncestorType = thisAncestor.getNodeType();
853 int otherAncestorType = otherAncestor.getNodeType();
854
855 // if the ancestor is an attribute, get owning element.
856 // we are now interested in the owner to determine position.
857
858 if (thisAncestorType == Node.ATTRIBUTE_NODE) {
859 thisNode = ((AttrImpl)thisAncestor).getOwnerElement();
860 }
861 if (otherAncestorType == Node.ATTRIBUTE_NODE) {
862 otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
863 }
864
865 // Before proceeding, we should check if both ancestor nodes turned
866 // out to be attributes for the same element
867 if (thisAncestorType == Node.ATTRIBUTE_NODE &&
868 otherAncestorType == Node.ATTRIBUTE_NODE &&
869 thisNode==otherNode)
870 return TREE_POSITION_EQUIVALENT;
871
872 // Now, find the ancestor of the owning element, if the original
873 // ancestor was an attribute
874
875 // Note: the following 2 loops are quite close to the ones above.
876 // May want to common them up. LM.
877 if (thisAncestorType == Node.ATTRIBUTE_NODE) {
878 thisDepth=0;
879 for (node=thisNode; node != null; node=node.getParentNode()) {
880 thisDepth +=1;
881 if (node == otherNode)
882 // The other node is an ancestor of the owning element
883 {
884 return TREE_POSITION_PRECEDING;
885 }
886 thisAncestor = node;
887 }
888 }
889
890 // Now, find the ancestor of the owning element, if the original
891 // ancestor was an attribute
892 if (otherAncestorType == Node.ATTRIBUTE_NODE) {
893 otherDepth=0;
894 for (node=otherNode; node != null; node=node.getParentNode()) {
895 otherDepth +=1;
896 if (node == thisNode)
897 // The other node is a descendent of the reference
898 // node's element
899 return TREE_POSITION_FOLLOWING;
900 otherAncestor = node;
901 }
902 }
903
904 // thisAncestor and otherAncestor must be the same at this point,
905 // otherwise, we are not in the same tree or document fragment
906 if (thisAncestor != otherAncestor)
907 return TREE_POSITION_DISCONNECTED;
908
909
910 // Go up the parent chain of the deeper node, until we find a node
911 // with the same depth as the shallower node
912
913 if (thisDepth > otherDepth) {
914 for (int i=0; i<thisDepth - otherDepth; i++)
915 thisNode = thisNode.getParentNode();
916 // Check if the node we have reached is in fact "otherNode". This can
917 // happen in the case of attributes. In this case, otherNode
918 // "precedes" this.
919 if (thisNode == otherNode)
920 return TREE_POSITION_PRECEDING;
921 }
922
923 else {
924 for (int i=0; i<otherDepth - thisDepth; i++)
925 otherNode = otherNode.getParentNode();
926 // Check if the node we have reached is in fact "thisNode". This can
927 // happen in the case of attributes. In this case, otherNode
928 // "follows" this.
929 if (otherNode == thisNode)
930 return TREE_POSITION_FOLLOWING;
931 }
932
933 // We now have nodes at the same depth in the tree. Find a common
934 // ancestor.
935 Node thisNodeP, otherNodeP;
936 for (thisNodeP=thisNode.getParentNode(),
937 otherNodeP=otherNode.getParentNode();
938 thisNodeP!=otherNodeP;) {
939 thisNode = thisNodeP;
940 otherNode = otherNodeP;
941 thisNodeP = thisNodeP.getParentNode();
942 otherNodeP = otherNodeP.getParentNode();
943 }
944
945 // At this point, thisNode and otherNode are direct children of
946 // the common ancestor.
947 // See whether thisNode or otherNode is the leftmost
948
949 for (Node current=thisNodeP.getFirstChild();
950 current!=null;
951 current=current.getNextSibling()) {
952 if (current==otherNode) {
953 return TREE_POSITION_PRECEDING;
954 }
955 else if (current==thisNode) {
956 return TREE_POSITION_FOLLOWING;
957 }
958 }
959 // REVISIT: shouldn't get here. Should probably throw an
960 // exception
961 return 0;
962
963 }
964 /**
965 * Compares a node with this node with regard to their position in the
966 * document.
967 * @param other The node to compare against this node.
968 * @return Returns how the given node is positioned relatively to this
969 * node.
970 * @since DOM Level 3
971 */
972 public short compareDocumentPosition(Node other) throws DOMException {
973
974 // If the nodes are the same, no flags should be set
975 if (this==other)
976 return 0;
977
978 // check if other is from a different implementation
979 try {
980 NodeImpl node = (NodeImpl) other;
981 } catch (ClassCastException e) {
982 // other comes from a different implementation
983 String msg = DOMMessageFormatter.formatMessage(
984 DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
985 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
986 }
987
988 Document thisOwnerDoc, otherOwnerDoc;
989 // get the respective Document owners.
990 if (this.getNodeType() == Node.DOCUMENT_NODE)
991 thisOwnerDoc = (Document)this;
992 else
993 thisOwnerDoc = this.getOwnerDocument();
994 if (other.getNodeType() == Node.DOCUMENT_NODE)
995 otherOwnerDoc = (Document)other;
996 else
997 otherOwnerDoc = other.getOwnerDocument();
998
999 // If from different documents, we know they are disconnected.
1000 // and have an implementation dependent order
1001 if (thisOwnerDoc != otherOwnerDoc &&
1002 thisOwnerDoc !=null &&
1003 otherOwnerDoc !=null)
1004 {
1005 int otherDocNum = ((CoreDocumentImpl)otherOwnerDoc).getNodeNumber();
1006 int thisDocNum = ((CoreDocumentImpl)thisOwnerDoc).getNodeNumber();
1007 if (otherDocNum > thisDocNum)
1008 return DOCUMENT_POSITION_DISCONNECTED |
1009 DOCUMENT_POSITION_FOLLOWING |
1010 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1011 else
1012 return DOCUMENT_POSITION_DISCONNECTED |
1013 DOCUMENT_POSITION_PRECEDING |
1014 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1015
1016 }
1017
1018 // Find the ancestor of each node, and the distance each node is from
1019 // its ancestor.
1020 // During this traversal, look for ancestor/descendent relationships
1021 // between the 2 nodes in question.
1022 // We do this now, so that we get this info correct for attribute nodes
1023 // and their children.
1024
1025 Node node;
1026 Node thisAncestor = this;
1027 Node otherAncestor = other;
1028
1029 int thisDepth=0;
1030 int otherDepth=0;
1031 for (node=this; node != null; node = node.getParentNode()) {
1032 thisDepth +=1;
1033 if (node == other)
1034 // The other node is an ancestor of this one.
1035 return (DOCUMENT_POSITION_CONTAINS |
1036 DOCUMENT_POSITION_PRECEDING);
1037 thisAncestor = node;
1038 }
1039
1040 for (node=other; node!=null; node=node.getParentNode()) {
1041 otherDepth +=1;
1042 if (node == this)
1043 // The other node is a descendent of the reference node.
1044 return (DOCUMENT_POSITION_IS_CONTAINED |
1045 DOCUMENT_POSITION_FOLLOWING);
1046 otherAncestor = node;
1047 }
1048
1049
1050
1051 int thisAncestorType = thisAncestor.getNodeType();
1052 int otherAncestorType = otherAncestor.getNodeType();
1053 Node thisNode = this;
1054 Node otherNode = other;
1055
1056 // Special casing for ENTITY, NOTATION, DOCTYPE and ATTRIBUTES
1057 // LM: should rewrite this.
1058 switch (thisAncestorType) {
1059 case Node.NOTATION_NODE:
1060 case Node.ENTITY_NODE: {
1061 DocumentType container = thisOwnerDoc.getDoctype();
1062 if (container == otherAncestor) return
1063 (DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_PRECEDING);
1064 switch (otherAncestorType) {
1065 case Node.NOTATION_NODE:
1066 case Node.ENTITY_NODE: {
1067 if (thisAncestorType != otherAncestorType)
1068 // the nodes are of different types
1069 return ((thisAncestorType>otherAncestorType) ?
1070 DOCUMENT_POSITION_PRECEDING:DOCUMENT_POSITION_FOLLOWING);
1071 else {
1072 // the nodes are of the same type. Find order.
1073 if (thisAncestorType == Node.NOTATION_NODE)
1074
1075 if (((NamedNodeMapImpl)container.getNotations()).precedes(otherAncestor,thisAncestor))
1076 return (DOCUMENT_POSITION_PRECEDING |
1077 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1078 else
1079 return (DOCUMENT_POSITION_FOLLOWING |
1080 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1081 else
1082 if (((NamedNodeMapImpl)container.getEntities()).precedes(otherAncestor,thisAncestor))
1083 return (DOCUMENT_POSITION_PRECEDING |
1084 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1085 else
1086 return (DOCUMENT_POSITION_FOLLOWING |
1087 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1088 }
1089 }
1090 }
1091 thisNode = thisAncestor = thisOwnerDoc;
1092 break;
1093 }
1094 case Node.DOCUMENT_TYPE_NODE: {
1095 if (otherNode == thisOwnerDoc)
1096 return (DOCUMENT_POSITION_PRECEDING |
1097 DOCUMENT_POSITION_CONTAINS);
1098 else if (thisOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc)
1099 return (DOCUMENT_POSITION_FOLLOWING);
1100 break;
1101 }
1102 case Node.ATTRIBUTE_NODE: {
1103 thisNode = ((AttrImpl)thisAncestor).getOwnerElement();
1104 if (otherAncestorType==Node.ATTRIBUTE_NODE) {
1105 otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
1106 if (otherNode == thisNode) {
1107 if (((NamedNodeMapImpl)thisNode.getAttributes()).precedes(other,this))
1108 return (DOCUMENT_POSITION_PRECEDING |
1109 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1110 else
1111 return (DOCUMENT_POSITION_FOLLOWING |
1112 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC);
1113 }
1114 }
1115
1116 // Now, find the ancestor of the element
1117 thisDepth=0;
1118 for (node=thisNode; node != null; node=node.getParentNode()) {
1119 thisDepth +=1;
1120 if (node == otherNode)
1121 {
1122 // The other node is an ancestor of the owning element
1123 return (DOCUMENT_POSITION_CONTAINS |
1124 DOCUMENT_POSITION_PRECEDING);
1125 }
1126 thisAncestor = node;
1127 }
1128 }
1129 }
1130 switch (otherAncestorType) {
1131 case Node.NOTATION_NODE:
1132 case Node.ENTITY_NODE: {
1133 DocumentType container = thisOwnerDoc.getDoctype();
1134 if (container == this) return (DOCUMENT_POSITION_IS_CONTAINED |
1135 DOCUMENT_POSITION_FOLLOWING);
1136 otherNode = otherAncestor = thisOwnerDoc;
1137 break;
1138 }
1139 case Node.DOCUMENT_TYPE_NODE: {
1140 if (thisNode == otherOwnerDoc)
1141 return (DOCUMENT_POSITION_FOLLOWING |
1142 DOCUMENT_POSITION_IS_CONTAINED);
1143 else if (otherOwnerDoc!=null && thisOwnerDoc==otherOwnerDoc)
1144 return (DOCUMENT_POSITION_PRECEDING);
1145 break;
1146 }
1147 case Node.ATTRIBUTE_NODE: {
1148 otherDepth=0;
1149 otherNode = ((AttrImpl)otherAncestor).getOwnerElement();
1150 for (node=otherNode; node != null; node=node.getParentNode()) {
1151 otherDepth +=1;
1152 if (node == thisNode)
1153 // The other node is a descendent of the reference
1154 // node's element
1155 return DOCUMENT_POSITION_FOLLOWING |
1156 DOCUMENT_POSITION_IS_CONTAINED;
1157 otherAncestor = node;
1158 }
1159
1160 }
1161 }
1162
1163 // thisAncestor and otherAncestor must be the same at this point,
1164 // otherwise, the original nodes are disconnected
1165 if (thisAncestor != otherAncestor) {
1166 int thisAncestorNum, otherAncestorNum;
1167 thisAncestorNum = ((NodeImpl)thisAncestor).getNodeNumber();
1168 otherAncestorNum = ((NodeImpl)otherAncestor).getNodeNumber();
1169
1170 if (thisAncestorNum > otherAncestorNum)
1171 return DOCUMENT_POSITION_DISCONNECTED |
1172 DOCUMENT_POSITION_FOLLOWING |
1173 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1174 else
1175 return DOCUMENT_POSITION_DISCONNECTED |
1176 DOCUMENT_POSITION_PRECEDING |
1177 DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
1178 }
1179
1180
1181 // Go up the parent chain of the deeper node, until we find a node
1182 // with the same depth as the shallower node
1183
1184 if (thisDepth > otherDepth) {
1185 for (int i=0; i<thisDepth - otherDepth; i++)
1186 thisNode = thisNode.getParentNode();
1187 // Check if the node we have reached is in fact "otherNode". This can
1188 // happen in the case of attributes. In this case, otherNode
1189 // "precedes" this.
1190 if (thisNode == otherNode)
1191 {
1192 return DOCUMENT_POSITION_PRECEDING;
1193 }
1194 }
1195
1196 else {
1197 for (int i=0; i<otherDepth - thisDepth; i++)
1198 otherNode = otherNode.getParentNode();
1199 // Check if the node we have reached is in fact "thisNode". This can
1200 // happen in the case of attributes. In this case, otherNode
1201 // "follows" this.
1202 if (otherNode == thisNode)
1203 return DOCUMENT_POSITION_FOLLOWING;
1204 }
1205
1206 // We now have nodes at the same depth in the tree. Find a common
1207 // ancestor.
1208 Node thisNodeP, otherNodeP;
1209 for (thisNodeP=thisNode.getParentNode(),
1210 otherNodeP=otherNode.getParentNode();
1211 thisNodeP!=otherNodeP;) {
1212 thisNode = thisNodeP;
1213 otherNode = otherNodeP;
1214 thisNodeP = thisNodeP.getParentNode();
1215 otherNodeP = otherNodeP.getParentNode();
1216 }
1217
1218 // At this point, thisNode and otherNode are direct children of
1219 // the common ancestor.
1220 // See whether thisNode or otherNode is the leftmost
1221
1222 for (Node current=thisNodeP.getFirstChild();
1223 current!=null;
1224 current=current.getNextSibling()) {
1225 if (current==otherNode) {
1226 return DOCUMENT_POSITION_PRECEDING;
1227 }
1228 else if (current==thisNode) {
1229 return DOCUMENT_POSITION_FOLLOWING;
1230 }
1231 }
1232 // REVISIT: shouldn't get here. Should probably throw an
1233 // exception
1234 return 0;
1235
1236 }
1237
1238 /**
1239 * This attribute returns the text content of this node and its
1240 * descendants. When it is defined to be null, setting it has no effect.
1241 * When set, any possible children this node may have are removed and
1242 * replaced by a single <code>Text</code> node containing the string
1243 * this attribute is set to. On getting, no serialization is performed,
1244 * the returned string does not contain any markup. No whitespace
1245 * normalization is performed, the returned string does not contain the
1246 * element content whitespaces . Similarly, on setting, no parsing is
1247 * performed either, the input string is taken as pure textual content.
1248 * <br>The string returned is made of the text content of this node
1249 * depending on its type, as defined below:
1250 * <table border='1'>
1251 * <tr>
1252 * <th>Node type</th>
1253 * <th>Content</th>
1254 * </tr>
1255
1256 /**
1257 * This attribute returns the text content of this node and its
1258 * descendants. When it is defined to be null, setting it has no effect.
1259 * When set, any possible children this node may have are removed and
1260 * replaced by a single <code>Text</code> node containing the string
1261 * this attribute is set to. On getting, no serialization is performed,
1262 * the returned string does not contain any markup. No whitespace
1263 * normalization is performed, the returned string does not contain the
1264 * element content whitespaces . Similarly, on setting, no parsing is
1265 * performed either, the input string is taken as pure textual content.
1266 * <br>The string returned is made of the text content of this node
1267 * depending on its type, as defined below:
1268 * <table border='1'>
1269 * <tr>
1270 * <th>Node type</th>
1271 * <th>Content</th>
1272 * </tr>
1273 * <tr>
1274 * <td valign='top' rowspan='1' colspan='1'>
1275 * ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
1276 * DOCUMENT_FRAGMENT_NODE</td>
1277 * <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
1278 * attribute value of every child node, excluding COMMENT_NODE and
1279 * PROCESSING_INSTRUCTION_NODE nodes</td>
1280 * </tr>
1281 * <tr>
1282 * <td valign='top' rowspan='1' colspan='1'>ATTRIBUTE_NODE, TEXT_NODE,
1283 * CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE</td>
1284 * <td valign='top' rowspan='1' colspan='1'>
1285 * <code>nodeValue</code></td>
1286 * </tr>
1287 * <tr>
1288 * <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
1289 * <td valign='top' rowspan='1' colspan='1'>
1290 * null</td>
1291 * </tr>
1292 * </table>
1293 * @exception DOMException
1294 * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
1295 * @exception DOMException
1296 * DOMSTRING_SIZE_ERR: Raised when it would return more characters than
1297 * fit in a <code>DOMString</code> variable on the implementation
1298 * platform.
1299 * @since DOM Level 3
1300 */
1301 public String getTextContent() throws DOMException {
1302 return getNodeValue(); // overriden in some subclasses
1303 }
1304
1305 // internal method taking a StringBuffer in parameter
1306 void getTextContent(StringBuffer buf) throws DOMException {
1307 String content = getNodeValue();
1308 if (content != null) {
1309 buf.append(content);
1310 }
1311 }
1312
1313 /**
1314 * This attribute returns the text content of this node and its
1315 * descendants. When it is defined to be null, setting it has no effect.
1316 * When set, any possible children this node may have are removed and
1317 * replaced by a single <code>Text</code> node containing the string
1318 * this attribute is set to. On getting, no serialization is performed,
1319 * the returned string does not contain any markup. No whitespace
1320 * normalization is performed, the returned string does not contain the
1321 * element content whitespaces . Similarly, on setting, no parsing is
1322 * performed either, the input string is taken as pure textual content.
1323 * <br>The string returned is made of the text content of this node
1324 * depending on its type, as defined below:
1325 * <table border='1'>
1326 * <tr>
1327 * <th>Node type</th>
1328 * <th>Content</th>
1329 * </tr>
1330 * <tr>
1331 * <td valign='top' rowspan='1' colspan='1'>
1332 * ELEMENT_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE,
1333 * DOCUMENT_FRAGMENT_NODE</td>
1334 * <td valign='top' rowspan='1' colspan='1'>concatenation of the <code>textContent</code>
1335 * attribute value of every child node, excluding COMMENT_NODE and
1336 * PROCESSING_INSTRUCTION_NODE nodes</td>
1337 * </tr>
1338 * <tr>
1339 * <td valign='top' rowspan='1' colspan='1'>ATTRIBUTE_NODE, TEXT_NODE,
1340 * CDATA_SECTION_NODE, COMMENT_NODE, PROCESSING_INSTRUCTION_NODE</td>
1341 * <td valign='top' rowspan='1' colspan='1'>
1342 * <code>nodeValue</code></td>
1343 * </tr>
1344 * <tr>
1345 * <td valign='top' rowspan='1' colspan='1'>DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE</td>
1346 * <td valign='top' rowspan='1' colspan='1'>
1347 * null</td>
1348 * </tr>
1349 * </table>
1350 * @exception DOMException
1351 * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
1352 * @exception DOMException
1353 * DOMSTRING_SIZE_ERR: Raised when it would return more characters than
1354 * fit in a <code>DOMString</code> variable on the implementation
1355 * platform.
1356 * @since DOM Level 3
1357 */
1358 public void setTextContent(String textContent)
1359 throws DOMException {
1360 setNodeValue(textContent);
1361 }
1362
1363 /**
1364 * Returns whether this node is the same node as the given one.
1365 * <br>This method provides a way to determine whether two
1366 * <code>Node</code> references returned by the implementation reference
1367 * the same object. When two <code>Node</code> references are references
1368 * to the same object, even if through a proxy, the references may be
1369 * used completely interchangably, such that all attributes have the
1370 * same values and calling the same DOM method on either reference
1371 * always has exactly the same effect.
1372 * @param other The node to test against.
1373 * @return Returns <code>true</code> if the nodes are the same,
1374 * <code>false</code> otherwise.
1375 * @since DOM Level 3
1376 */
1377 public boolean isSameNode(Node other) {
1378 // we do not use any wrapper so the answer is obvious
1379 return this == other;
1380 }
1381
1382
1383
1384
1385 /**
1386 * DOM Level 3: Experimental
1387 * This method checks if the specified <code>namespaceURI</code> is the
1388 * default namespace or not.
1389 * @param namespaceURI The namespace URI to look for.
1390 * @return <code>true</code> if the specified <code>namespaceURI</code>
1391 * is the default namespace, <code>false</code> otherwise.
1392 * @since DOM Level 3
1393 */
1394 public boolean isDefaultNamespace(String namespaceURI){
1395 // REVISIT: remove casts when DOM L3 becomes REC.
1396 short type = this.getNodeType();
1397 switch (type) {
1398 case Node.ELEMENT_NODE: {
1399 String namespace = this.getNamespaceURI();
1400 String prefix = this.getPrefix();
1401
1402 // REVISIT: is it possible that prefix is empty string?
1403 if (prefix == null || prefix.length() == 0) {
1404 if (namespaceURI == null) {
1405 return (namespace == namespaceURI);
1406 }
1407 return namespaceURI.equals(namespace);
1408 }
1409 if (this.hasAttributes()) {
1410 ElementImpl elem = (ElementImpl)this;
1411 NodeImpl attr = (NodeImpl)elem.getAttributeNodeNS("http://www.w3.org/2000/xmlns/", "xmlns");
1412 if (attr != null) {
1413 String value = attr.getNodeValue();
1414 if (namespaceURI == null) {
1415 return (namespace == value);
1416 }
1417 return namespaceURI.equals(value);
1418 }
1419 }
1420
1421 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1422 if (ancestor != null) {
1423 return ancestor.isDefaultNamespace(namespaceURI);
1424 }
1425 return false;
1426 }
1427 case Node.DOCUMENT_NODE:{
1428 return((NodeImpl)((Document)this).getDocumentElement()).isDefaultNamespace(namespaceURI);
1429 }
1430
1431 case Node.ENTITY_NODE :
1432 case Node.NOTATION_NODE:
1433 case Node.DOCUMENT_FRAGMENT_NODE:
1434 case Node.DOCUMENT_TYPE_NODE:
1435 // type is unknown
1436 return false;
1437 case Node.ATTRIBUTE_NODE:{
1438 if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1439 return ownerNode.isDefaultNamespace(namespaceURI);
1440
1441 }
1442 return false;
1443 }
1444 default:{
1445 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1446 if (ancestor != null) {
1447 return ancestor.isDefaultNamespace(namespaceURI);
1448 }
1449 return false;
1450 }
1451
1452 }
1453
1454
1455 }
1456
1457
1458 /**
1459 *
1460 * DOM Level 3 - Experimental:
1461 * Look up the prefix associated to the given namespace URI, starting from this node.
1462 *
1463 * @param namespaceURI
1464 * @return the prefix for the namespace
1465 */
1466 public String lookupPrefix(String namespaceURI){
1467
1468 // REVISIT: When Namespaces 1.1 comes out this may not be true
1469 // Prefix can't be bound to null namespace
1470 if (namespaceURI == null) {
1471 return null;
1472 }
1473
1474 short type = this.getNodeType();
1475
1476 switch (type) {
1477 case Node.ELEMENT_NODE: {
1478
1479 String namespace = this.getNamespaceURI(); // to flip out children
1480 return lookupNamespacePrefix(namespaceURI, (ElementImpl)this);
1481 }
1482 case Node.DOCUMENT_NODE:{
1483 return((NodeImpl)((Document)this).getDocumentElement()).lookupPrefix(namespaceURI);
1484 }
1485
1486 case Node.ENTITY_NODE :
1487 case Node.NOTATION_NODE:
1488 case Node.DOCUMENT_FRAGMENT_NODE:
1489 case Node.DOCUMENT_TYPE_NODE:
1490 // type is unknown
1491 return null;
1492 case Node.ATTRIBUTE_NODE:{
1493 if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1494 return ownerNode.lookupPrefix(namespaceURI);
1495
1496 }
1497 return null;
1498 }
1499 default:{
1500 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1501 if (ancestor != null) {
1502 return ancestor.lookupPrefix(namespaceURI);
1503 }
1504 return null;
1505 }
1506
1507 }
1508 }
1509 /**
1510 * DOM Level 3 - Experimental:
1511 * Look up the namespace URI associated to the given prefix, starting from this node.
1512 * Use lookupNamespaceURI(null) to lookup the default namespace
1513 *
1514 * @param namespaceURI
1515 * @return th URI for the namespace
1516 * @since DOM Level 3
1517 */
1518 public String lookupNamespaceURI(String specifiedPrefix) {
1519 short type = this.getNodeType();
1520 switch (type) {
1521 case Node.ELEMENT_NODE : {
1522
1523 String namespace = this.getNamespaceURI();
1524 String prefix = this.getPrefix();
1525 if (namespace !=null) {
1526 // REVISIT: is it possible that prefix is empty string?
1527 if (specifiedPrefix== null && prefix==specifiedPrefix) {
1528 // looking for default namespace
1529 return namespace;
1530 } else if (prefix != null && prefix.equals(specifiedPrefix)) {
1531 // non default namespace
1532 return namespace;
1533 }
1534 }
1535 if (this.hasAttributes()) {
1536 NamedNodeMap map = this.getAttributes();
1537 int length = map.getLength();
1538 for (int i=0;i<length;i++) {
1539 Node attr = map.item(i);
1540 String attrPrefix = attr.getPrefix();
1541 String value = attr.getNodeValue();
1542 namespace = attr.getNamespaceURI();
1543 if (namespace !=null && namespace.equals("http://www.w3.org/2000/xmlns/")) {
1544 // at this point we are dealing with DOM Level 2 nodes only
1545 if (specifiedPrefix == null &&
1546 attr.getNodeName().equals("xmlns")) {
1547 // default namespace
1548 return value;
1549 } else if (attrPrefix !=null &&
1550 attrPrefix.equals("xmlns") &&
1551 attr.getLocalName().equals(specifiedPrefix)) {
1552 // non default namespace
1553 return value;
1554 }
1555 }
1556 }
1557 }
1558 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1559 if (ancestor != null) {
1560 return ancestor.lookupNamespaceURI(specifiedPrefix);
1561 }
1562
1563 return null;
1564
1565
1566 }
1567 case Node.DOCUMENT_NODE : {
1568 return((NodeImpl)((Document)this).getDocumentElement()).lookupNamespaceURI(specifiedPrefix);
1569 }
1570 case Node.ENTITY_NODE :
1571 case Node.NOTATION_NODE:
1572 case Node.DOCUMENT_FRAGMENT_NODE:
1573 case Node.DOCUMENT_TYPE_NODE:
1574 // type is unknown
1575 return null;
1576 case Node.ATTRIBUTE_NODE:{
1577 if (this.ownerNode.getNodeType() == Node.ELEMENT_NODE) {
1578 return ownerNode.lookupNamespaceURI(specifiedPrefix);
1579
1580 }
1581 return null;
1582 }
1583 default:{
1584 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1585 if (ancestor != null) {
1586 return ancestor.lookupNamespaceURI(specifiedPrefix);
1587 }
1588 return null;
1589 }
1590
1591 }
1592 }
1593
1594
1595 Node getElementAncestor (Node currentNode){
1596 Node parent = currentNode.getParentNode();
1597 if (parent != null) {
1598 short type = parent.getNodeType();
1599 if (type == Node.ELEMENT_NODE) {
1600 return parent;
1601 }
1602 return getElementAncestor(parent);
1603 }
1604 return null;
1605 }
1606
1607 String lookupNamespacePrefix(String namespaceURI, ElementImpl el){
1608 String namespace = this.getNamespaceURI();
1609 // REVISIT: if no prefix is available is it null or empty string, or
1610 // could be both?
1611 String prefix = this.getPrefix();
1612
1613 if (namespace!=null && namespace.equals(namespaceURI)) {
1614 if (prefix != null) {
1615 String foundNamespace = el.lookupNamespaceURI(prefix);
1616 if (foundNamespace !=null && foundNamespace.equals(namespaceURI)) {
1617 return prefix;
1618 }
1619
1620 }
1621 }
1622 if (this.hasAttributes()) {
1623 NamedNodeMap map = this.getAttributes();
1624 int length = map.getLength();
1625 for (int i=0;i<length;i++) {
1626 Node attr = map.item(i);
1627 String attrPrefix = attr.getPrefix();
1628 String value = attr.getNodeValue();
1629 namespace = attr.getNamespaceURI();
1630 if (namespace !=null && namespace.equals("http://www.w3.org/2000/xmlns/")) {
1631 // DOM Level 2 nodes
1632 if (((attr.getNodeName().equals("xmlns")) ||
1633 (attrPrefix !=null && attrPrefix.equals("xmlns")) &&
1634 value.equals(namespaceURI))) {
1635
1636 String localname= attr.getLocalName();
1637 String foundNamespace = el.lookupNamespaceURI(localname);
1638 if (foundNamespace !=null && foundNamespace.equals(namespaceURI)) {
1639 return localname;
1640 }
1641 }
1642
1643
1644 }
1645 }
1646 }
1647 NodeImpl ancestor = (NodeImpl)getElementAncestor(this);
1648
1649 if (ancestor != null) {
1650 return ancestor.lookupNamespacePrefix(namespaceURI, el);
1651 }
1652 return null;
1653 }
1654
1655 /**
1656 * Tests whether two nodes are equal.
1657 * <br>This method tests for equality of nodes, not sameness (i.e.,
1658 * whether the two nodes are references to the same object) which can be
1659 * tested with <code>Node.isSameNode</code>. All nodes that are the same
1660 * will also be equal, though the reverse may not be true.
1661 * <br>Two nodes are equal if and only if the following conditions are
1662 * satisfied: The two nodes are of the same type.The following string
1663 * attributes are equal: <code>nodeName</code>, <code>localName</code>,
1664 * <code>namespaceURI</code>, <code>prefix</code>, <code>nodeValue</code>
1665 * , <code>baseURI</code>. This is: they are both <code>null</code>, or
1666 * they have the same length and are character for character identical.
1667 * The <code>attributes</code> <code>NamedNodeMaps</code> are equal.
1668 * This is: they are both <code>null</code>, or they have the same
1669 * length and for each node that exists in one map there is a node that
1670 * exists in the other map and is equal, although not necessarily at the
1671 * same index.The <code>childNodes</code> <code>NodeLists</code> are
1672 * equal. This is: they are both <code>null</code>, or they have the
1673 * same length and contain equal nodes at the same index. This is true
1674 * for <code>Attr</code> nodes as for any other type of node. Note that
1675 * normalization can affect equality; to avoid this, nodes should be
1676 * normalized before being compared.
1677 * <br>For two <code>DocumentType</code> nodes to be equal, the following
1678 * conditions must also be satisfied: The following string attributes
1679 * are equal: <code>publicId</code>, <code>systemId</code>,
1680 * <code>internalSubset</code>.The <code>entities</code>
1681 * <code>NamedNodeMaps</code> are equal.The <code>notations</code>
1682 * <code>NamedNodeMaps</code> are equal.
1683 * <br>On the other hand, the following do not affect equality: the
1684 * <code>ownerDocument</code> attribute, the <code>specified</code>
1685 * attribute for <code>Attr</code> nodes, the
1686 * <code>isWhitespaceInElementContent</code> attribute for
1687 * <code>Text</code> nodes, as well as any user data or event listeners
1688 * registered on the nodes.
1689 * @param arg The node to compare equality with.
1690 * @param deep If <code>true</code>, recursively compare the subtrees; if
1691 * <code>false</code>, compare only the nodes themselves (and its
1692 * attributes, if it is an <code>Element</code>).
1693 * @return If the nodes, and possibly subtrees are equal,
1694 * <code>true</code> otherwise <code>false</code>.
1695 * @since DOM Level 3
1696 */
1697 public boolean isEqualNode(Node arg) {
1698 if (arg == this) {
1699 return true;
1700 }
1701 if (arg.getNodeType() != getNodeType()) {
1702 return false;
1703 }
1704 // in theory nodeName can't be null but better be careful
1705 // who knows what other implementations may be doing?...
1706 if (getNodeName() == null) {
1707 if (arg.getNodeName() != null) {
1708 return false;
1709 }
1710 }
1711 else if (!getNodeName().equals(arg.getNodeName())) {
1712 return false;
1713 }
1714
1715 if (getLocalName() == null) {
1716 if (arg.getLocalName() != null) {
1717 return false;
1718 }
1719 }
1720 else if (!getLocalName().equals(arg.getLocalName())) {
1721 return false;
1722 }
1723
1724 if (getNamespaceURI() == null) {
1725 if (arg.getNamespaceURI() != null) {
1726 return false;
1727 }
1728 }
1729 else if (!getNamespaceURI().equals(arg.getNamespaceURI())) {
1730 return false;
1731 }
1732
1733 if (getPrefix() == null) {
1734 if (arg.getPrefix() != null) {
1735 return false;
1736 }
1737 }
1738 else if (!getPrefix().equals(arg.getPrefix())) {
1739 return false;
1740 }
1741
1742 if (getNodeValue() == null) {
1743 if (arg.getNodeValue() != null) {
1744 return false;
1745 }
1746 }
1747 else if (!getNodeValue().equals(arg.getNodeValue())) {
1748 return false;
1749 }
1750
1751
1752 return true;
1753 }
1754
1755 /**
1756 * @since DOM Level 3
1757 */
1758 public Object getFeature(String feature, String version) {
1759 // we don't have any alternate node, either this node does the job
1760 // or we don't have anything that does
1761 return isSupported(feature, version) ? this : null;
1762 }
1763
1764 /**
1765 * Associate an object to a key on this node. The object can later be
1766 * retrieved from this node by calling <code>getUserData</code> with the
1767 * same key.
1768 * @param key The key to associate the object to.
1769 * @param data The object to associate to the given key, or
1770 * <code>null</code> to remove any existing association to that key.
1771 * @param handler The handler to associate to that key, or
1772 * <code>null</code>.
1773 * @return Returns the <code>DOMObject</code> previously associated to
1774 * the given key on this node, or <code>null</code> if there was none.
1775 * @since DOM Level 3
1776 */
1777 public Object setUserData(String key,
1778 Object data,
1779 UserDataHandler handler) {
1780 return ownerDocument().setUserData(this, key, data, handler);
1781 }
1782
1783 /**
1784 * Retrieves the object associated to a key on a this node. The object
1785 * must first have been set to this node by calling
1786 * <code>setUserData</code> with the same key.
1787 * @param key The key the object is associated to.
1788 * @return Returns the <code>DOMObject</code> associated to the given key
1789 * on this node, or <code>null</code> if there was none.
1790 * @since DOM Level 3
1791 */
1792 public Object getUserData(String key) {
1793 return ownerDocument().getUserData(this, key);
1794 }
1795
1796 protected Hashtable getUserDataRecord(){
1797 return ownerDocument().getUserDataRecord(this);
1798 }
1799
1800 //
1801 // Public methods
1802 //
1803
1804 /**
1805 * NON-DOM: PR-DOM-Level-1-19980818 mentions readonly nodes in conjunction
1806 * with Entities, but provides no API to support this.
1807 * <P>
1808 * Most DOM users should not touch this method. Its anticpated use
1809 * is during construction of EntityRefernces, where it will be used to
1810 * lock the contents replicated from Entity so they can't be casually
1811 * altered. It _could_ be published as a DOM extension, if desired.
1812 * <P>
1813 * Note: since we never have any children deep is meaningless here,
1814 * ParentNode overrides this behavior.
1815 * @see ParentNode
1816 *
1817 * @param readOnly True or false as desired.
1818 * @param deep If true, children are also toggled. Note that this will
1819 * not change the state of an EntityReference or its children,
1820 * which are always read-only.
1821 */
1822 public void setReadOnly(boolean readOnly, boolean deep) {
1823
1824 if (needsSyncData()) {
1825 synchronizeData();
1826 }
1827 isReadOnly(readOnly);
1828
1829 } // setReadOnly(boolean,boolean)
1830
1831 /**
1832 * NON-DOM: Returns true if this node is read-only. This is a
1833 * shallow check.
1834 */
1835 public boolean getReadOnly() {
1836
1837 if (needsSyncData()) {
1838 synchronizeData();
1839 }
1840 return isReadOnly();
1841
1842 } // getReadOnly():boolean
1843
1844 /**
1845 * NON-DOM: As an alternative to subclassing the DOM, this implementation
1846 * has been extended with the ability to attach an object to each node.
1847 * (If you need multiple objects, you can attach a collection such as a
1848 * vector or hashtable, then attach your application information to that.)
1849 * <p><b>Important Note:</b> You are responsible for removing references
1850 * to your data on nodes that are no longer used. Failure to do so will
1851 * prevent the nodes, your data is attached to, to be garbage collected
1852 * until the whole document is.
1853 *
1854 * @param data the object to store or null to remove any existing reference
1855 */
1856 public void setUserData(Object data) {
1857 ownerDocument().setUserData(this, data);
1858 }
1859
1860 /**
1861 * NON-DOM:
1862 * Returns the user data associated to this node.
1863 */
1864 public Object getUserData() {
1865 return ownerDocument().getUserData(this);
1866 }
1867
1868 //
1869 // Protected methods
1870 //
1871
1872 /**
1873 * Denotes that this node has changed.
1874 */
1875 protected void changed() {
1876 // we do not actually store this information on every node, we only
1877 // have a global indicator on the Document. Doing otherwise cost us too
1878 // much for little gain.
1879 ownerDocument().changed();
1880 }
1881
1882 /**
1883 * Returns the number of changes to this node.
1884 */
1885 protected int changes() {
1886 // we do not actually store this information on every node, we only
1887 // have a global indicator on the Document. Doing otherwise cost us too
1888 // much for little gain.
1889 return ownerDocument().changes();
1890 }
1891
1892 /**
1893 * Override this method in subclass to hook in efficient
1894 * internal data structure.
1895 */
1896 protected void synchronizeData() {
1897 // By default just change the flag to avoid calling this method again
1898 needsSyncData(false);
1899 }
1900
1901 /**
1902 * For non-child nodes, the node which "points" to this node.
1903 * For example, the owning element for an attribute
1904 */
1905 protected Node getContainer() {
1906 return null;
1907 }
1908
1909
1910 /*
1911 * Flags setters and getters
1912 */
1913
1914 final boolean isReadOnly() {
1915 return (flags & READONLY) != 0;
1916 }
1917
1918 final void isReadOnly(boolean value) {
1919 flags = (short) (value ? flags | READONLY : flags & ~READONLY);
1920 }
1921
1922 final boolean needsSyncData() {
1923 return (flags & SYNCDATA) != 0;
1924 }
1925
1926 final void needsSyncData(boolean value) {
1927 flags = (short) (value ? flags | SYNCDATA : flags & ~SYNCDATA);
1928 }
1929
1930 final boolean needsSyncChildren() {
1931 return (flags & SYNCCHILDREN) != 0;
1932 }
1933
1934 public final void needsSyncChildren(boolean value) {
1935 flags = (short) (value ? flags | SYNCCHILDREN : flags & ~SYNCCHILDREN);
1936 }
1937
1938 final boolean isOwned() {
1939 return (flags & OWNED) != 0;
1940 }
1941
1942 final void isOwned(boolean value) {
1943 flags = (short) (value ? flags | OWNED : flags & ~OWNED);
1944 }
1945
1946 final boolean isFirstChild() {
1947 return (flags & FIRSTCHILD) != 0;
1948 }
1949
1950 final void isFirstChild(boolean value) {
1951 flags = (short) (value ? flags | FIRSTCHILD : flags & ~FIRSTCHILD);
1952 }
1953
1954 final boolean isSpecified() {
1955 return (flags & SPECIFIED) != 0;
1956 }
1957
1958 final void isSpecified(boolean value) {
1959 flags = (short) (value ? flags | SPECIFIED : flags & ~SPECIFIED);
1960 }
1961
1962 // inconsistent name to avoid clash with public method on TextImpl
1963 final boolean internalIsIgnorableWhitespace() {
1964 return (flags & IGNORABLEWS) != 0;
1965 }
1966
1967 final void isIgnorableWhitespace(boolean value) {
1968 flags = (short) (value ? flags | IGNORABLEWS : flags & ~IGNORABLEWS);
1969 }
1970
1971 final boolean hasStringValue() {
1972 return (flags & HASSTRING) != 0;
1973 }
1974
1975 final void hasStringValue(boolean value) {
1976 flags = (short) (value ? flags | HASSTRING : flags & ~HASSTRING);
1977 }
1978
1979 final boolean isNormalized() {
1980 return (flags & NORMALIZED) != 0;
1981 }
1982
1983 final void isNormalized(boolean value) {
1984 // See if flag should propagate to parent.
1985 if (!value && isNormalized() && ownerNode != null) {
1986 ownerNode.isNormalized(false);
1987 }
1988 flags = (short) (value ? flags | NORMALIZED : flags & ~NORMALIZED);
1989 }
1990
1991 final boolean isIdAttribute() {
1992 return (flags & ID) != 0;
1993 }
1994
1995 final void isIdAttribute(boolean value) {
1996 flags = (short) (value ? flags | ID : flags & ~ID);
1997 }
1998
1999 //
2000 // Object methods
2001 //
2002
2003 /** NON-DOM method for debugging convenience. */
2004 public String toString() {
2005 return "["+getNodeName()+": "+getNodeValue()+"]";
2006 }
2007
2008 //
2009 // Serialization methods
2010 //
2011
2012 /** Serialize object. */
2013 private void writeObject(ObjectOutputStream out) throws IOException {
2014
2015 // synchronize data
2016 if (needsSyncData()) {
2017 synchronizeData();
2018 }
2019 // write object
2020 out.defaultWriteObject();
2021
2022 } // writeObject(ObjectOutputStream)
2023
2024 } // class NodeImpl