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