1 /*
   2  * Copyright (c) 2015, 2017 Oracle and/or its affiliates. All rights reserved.
   3  */
   4  /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  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.Map;
  27 import org.w3c.dom.DOMException;
  28 import org.w3c.dom.Document;
  29 import org.w3c.dom.DocumentType;
  30 import org.w3c.dom.NamedNodeMap;
  31 import org.w3c.dom.Node;
  32 import org.w3c.dom.NodeList;
  33 import org.w3c.dom.UserDataHandler;
  34 import org.w3c.dom.events.Event;
  35 import org.w3c.dom.events.EventListener;
  36 import org.w3c.dom.events.EventTarget;
  37 
  38 /**
  39  * NodeImpl provides the basic structure of a DOM tree. It is never used
  40  * directly, but instead is subclassed to add type and data
  41  * information, and additional methods, appropriate to each node of
  42  * the tree. Only its subclasses should be instantiated -- and those,
  43  * with the exception of Document itself, only through a specific
  44  * Document's factory methods.
  45  * <P>
  46  * The Node interface provides shared behaviors such as siblings and
  47  * children, both for consistancy and so that the most common tree
  48  * operations may be performed without constantly having to downcast
  49  * to specific node types. When there is no obvious mapping for one of
  50  * these queries, it will respond with null.
  51  * Note that the default behavior is that children are forbidden. To
  52  * permit them, the subclass ParentNode overrides several methods.
  53  * <P>
  54  * NodeImpl also implements NodeList, so it can return itself in
  55  * response to the getChildNodes() query. This eliminiates the need
  56  * for a separate ChildNodeList object. Note that this is an
  57  * IMPLEMENTATION DETAIL; applications should _never_ assume that
  58  * this identity exists.
  59  * <P>
  60  * All nodes in a single document must originate
  61  * in that document. (Note that this is much tighter than "must be
  62  * same implementation") Nodes are all aware of their ownerDocument,
  63  * and attempts to mismatch will throw WRONG_DOCUMENT_ERR.
  64  * <P>
  65  * However, to save memory not all nodes always have a direct reference
  66  * to their ownerDocument. When a node is owned by another node it relies
  67  * on its owner to store its ownerDocument. Parent nodes always store it
  68  * though, so there is never more than one level of indirection.
  69  * And when a node doesn't have an owner, ownerNode refers to its
  70  * ownerDocument.
  71  * <p>
  72  * This class doesn't directly support mutation events, however, it still
  73  * implements the EventTarget interface and forward all related calls to the
  74  * document so that the document class do so.
  75  *
  76  * @xerces.internal
  77  *
  78  * @author Arnaud  Le Hors, IBM
  79  * @author Joe Kesselman, IBM
  80  * @since  PR-DOM-Level-1-19980818.
  81  */
  82 public abstract class NodeImpl
  83     implements Node, NodeList, EventTarget, Cloneable, Serializable{
  84 
  85     //
  86     // Constants
  87     //
  88 
  89 
  90     // TreePosition Constants.
  91     // Taken from DOM L3 Node interface.
  92     /**
  93      * The node precedes the reference node.
  94      */
  95     public static final short TREE_POSITION_PRECEDING   = 0x01;
  96     /**
  97      * The node follows the reference node.
  98      */
  99     public static final short TREE_POSITION_FOLLOWING   = 0x02;
 100     /**
 101      * The node is an ancestor of the reference node.
 102      */
 103     public static final short TREE_POSITION_ANCESTOR    = 0x04;
 104     /**
 105      * The node is a descendant of the reference node.
 106      */
 107     public static final short TREE_POSITION_DESCENDANT  = 0x08;
 108     /**
 109      * The two nodes have an equivalent position. This is the case of two
 110      * attributes that have the same <code>ownerElement</code>, and two
 111      * nodes that are the same.
 112      */
 113     public static final short TREE_POSITION_EQUIVALENT  = 0x10;
 114     /**
 115      * The two nodes are the same. Two nodes that are the same have an
 116      * equivalent position, though the reverse may not be true.
 117      */
 118     public static final short TREE_POSITION_SAME_NODE   = 0x20;
 119     /**
 120      * The two nodes are disconnected, they do not have any common ancestor.
 121      * This is the case of two nodes that are not in the same document.
 122      */
 123     public static final short TREE_POSITION_DISCONNECTED = 0x00;
 124 
 125 
 126     // DocumentPosition
 127     public static final short DOCUMENT_POSITION_DISCONNECTED = 0x01;
 128     public static final short DOCUMENT_POSITION_PRECEDING = 0x02;
 129     public static final short DOCUMENT_POSITION_FOLLOWING = 0x04;
 130     public static final short DOCUMENT_POSITION_CONTAINS = 0x08;
 131     public static final short DOCUMENT_POSITION_IS_CONTAINED = 0x10;
 132     public static final short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
 133 
 134     /** Serialization version. */
 135     static final long serialVersionUID = -6316591992167219696L;
 136 
 137     // public
 138 
 139     /** Element definition node type. */
 140     public static final short ELEMENT_DEFINITION_NODE = 21;
 141 
 142     //
 143     // Data
 144     //
 145 
 146     // links
 147 
 148     protected NodeImpl ownerNode; // typically the parent but not always!
 149 
 150     // data
 151 
 152     protected short flags;
 153 
 154     protected final static short READONLY     = 0x1<<0;
 155     protected final static short SYNCDATA     = 0x1<<1;
 156     protected final static short SYNCCHILDREN = 0x1<<2;
 157     protected final static short OWNED        = 0x1<<3;
 158     protected final static short FIRSTCHILD   = 0x1<<4;
 159     protected final static short SPECIFIED    = 0x1<<5;
 160     protected final static short IGNORABLEWS  = 0x1<<6;
 161     protected final static short HASSTRING    = 0x1<<7;
 162     protected final static short NORMALIZED = 0x1<<8;
 163     protected final static short ID           = 0x1<<9;
 164 
 165     //
 166     // Constructors
 167     //
 168 
 169     /**
 170      * No public constructor; only subclasses of Node should be
 171      * instantiated, and those normally via a Document's factory methods
 172      * <p>
 173      * Every Node knows what Document it belongs to.
 174      */
 175     protected NodeImpl(CoreDocumentImpl ownerDocument) {
 176         // as long as we do not have any owner, ownerNode is our ownerDocument
 177         ownerNode = ownerDocument;
 178     } // <init>(CoreDocumentImpl)
 179 
 180     /** Constructor for serialization. */
 181     public NodeImpl() {}
 182 
 183     //
 184     // Node methods
 185     //
 186 
 187     /**
 188      * A short integer indicating what type of node this is. The named
 189      * constants for this value are defined in the org.w3c.dom.Node interface.
 190      */
 191     public abstract short getNodeType();
 192 
 193     /**
 194      * the name of this node.
 195      */
 196     public abstract String getNodeName();
 197 
 198     /**
 199      * Returns the node value.
 200      * @throws DOMException(DOMSTRING_SIZE_ERR)
 201      */
 202     public String getNodeValue()
 203         throws DOMException {
 204         return null;            // overridden in some subclasses
 205     }
 206 
 207     /**
 208      * Sets the node value.
 209      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR)
 210      */
 211     public void setNodeValue(String x)
 212         throws DOMException {
 213         // Default behavior is to do nothing, overridden in some subclasses
 214     }
 215 
 216     /**
 217      * Adds a child node to the end of the list of children for this node.
 218      * Convenience shorthand for insertBefore(newChild,null).
 219      * @see #insertBefore(Node, Node)
 220      * <P>
 221      * By default we do not accept any children, ParentNode overrides this.
 222      * @see ParentNode
 223      *
 224      * @return newChild, in its new state (relocated, or emptied in the case of
 225      * DocumentNode.)
 226      *
 227      * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
 228      * type that shouldn't be a child of this node.
 229      *
 230      * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
 231      * different owner document than we do.
 232      *
 233      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
 234      * read-only.
 235      */
 236     public Node appendChild(Node newChild) throws DOMException {
 237         return insertBefore(newChild, null);
 238     }
 239 
 240     /**
 241      * Returns a duplicate of a given node. You can consider this a
 242      * generic "copy constructor" for nodes. The newly returned object should
 243      * be completely independent of the source object's subtree, so changes
 244      * in one after the clone has been made will not affect the other.
 245      * <P>
 246      * Note: since we never have any children deep is meaningless here,
 247      * ParentNode overrides this behavior.
 248      * @see ParentNode
 249      *
 250      * <p>
 251      * Example: Cloning a Text node will copy both the node and the text it
 252      * contains.
 253      * <p>
 254      * Example: Cloning something that has children -- Element or Attr, for
 255      * example -- will _not_ clone those children unless a "deep clone"
 256      * has been requested. A shallow clone of an Attr node will yield an
 257      * empty Attr of the same name.
 258      * <p>
 259      * NOTE: Clones will always be read/write, even if the node being cloned
 260      * is read-only, to permit applications using only the DOM API to obtain
 261      * editable copies of locked portions of the tree.
 262      */
 263     public Node cloneNode(boolean deep) {
 264 
 265         if (needsSyncData()) {
 266             synchronizeData();
 267         }
 268 
 269         NodeImpl newnode;
 270         try {
 271             newnode = (NodeImpl)clone();
 272         }
 273         catch (CloneNotSupportedException e) {
 274             // if we get here we have an error in our program we may as well
 275             // be vocal about it, so that people can take appropriate action.
 276             throw new RuntimeException("**Internal Error**" + e);
 277         }
 278 
 279         // Need to break the association w/ original kids
 280         newnode.ownerNode      = ownerDocument();
 281         newnode.isOwned(false);
 282 
 283         // By default we make all clones readwrite,
 284         // this is overriden in readonly subclasses
 285         newnode.isReadOnly(false);
 286 
 287         ownerDocument().callUserDataHandlers(this, newnode,
 288                                              UserDataHandler.NODE_CLONED);
 289 
 290         return newnode;
 291 
 292     } // cloneNode(boolean):Node
 293 
 294     /**
 295      * Find the Document that this Node belongs to (the document in
 296      * whose context the Node was created). The Node may or may not
 297      * currently be part of that Document's actual contents.
 298      */
 299     public Document getOwnerDocument() {
 300         // if we have an owner simply forward the request
 301         // otherwise ownerNode is our ownerDocument
 302         if (isOwned()) {
 303             return ownerNode.ownerDocument();
 304         } else {
 305             return (Document) ownerNode;
 306         }
 307     }
 308 
 309     /**
 310      * same as above but returns internal type and this one is not overridden
 311      * by CoreDocumentImpl to return null
 312      */
 313     CoreDocumentImpl ownerDocument() {
 314         // if we have an owner simply forward the request
 315         // otherwise ownerNode is our ownerDocument
 316         if (isOwned()) {
 317             return ownerNode.ownerDocument();
 318         } else {
 319             return (CoreDocumentImpl) ownerNode;
 320         }
 321     }
 322 
 323     /**
 324      * NON-DOM
 325      * set the ownerDocument of this node
 326      */
 327     void setOwnerDocument(CoreDocumentImpl doc) {
 328         if (needsSyncData()) {
 329             synchronizeData();
 330         }
 331         // if we have an owner we rely on it to have it right
 332         // otherwise ownerNode is our ownerDocument
 333         if (!isOwned()) {
 334             ownerNode = doc;
 335         }
 336     }
 337 
 338     /**
 339      * Returns the node number
 340      */
 341     protected int getNodeNumber() {
 342         int nodeNumber;
 343         CoreDocumentImpl cd = (CoreDocumentImpl)(this.getOwnerDocument());
 344         nodeNumber = cd.getNodeNumber(this);
 345         return nodeNumber;
 346     }
 347 
 348     /**
 349      * Obtain the DOM-tree parent of this node, or null if it is not
 350      * currently active in the DOM tree (perhaps because it has just been
 351      * created or removed). Note that Document, DocumentFragment, and
 352      * Attribute will never have parents.
 353      */
 354     public Node getParentNode() {
 355         return null;            // overriden by ChildNode
 356     }
 357 
 358     /*
 359      * same as above but returns internal type
 360      */
 361     NodeImpl parentNode() {
 362         return null;
 363     }
 364 
 365     /** The next child of this node's parent, or null if none */
 366     public Node getNextSibling() {
 367         return null;            // default behavior, overriden in ChildNode
 368     }
 369 
 370     /** The previous child of this node's parent, or null if none */
 371     public Node getPreviousSibling() {
 372         return null;            // default behavior, overriden in ChildNode
 373     }
 374 
 375     ChildNode previousSibling() {
 376         return null;            // default behavior, overriden in ChildNode
 377     }
 378 
 379     /**
 380      * Return the collection of attributes associated with this node,
 381      * or null if none. At this writing, Element is the only type of node
 382      * which will ever have attributes.
 383      *
 384      * @see ElementImpl
 385      */
 386     public NamedNodeMap getAttributes() {
 387         return null; // overridden in ElementImpl
 388     }
 389 
 390     /**
 391      *  Returns whether this node (if it is an element) has any attributes.
 392      * @return <code>true</code> if this node has any attributes,
 393      *   <code>false</code> otherwise.
 394      * @since DOM Level 2
 395      * @see ElementImpl
 396      */
 397     public boolean hasAttributes() {
 398         return false;           // overridden in ElementImpl
 399     }
 400 
 401     /**
 402      * Test whether this node has any children. Convenience shorthand
 403      * for (Node.getFirstChild()!=null)
 404      * <P>
 405      * By default we do not have any children, ParentNode overrides this.
 406      * @see ParentNode
 407      */
 408     public boolean hasChildNodes() {
 409         return false;
 410     }
 411 
 412     /**
 413      * Obtain a NodeList enumerating all children of this node. If there
 414      * are none, an (initially) empty NodeList is returned.
 415      * <p>
 416      * NodeLists are "live"; as children are added/removed the NodeList
 417      * will immediately reflect those changes. Also, the NodeList refers
 418      * to the actual nodes, so changes to those nodes made via the DOM tree
 419      * will be reflected in the NodeList and vice versa.
 420      * <p>
 421      * In this implementation, Nodes implement the NodeList interface and
 422      * provide their own getChildNodes() support. Other DOMs may solve this
 423      * differently.
 424      */
 425     public NodeList getChildNodes() {
 426         return this;
 427     }
 428 
 429     /** The first child of this Node, or null if none.
 430      * <P>
 431      * By default we do not have any children, ParentNode overrides this.
 432      * @see ParentNode
 433      */
 434     public Node getFirstChild() {
 435         return null;
 436     }
 437 
 438     /** The first child of this Node, or null if none.
 439      * <P>
 440      * By default we do not have any children, ParentNode overrides this.
 441      * @see ParentNode
 442      */
 443     public Node getLastChild() {
 444         return null;
 445     }
 446 
 447     /**
 448      * Move one or more node(s) to our list of children. Note that this
 449      * implicitly removes them from their previous parent.
 450      * <P>
 451      * By default we do not accept any children, ParentNode overrides this.
 452      * @see ParentNode
 453      *
 454      * @param newChild The Node to be moved to our subtree. As a
 455      * convenience feature, inserting a DocumentNode will instead insert
 456      * all its children.
 457      *
 458      * @param refChild Current child which newChild should be placed
 459      * immediately before. If refChild is null, the insertion occurs
 460      * after all existing Nodes, like appendChild().
 461      *
 462      * @return newChild, in its new state (relocated, or emptied in the case of
 463      * DocumentNode.)
 464      *
 465      * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
 466      * type that shouldn't be a child of this node, or if newChild is an
 467      * ancestor of this node.
 468      *
 469      * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
 470      * different owner document than we do.
 471      *
 472      * @throws DOMException(NOT_FOUND_ERR) if refChild is not a child of
 473      * this node.
 474      *
 475      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
 476      * read-only.
 477      */
 478     public Node insertBefore(Node newChild, Node refChild)
 479         throws DOMException {
 480         throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
 481               DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
 482                  "HIERARCHY_REQUEST_ERR", null));
 483     }
 484 
 485     /**
 486      * Remove a child from this Node. The removed child's subtree
 487      * remains intact so it may be re-inserted elsewhere.
 488      * <P>
 489      * By default we do not have any children, ParentNode overrides this.
 490      * @see ParentNode
 491      *
 492      * @return oldChild, in its new state (removed).
 493      *
 494      * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
 495      * this node.
 496      *
 497      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
 498      * read-only.
 499      */
 500     public Node removeChild(Node oldChild)
 501                 throws DOMException {
 502         throw new DOMException(DOMException.NOT_FOUND_ERR,
 503               DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
 504                  "NOT_FOUND_ERR", null));
 505     }
 506 
 507     /**
 508      * Make newChild occupy the location that oldChild used to
 509      * have. Note that newChild will first be removed from its previous
 510      * parent, if any. Equivalent to inserting newChild before oldChild,
 511      * then removing oldChild.
 512      * <P>
 513      * By default we do not have any children, ParentNode overrides this.
 514      * @see ParentNode
 515      *
 516      * @return oldChild, in its new state (removed).
 517      *
 518      * @throws DOMException(HIERARCHY_REQUEST_ERR) if newChild is of a
 519      * type that shouldn't be a child of this node, or if newChild is
 520      * one of our ancestors.
 521      *
 522      * @throws DOMException(WRONG_DOCUMENT_ERR) if newChild has a
 523      * different owner document than we do.
 524      *
 525      * @throws DOMException(NOT_FOUND_ERR) if oldChild is not a child of
 526      * this node.
 527      *
 528      * @throws DOMException(NO_MODIFICATION_ALLOWED_ERR) if this node is
 529      * read-only.
 530      */
 531     public Node replaceChild(Node newChild, Node oldChild)
 532         throws DOMException {
 533         throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
 534               DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
 535                  "HIERARCHY_REQUEST_ERR", null));
 536     }
 537 
 538     //
 539     // NodeList methods
 540     //
 541 
 542     /**
 543      * NodeList method: Count the immediate children of this node
 544      * <P>
 545      * By default we do not have any children, ParentNode overrides this.
 546      * @see ParentNode
 547      *
 548      * @return int
 549      */
 550     public int getLength() {
 551         return 0;
 552     }
 553 
 554     /**
 555      * NodeList method: Return the Nth immediate child of this node, or
 556      * null if the index is out of bounds.
 557      * <P>
 558      * By default we do not have any children, ParentNode overrides this.
 559      * @see ParentNode
 560      *
 561      * @return org.w3c.dom.Node
 562      * @param Index int
 563      */
 564     public Node item(int index) {
 565         return null;
 566     }
 567 
 568     //
 569     // DOM2: methods, getters, setters
 570     //
 571 
 572     /**
 573      * Puts all <code>Text</code> nodes in the full depth of the sub-tree
 574      * underneath this <code>Node</code>, including attribute nodes, into a
 575      * "normal" form where only markup (e.g., tags, comments, processing
 576      * instructions, CDATA sections, and entity references) separates
 577      * <code>Text</code> nodes, i.e., there are no adjacent <code>Text</code>
 578      * nodes.  This can be used to ensure that the DOM view of a document is
 579      * the same as if it were saved and re-loaded, and is useful when
 580      * operations (such as XPointer lookups) that depend on a particular
 581      * document tree structure are to be used.In cases where the document
 582      * contains <code>CDATASections</code>, the normalize operation alone may
 583      * not be sufficient, since XPointers do not differentiate between
 584      * <code>Text</code> nodes and <code>CDATASection</code> nodes.
 585      * <p>
 586      * Note that this implementation simply calls normalize() on this Node's
 587      * children. It is up to implementors or Node to override normalize()
 588      * to take action.
 589      */
 590     public void normalize() {
 591         /* by default we do not have any children,
 592            ParentNode overrides this behavior */
 593     }
 594 
 595     /**
 596      * Introduced in DOM Level 2. <p>
 597      * Tests whether the DOM implementation implements a specific feature and
 598      * that feature is supported by this node.
 599      * @param feature The package name of the feature to test. This is the same
 600      * name as what can be passed to the method hasFeature on
 601      * DOMImplementation.
 602      * @param version This is the version number of the package name to
 603      * test. In Level 2, version 1, this is the string "2.0". If the version is
 604      * not specified, supporting any version of the feature will cause the
 605      * method to return true.
 606      * @return boolean Returns true if this node defines a subtree within which
 607      * the specified feature is supported, false otherwise.
 608      * @since WD-DOM-Level-2-19990923
 609      */
 610     public boolean isSupported(String feature, String version)
 611     {
 612         return ownerDocument().getImplementation().hasFeature(feature,
 613                                                               version);
 614     }
 615 
 616     /**
 617      * Introduced in DOM Level 2. <p>
 618      *
 619      * The namespace URI of this node, or null if it is unspecified. When this
 620      * node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE, this is
 621      * always null and setting it has no effect. <p>
 622      *
 623      * This is not a computed value that is the result of a namespace lookup
 624      * based on an examination of the namespace declarations in scope. It is
 625      * merely the namespace URI given at creation time.<p>
 626      *
 627      * For nodes created with a DOM Level 1 method, such as createElement
 628      * from the Document interface, this is null.
 629      * @since WD-DOM-Level-2-19990923
 630      * @see AttrNSImpl
 631      * @see ElementNSImpl
 632      */
 633     public String getNamespaceURI()
 634     {
 635         return null;
 636     }
 637 
 638     /**
 639      * Introduced in DOM Level 2. <p>
 640      *
 641      * The namespace prefix of this node, or null if it is unspecified. When
 642      * this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE this
 643      * is always null and setting it has no effect.<p>
 644      *
 645      * For nodes created with a DOM Level 1 method, such as createElement
 646      * from the Document interface, this is null. <p>
 647      *
 648      * @since WD-DOM-Level-2-19990923
 649      * @see AttrNSImpl
 650      * @see ElementNSImpl
 651      */
 652     public String getPrefix()
 653     {
 654         return null;
 655     }
 656 
 657     /**
 658      *  Introduced in DOM Level 2. <p>
 659      *
 660      *  The namespace prefix of this node, or null if it is unspecified. When
 661      *  this node is of any type other than ELEMENT_NODE and ATTRIBUTE_NODE
 662      *  this is always null and setting it has no effect.<p>
 663      *
 664      *  For nodes created with a DOM Level 1 method, such as createElement from
 665      *  the Document interface, this is null.<p>
 666      *
 667      *  Note that setting this attribute changes the nodeName attribute, which
 668      *  holds the qualified name, as well as the tagName and name attributes of
 669      *  the Element and Attr interfaces, when applicable.<p>
 670      *
 671      * @throws INVALID_CHARACTER_ERR Raised if the specified
 672      *  prefix contains an invalid character.
 673      *
 674      * @since WD-DOM-Level-2-19990923
 675      * @see AttrNSImpl
 676      * @see ElementNSImpl
 677      */
 678     public void setPrefix(String prefix)
 679         throws DOMException
 680     {
 681         throw new DOMException(DOMException.NAMESPACE_ERR,
 682               DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
 683                  "NAMESPACE_ERR", null));
 684     }
 685 
 686     /**
 687      * Introduced in DOM Level 2. <p>
 688      *
 689      * Returns the local part of the qualified name of this node.
 690      * For nodes created with a DOM Level 1 method, such as createElement
 691      * from the Document interface, and for nodes of any type other than
 692      * ELEMENT_NODE and ATTRIBUTE_NODE this is the same as the nodeName
 693      * attribute.
 694      * @since WD-DOM-Level-2-19990923
 695      * @see AttrNSImpl
 696      * @see ElementNSImpl
 697      */
 698     public String             getLocalName()
 699     {
 700         return null;
 701     }
 702 
 703     //
 704     // EventTarget support
 705     //
 706 
 707     public void addEventListener(String type, EventListener listener,
 708                                  boolean useCapture) {
 709         // simply forward to Document
 710         ownerDocument().addEventListener(this, type, listener, useCapture);
 711     }
 712 
 713     public void removeEventListener(String type, EventListener listener,
 714                                     boolean useCapture) {
 715         // simply forward to Document
 716         ownerDocument().removeEventListener(this, type, listener, useCapture);
 717     }
 718 
 719     public boolean dispatchEvent(Event event) {
 720         // simply forward to Document
 721         return ownerDocument().dispatchEvent(this, event);
 722     }
 723 
 724     //
 725     // Public DOM Level 3 methods
 726     //
 727 
 728     /**
 729      * The absolute base URI of this node or <code>null</code> if undefined.
 730      * This value is computed according to . However, when the
 731      * <code>Document</code> supports the feature "HTML" , the base URI is
 732      * computed using first the value of the href attribute of the HTML BASE
 733      * element if any, and the value of the <code>documentURI</code>
 734      * attribute from the <code>Document</code> interface otherwise.
 735      * <br> When the node is an <code>Element</code>, a <code>Document</code>
 736      * or a a <code>ProcessingInstruction</code>, this attribute represents
 737      * the properties [base URI] defined in . When the node is a
 738      * <code>Notation</code>, an <code>Entity</code>, or an
 739      * <code>EntityReference</code>, this attribute represents the
 740      * properties [declaration base URI] in the . How will this be affected
 741      * by resolution of relative namespace URIs issue?It's not.Should this
 742      * only be on Document, Element, ProcessingInstruction, Entity, and
 743      * Notation nodes, according to the infoset? If not, what is it equal to
 744      * on other nodes? Null? An empty string? I think it should be the
 745      * parent's.No.Should this be read-only and computed or and actual
 746      * read-write attribute?Read-only and computed (F2F 19 Jun 2000 and
 747      * teleconference 30 May 2001).If the base HTML element is not yet
 748      * attached to a document, does the insert change the Document.baseURI?
 749      * Yes. (F2F 26 Sep 2001)
 750      * @since DOM Level 3
 751      */
 752     public String getBaseURI() {
 753         return null;
 754     }
 755 
 756     /**
 757      * Compares a node with this node with regard to their position in the
 758      * tree and according to the document order. This order can be extended
 759      * by module that define additional types of nodes.
 760      * @param other The node to compare against this node.
 761      * @return Returns how the given node is positioned relatively to this
 762      *   node.
 763      * @since DOM Level 3
 764      * @deprecated
 765      */
 766     @Deprecated
 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 Map<String, ParentNode.UserDataRecord> 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      * List or Map, 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