View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 1999-2002,2004,2005 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *      http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package com.sun.org.apache.xerces.internal.dom;
22  
23  import java.lang.reflect.Constructor;
24  import java.util.Enumeration;
25  import java.util.Hashtable;
26  import com.sun.org.apache.xerces.internal.util.URI;
27  import com.sun.org.apache.xerces.internal.impl.Constants;
28  
29  import org.w3c.dom.DOMConfiguration;
30  import org.w3c.dom.UserDataHandler;
31  import com.sun.org.apache.xerces.internal.util.XMLChar;
32  import com.sun.org.apache.xerces.internal.util.XML11Char;
33  import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
34  import com.sun.org.apache.xerces.internal.utils.ObjectFactory;
35  import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
36  import org.w3c.dom.Attr;
37  import org.w3c.dom.CDATASection;
38  import org.w3c.dom.Comment;
39  import org.w3c.dom.DOMException;
40  import org.w3c.dom.DOMImplementation;
41  import org.w3c.dom.Document;
42  import org.w3c.dom.DocumentFragment;
43  import org.w3c.dom.DocumentType;
44  import org.w3c.dom.Element;
45  import org.w3c.dom.Entity;
46  import org.w3c.dom.EntityReference;
47  import org.w3c.dom.NamedNodeMap;
48  import org.w3c.dom.Node;
49  import org.w3c.dom.NodeList;
50  import org.w3c.dom.Notation;
51  import org.w3c.dom.ProcessingInstruction;
52  import org.w3c.dom.Text;
53  import org.w3c.dom.events.Event;
54  import org.w3c.dom.events.EventListener;
55  import org.w3c.dom.ls.DOMImplementationLS;
56  import org.w3c.dom.ls.LSSerializer;
57  
58  /**
59   * The Document interface represents the entire HTML or XML document.
60   * Conceptually, it is the root of the document tree, and provides the
61   * primary access to the document's data.
62   * <P>
63   * Since elements, text nodes, comments, processing instructions,
64   * etc. cannot exist outside the context of a Document, the Document
65   * interface also contains the factory methods needed to create these
66   * objects. The Node objects created have a ownerDocument attribute
67   * which associates them with the Document within whose context they
68   * were created.
69   * <p>
70   * The CoreDocumentImpl class only implements the DOM Core. Additional modules
71   * are supported by the more complete DocumentImpl subclass.
72   * <p>
73   * <b>Note:</b> When any node in the document is serialized, the
74   * entire document is serialized along with it.
75   *
76   * @xerces.internal
77   *
78   * @author Arnaud  Le Hors, IBM
79   * @author Joe Kesselman, IBM
80   * @author Andy Clark, IBM
81   * @author Ralf Pfeiffer, IBM
82   * @version $Id: CoreDocumentImpl.java,v 1.9 2010-11-01 04:39:37 joehw Exp $
83   * @since  PR-DOM-Level-1-19980818.
84   */
85  
86  
87  public class CoreDocumentImpl
88  extends ParentNode implements Document  {
89  
90          /**TODO::
91           * 1. Change XML11Char method names similar to XMLChar. That will prevent lot
92           * of dirty version checking code.
93           *
94           * 2. IMO during cloneNode qname/isXMLName check should not be made.
95           */
96      //
97      // Constants
98      //
99  
100     /** Serialization version. */
101     static final long serialVersionUID = 0;
102 
103     //
104     // Data
105     //
106 
107     // document information
108 
109     /** Document type. */
110     protected DocumentTypeImpl docType;
111 
112     /** Document element. */
113     protected ElementImpl docElement;
114 
115     /** NodeListCache free list */
116     transient NodeListCache fFreeNLCache;
117 
118     /**Experimental DOM Level 3 feature: Document encoding */
119     protected String encoding;
120 
121     /**Experimental DOM Level 3 feature: Document actualEncoding */
122     protected String actualEncoding;
123 
124     /**Experimental DOM Level 3 feature: Document version */
125     protected String version;
126 
127     /**Experimental DOM Level 3 feature: Document standalone */
128     protected boolean standalone;
129 
130     /**Experimental DOM Level 3 feature: documentURI */
131     protected String fDocumentURI;
132 
133         //Revisit :: change to a better data structure.
134     /** Table for user data attached to this document nodes. */
135     protected Hashtable userData;
136 
137 
138     /** Identifiers. */
139     protected Hashtable identifiers;
140 
141     // DOM Level 3: normalizeDocument
142     transient DOMNormalizer domNormalizer = null;
143     transient DOMConfigurationImpl fConfiguration = null;
144 
145     // support of XPath API
146     transient Object fXPathEvaluator = null;
147 
148     /** Table for quick check of child insertion. */
149     private final static int[] kidOK;
150 
151     /**
152      * Number of alterations made to this document since its creation.
153      * Serves as a "dirty bit" so that live objects such as NodeList can
154      * recognize when an alteration has been made and discard its cached
155      * state information.
156      * <p>
157      * Any method that alters the tree structure MUST cause or be
158      * accompanied by a call to changed(), to inform it that any outstanding
159      * NodeLists may have to be updated.
160      * <p>
161      * (Required because NodeList is simultaneously "live" and integer-
162      * indexed -- a bad decision in the DOM's design.)
163      * <p>
164      * Note that changes which do not affect the tree's structure -- changing
165      * the node's name, for example -- do _not_ have to call changed().
166      * <p>
167      * Alternative implementation would be to use a cryptographic
168      * Digest value rather than a count. This would have the advantage that
169      * "harmless" changes (those producing equal() trees) would not force
170      * NodeList to resynchronize. Disadvantage is that it's slightly more prone
171      * to "false negatives", though that's the difference between "wildly
172      * unlikely" and "absurdly unlikely". IF we start maintaining digests,
173      * we should consider taking advantage of them.
174      *
175      * Note: This used to be done a node basis, so that we knew what
176      * subtree changed. But since only DeepNodeList really use this today,
177      * the gain appears to be really small compared to the cost of having
178      * an int on every (parent) node plus having to walk up the tree all the
179      * way to the root to mark the branch as changed everytime a node is
180      * changed.
181      * So we now have a single counter global to the document. It means that
182      * some objects may flush their cache more often than necessary, but this
183      * makes nodes smaller and only the document needs to be marked as changed.
184      */
185     protected int changes = 0;
186 
187     // experimental
188 
189     /** Allow grammar access. */
190     protected boolean allowGrammarAccess;
191 
192     /** Bypass error checking. */
193     protected boolean errorChecking = true;
194     /** Ancestor checking */
195     protected boolean ancestorChecking = true;
196 
197     //Did version change at any point when the document was created ?
198     //this field helps us to optimize when normalizingDocument.
199     protected boolean xmlVersionChanged = false ;
200 
201     /** The following are required for compareDocumentPosition
202      */
203     // Document number.   Documents are ordered across the implementation using
204     // positive integer values.  Documents are assigned numbers on demand.
205     private int documentNumber=0;
206     // Node counter and table.  Used to assign numbers to nodes for this
207     // document.  Node number values are negative integers.  Nodes are
208     // assigned numbers on demand.
209     private int nodeCounter = 0;
210     private Hashtable nodeTable;
211     private boolean xml11Version = false; //by default 1.0
212     //
213     // Static initialization
214     //
215 
216     static {
217 
218         kidOK = new int[13];
219 
220         kidOK[DOCUMENT_NODE] =
221         1 << ELEMENT_NODE | 1 << PROCESSING_INSTRUCTION_NODE |
222         1 << COMMENT_NODE | 1 << DOCUMENT_TYPE_NODE;
223 
224         kidOK[DOCUMENT_FRAGMENT_NODE] =
225         kidOK[ENTITY_NODE] =
226         kidOK[ENTITY_REFERENCE_NODE] =
227         kidOK[ELEMENT_NODE] =
228         1 << ELEMENT_NODE | 1 << PROCESSING_INSTRUCTION_NODE |
229         1 << COMMENT_NODE | 1 << TEXT_NODE |
230         1 << CDATA_SECTION_NODE | 1 << ENTITY_REFERENCE_NODE ;
231 
232 
233         kidOK[ATTRIBUTE_NODE] =
234         1 << TEXT_NODE | 1 << ENTITY_REFERENCE_NODE;
235 
236         kidOK[DOCUMENT_TYPE_NODE] =
237         kidOK[PROCESSING_INSTRUCTION_NODE] =
238         kidOK[COMMENT_NODE] =
239         kidOK[TEXT_NODE] =
240         kidOK[CDATA_SECTION_NODE] =
241         kidOK[NOTATION_NODE] =
242         0;
243 
244     } // static
245 
246     //
247     // Constructors
248     //
249 
250     /**
251      * NON-DOM: Actually creating a Document is outside the DOM's spec,
252      * since it has to operate in terms of a particular implementation.
253      */
254     public CoreDocumentImpl() {
255         this(false);
256     }
257 
258     /** Constructor. */
259     public CoreDocumentImpl(boolean grammarAccess) {
260         super(null);
261         ownerDocument = this;
262         allowGrammarAccess = grammarAccess;
263         String systemProp = SecuritySupport.getSystemProperty(Constants.SUN_DOM_PROPERTY_PREFIX+Constants.SUN_DOM_ANCESTOR_CHECCK);
264         if (systemProp != null) {
265             if (systemProp.equalsIgnoreCase("false")) {
266                 ancestorChecking = false;
267             }
268         }
269     }
270 
271     /**
272      * For DOM2 support.
273      * The createDocument factory method is in DOMImplementation.
274      */
275     public CoreDocumentImpl(DocumentType doctype) {
276         this(doctype, false);
277     }
278 
279     /** For DOM2 support. */
280     public CoreDocumentImpl(DocumentType doctype, boolean grammarAccess) {
281         this(grammarAccess);
282         if (doctype != null) {
283             DocumentTypeImpl doctypeImpl;
284             try {
285                 doctypeImpl = (DocumentTypeImpl) doctype;
286             } catch (ClassCastException e) {
287                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
288                 throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
289             }
290             doctypeImpl.ownerDocument = this;
291             appendChild(doctype);
292         }
293     }
294 
295     //
296     // Node methods
297     //
298 
299     // even though ownerDocument refers to this in this implementation
300     // the DOM Level 2 spec says it must be null, so make it appear so
301     final public Document getOwnerDocument() {
302         return null;
303     }
304 
305     /** Returns the node type. */
306     public short getNodeType() {
307         return Node.DOCUMENT_NODE;
308     }
309 
310     /** Returns the node name. */
311     public String getNodeName() {
312         return "#document";
313     }
314 
315     /**
316      * Deep-clone a document, including fixing ownerDoc for the cloned
317      * children. Note that this requires bypassing the WRONG_DOCUMENT_ERR
318      * protection. I've chosen to implement it by calling importNode
319      * which is DOM Level 2.
320      *
321      * @return org.w3c.dom.Node
322      * @param deep boolean, iff true replicate children
323      */
324     public Node cloneNode(boolean deep) {
325 
326         CoreDocumentImpl newdoc = new CoreDocumentImpl();
327         callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED);
328         cloneNode(newdoc, deep);
329 
330         return newdoc;
331 
332     } // cloneNode(boolean):Node
333 
334 
335     /**
336      * internal method to share code with subclass
337      **/
338     protected void cloneNode(CoreDocumentImpl newdoc, boolean deep) {
339 
340         // clone the children by importing them
341         if (needsSyncChildren()) {
342             synchronizeChildren();
343         }
344 
345         if (deep) {
346             Hashtable reversedIdentifiers = null;
347 
348             if (identifiers != null) {
349                 // Build a reverse mapping from element to identifier.
350                 reversedIdentifiers = new Hashtable();
351                 Enumeration elementIds = identifiers.keys();
352                 while (elementIds.hasMoreElements()) {
353                     Object elementId = elementIds.nextElement();
354                     reversedIdentifiers.put(identifiers.get(elementId),
355                     elementId);
356                 }
357             }
358 
359             // Copy children into new document.
360             for (ChildNode kid = firstChild; kid != null;
361             kid = kid.nextSibling) {
362                 newdoc.appendChild(newdoc.importNode(kid, true, true,
363                 reversedIdentifiers));
364             }
365         }
366 
367         // experimental
368         newdoc.allowGrammarAccess = allowGrammarAccess;
369         newdoc.errorChecking = errorChecking;
370 
371     } // cloneNode(CoreDocumentImpl,boolean):void
372 
373     /**
374      * Since a Document may contain at most one top-level Element child,
375      * and at most one DocumentType declaraction, we need to subclass our
376      * add-children methods to implement this constraint.
377      * Since appendChild() is implemented as insertBefore(,null),
378      * altering the latter fixes both.
379      * <p>
380      * While I'm doing so, I've taken advantage of the opportunity to
381      * cache documentElement and docType so we don't have to
382      * search for them.
383      *
384      * REVISIT: According to the spec it is not allowed to alter neither the
385      * document element nor the document type in any way
386      */
387     public Node insertBefore(Node newChild, Node refChild)
388     throws DOMException {
389 
390         // Only one such child permitted
391         int type = newChild.getNodeType();
392         if (errorChecking) {
393             if((type == Node.ELEMENT_NODE && docElement != null) ||
394             (type == Node.DOCUMENT_TYPE_NODE && docType != null)) {
395                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
396                 throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, msg);
397             }
398         }
399         // Adopt orphan doctypes
400         if (newChild.getOwnerDocument() == null &&
401         newChild instanceof DocumentTypeImpl) {
402             ((DocumentTypeImpl) newChild).ownerDocument = this;
403         }
404         super.insertBefore(newChild,refChild);
405 
406         // If insert succeeded, cache the kid appropriately
407         if (type == Node.ELEMENT_NODE) {
408             docElement = (ElementImpl)newChild;
409         }
410         else if (type == Node.DOCUMENT_TYPE_NODE) {
411             docType = (DocumentTypeImpl)newChild;
412         }
413 
414         return newChild;
415 
416     } // insertBefore(Node,Node):Node
417 
418     /**
419      * Since insertBefore caches the docElement (and, currently, docType),
420      * removeChild has to know how to undo the cache
421      *
422      * REVISIT: According to the spec it is not allowed to alter neither the
423      * document element nor the document type in any way
424      */
425     public Node removeChild(Node oldChild) throws DOMException {
426 
427         super.removeChild(oldChild);
428 
429         // If remove succeeded, un-cache the kid appropriately
430         int type = oldChild.getNodeType();
431         if(type == Node.ELEMENT_NODE) {
432             docElement = null;
433         }
434         else if (type == Node.DOCUMENT_TYPE_NODE) {
435             docType = null;
436         }
437 
438         return oldChild;
439 
440     }   // removeChild(Node):Node
441 
442     /**
443      * Since we cache the docElement (and, currently, docType),
444      * replaceChild has to update the cache
445      *
446      * REVISIT: According to the spec it is not allowed to alter neither the
447      * document element nor the document type in any way
448      */
449     public Node replaceChild(Node newChild, Node oldChild)
450     throws DOMException {
451 
452         // Adopt orphan doctypes
453         if (newChild.getOwnerDocument() == null &&
454         newChild instanceof DocumentTypeImpl) {
455             ((DocumentTypeImpl) newChild).ownerDocument = this;
456         }
457 
458         if (errorChecking &&((docType != null &&
459             oldChild.getNodeType() != Node.DOCUMENT_TYPE_NODE &&
460             newChild.getNodeType() == Node.DOCUMENT_TYPE_NODE)
461             || (docElement != null &&
462             oldChild.getNodeType() != Node.ELEMENT_NODE &&
463             newChild.getNodeType() == Node.ELEMENT_NODE))) {
464 
465             throw new DOMException(
466                 DOMException.HIERARCHY_REQUEST_ERR,
467                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null));
468         }
469         super.replaceChild(newChild, oldChild);
470 
471         int type = oldChild.getNodeType();
472         if(type == Node.ELEMENT_NODE) {
473             docElement = (ElementImpl)newChild;
474         }
475         else if (type == Node.DOCUMENT_TYPE_NODE) {
476             docType = (DocumentTypeImpl)newChild;
477         }
478         return oldChild;
479     }   // replaceChild(Node,Node):Node
480 
481     /*
482      * Get Node text content
483      * @since DOM Level 3
484      */
485     public String getTextContent() throws DOMException {
486         return null;
487     }
488 
489     /*
490      * Set Node text content
491      * @since DOM Level 3
492      */
493     public void setTextContent(String textContent)
494     throws DOMException {
495         // no-op
496     }
497 
498     /**
499      * @since DOM Level 3
500      */
501     public Object getFeature(String feature, String version) {
502 
503         boolean anyVersion = version == null || version.length() == 0;
504 
505         // if a plus sign "+" is prepended to any feature name, implementations
506         // are considered in which the specified feature may not be directly
507         // castable DOMImplementation.getFeature(feature, version). Without a
508         // plus, only features whose interfaces are directly castable are
509         // considered.
510         if ((feature.equalsIgnoreCase("+XPath"))
511             && (anyVersion || version.equals("3.0"))) {
512 
513             // If an XPathEvaluator was created previously
514             // return it otherwise create a new one.
515             if (fXPathEvaluator != null) {
516                 return fXPathEvaluator;
517             }
518 
519             try {
520                 Class xpathClass = ObjectFactory.findProviderClass (
521                         "com.sun.org.apache.xpath.internal.domapi.XPathEvaluatorImpl", true);
522                 Constructor xpathClassConstr =
523                     xpathClass.getConstructor(new Class[] { Document.class });
524 
525                 // Check if the DOM XPath implementation implements
526                 // the interface org.w3c.dom.XPathEvaluator
527                 Class interfaces[] = xpathClass.getInterfaces();
528                 for (int i = 0; i < interfaces.length; i++) {
529                     if (interfaces[i].getName().equals(
530                     "org.w3c.dom.xpath.XPathEvaluator")) {
531                         fXPathEvaluator = xpathClassConstr.newInstance(new Object[] { this });
532                         return fXPathEvaluator;
533                     }
534                 }
535                 return null;
536             } catch (Exception e) {
537                 return null;
538             }
539         }
540         return super.getFeature(feature, version);
541     }
542 
543     //
544     // Document methods
545     //
546 
547     // factory methods
548 
549     /**
550      * Factory method; creates an Attribute having this Document as its
551      * OwnerDoc.
552      *
553      * @param name The name of the attribute. Note that the attribute's value is
554      * _not_ established at the factory; remember to set it!
555      *
556      * @throws DOMException(INVALID_NAME_ERR)
557      * if the attribute name is not acceptable.
558      */
559     public Attr createAttribute(String name)
560         throws DOMException {
561 
562         if (errorChecking && !isXMLName(name,xml11Version)) {
563             String msg =
564                 DOMMessageFormatter.formatMessage(
565                     DOMMessageFormatter.DOM_DOMAIN,
566                     "INVALID_CHARACTER_ERR",
567                     null);
568             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
569         }
570         return new AttrImpl(this, name);
571 
572     } // createAttribute(String):Attr
573 
574     /**
575      * Factory method; creates a CDATASection having this Document as
576      * its OwnerDoc.
577      *
578      * @param data The initial contents of the CDATA
579      *
580      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents. (HTML
581      * not yet implemented.)
582      */
583     public CDATASection createCDATASection(String data)
584     throws DOMException {
585         return new CDATASectionImpl(this, data);
586     }
587 
588     /**
589      * Factory method; creates a Comment having this Document as its
590      * OwnerDoc.
591      *
592      * @param data The initial contents of the Comment. */
593     public Comment createComment(String data) {
594         return new CommentImpl(this, data);
595     }
596 
597     /**
598      * Factory method; creates a DocumentFragment having this Document
599      * as its OwnerDoc.
600      */
601     public DocumentFragment createDocumentFragment() {
602         return new DocumentFragmentImpl(this);
603     }
604 
605     /**
606      * Factory method; creates an Element having this Document
607      * as its OwnerDoc.
608      *
609      * @param tagName The name of the element type to instantiate. For
610      * XML, this is case-sensitive. For HTML, the tagName parameter may
611      * be provided in any case, but it must be mapped to the canonical
612      * uppercase form by the DOM implementation.
613      *
614      * @throws DOMException(INVALID_NAME_ERR) if the tag name is not
615      * acceptable.
616      */
617     public Element createElement(String tagName)
618     throws DOMException {
619 
620         if (errorChecking && !isXMLName(tagName,xml11Version)) {
621             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
622             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
623         }
624         return new ElementImpl(this, tagName);
625 
626     } // createElement(String):Element
627 
628     /**
629      * Factory method; creates an EntityReference having this Document
630      * as its OwnerDoc.
631      *
632      * @param name The name of the Entity we wish to refer to
633      *
634      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
635      * nonstandard entities are not permitted. (HTML not yet
636      * implemented.)
637      */
638     public EntityReference createEntityReference(String name)
639     throws DOMException {
640 
641         if (errorChecking && !isXMLName(name,xml11Version)) {
642             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
643             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
644         }
645         return new EntityReferenceImpl(this, name);
646 
647     } // createEntityReference(String):EntityReference
648 
649     /**
650      * Factory method; creates a ProcessingInstruction having this Document
651      * as its OwnerDoc.
652      *
653      * @param target The target "processor channel"
654      * @param data Parameter string to be passed to the target.
655      *
656      * @throws DOMException(INVALID_NAME_ERR) if the target name is not
657      * acceptable.
658      *
659      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents. (HTML
660      * not yet implemented.)
661      */
662     public ProcessingInstruction createProcessingInstruction(String target,
663     String data)
664     throws DOMException {
665 
666         if (errorChecking && !isXMLName(target,xml11Version)) {
667             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
668             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
669         }
670         return new ProcessingInstructionImpl(this, target, data);
671 
672     } // createProcessingInstruction(String,String):ProcessingInstruction
673 
674     /**
675      * Factory method; creates a Text node having this Document as its
676      * OwnerDoc.
677      *
678      * @param data The initial contents of the Text.
679      */
680     public Text createTextNode(String data) {
681         return new TextImpl(this, data);
682     }
683 
684     // other document methods
685 
686     /**
687      * For XML, this provides access to the Document Type Definition.
688      * For HTML documents, and XML documents which don't specify a DTD,
689      * it will be null.
690      */
691     public DocumentType getDoctype() {
692         if (needsSyncChildren()) {
693             synchronizeChildren();
694         }
695         return docType;
696     }
697 
698 
699     /**
700      * Convenience method, allowing direct access to the child node
701      * which is considered the root of the actual document content. For
702      * HTML, where it is legal to have more than one Element at the top
703      * level of the document, we pick the one with the tagName
704      * "HTML". For XML there should be only one top-level
705      *
706      * (HTML not yet supported.)
707      */
708     public Element getDocumentElement() {
709         if (needsSyncChildren()) {
710             synchronizeChildren();
711         }
712         return docElement;
713     }
714 
715     /**
716      * Return a <em>live</em> collection of all descendent Elements (not just
717      * immediate children) having the specified tag name.
718      *
719      * @param tagname The type of Element we want to gather. "*" will be
720      * taken as a wildcard, meaning "all elements in the document."
721      *
722      * @see DeepNodeListImpl
723      */
724     public NodeList getElementsByTagName(String tagname) {
725         return new DeepNodeListImpl(this,tagname);
726     }
727 
728     /**
729      * Retrieve information describing the abilities of this particular
730      * DOM implementation. Intended to support applications that may be
731      * using DOMs retrieved from several different sources, potentially
732      * with different underlying representations.
733      */
734     public DOMImplementation getImplementation() {
735         // Currently implemented as a singleton, since it's hardcoded
736         // information anyway.
737         return CoreDOMImplementationImpl.getDOMImplementation();
738     }
739 
740     //
741     // Public methods
742     //
743 
744     // properties
745 
746     /**
747      * Sets whether the DOM implementation performs error checking
748      * upon operations. Turning off error checking only affects
749      * the following DOM checks:
750      * <ul>
751      * <li>Checking strings to make sure that all characters are
752      *     legal XML characters
753      * <li>Hierarchy checking such as allowed children, checks for
754      *     cycles, etc.
755      * </ul>
756      * <p>
757      * Turning off error checking does <em>not</em> turn off the
758      * following checks:
759      * <ul>
760      * <li>Read only checks
761      * <li>Checks related to DOM events
762      * </ul>
763      */
764 
765     public void setErrorChecking(boolean check) {
766         errorChecking = check;
767     }
768 
769     /*
770      * DOM Level 3 WD - Experimental.
771      */
772     public void setStrictErrorChecking(boolean check) {
773         errorChecking = check;
774     }
775 
776     /**
777      * Returns true if the DOM implementation performs error checking.
778      */
779     public boolean getErrorChecking() {
780         return errorChecking;
781     }
782 
783     /*
784      * DOM Level 3 WD - Experimental.
785      */
786     public boolean getStrictErrorChecking() {
787         return errorChecking;
788     }
789 
790 
791     /**
792      * DOM Level 3 CR - Experimental. (Was getActualEncoding)
793      *
794      * An attribute specifying the encoding used for this document
795      * at the time of the parsing. This is <code>null</code> when
796      * it is not known, such as when the <code>Document</code> was
797      * created in memory.
798      * @since DOM Level 3
799      */
800     public String getInputEncoding() {
801         return actualEncoding;
802     }
803 
804     /**
805      * DOM Internal
806      * (Was a DOM L3 Core WD public interface method setActualEncoding )
807      *
808      * An attribute specifying the actual encoding of this document. This is
809      * <code>null</code> otherwise.
810      * <br> This attribute represents the property [character encoding scheme]
811      * defined in .
812      */
813     public void setInputEncoding(String value) {
814         actualEncoding = value;
815     }
816 
817     /**
818      * DOM Internal
819      * (Was a DOM L3 Core WD public interface method setXMLEncoding )
820      *
821      * An attribute specifying, as part of the XML declaration,
822      * the encoding of this document. This is null when unspecified.
823      */
824     public void setXmlEncoding(String value) {
825         encoding = value;
826     }
827 
828     /**
829      * @deprecated This method is internal and only exists for
830      * compatibility with older applications. New applications
831      * should never call this method.
832      */
833     public void setEncoding(String value) {
834         setXmlEncoding(value);
835     }
836 
837     /**
838      * DOM Level 3 WD - Experimental.
839      * The encoding of this document (part of XML Declaration)
840      */
841     public String getXmlEncoding() {
842         return encoding;
843     }
844 
845     /**
846      * @deprecated This method is internal and only exists for
847      * compatibility with older applications. New applications
848      * should never call this method.
849      */
850     public String getEncoding() {
851         return getXmlEncoding();
852     }
853 
854     /**
855      * DOM Level 3 CR - Experimental.
856      * version - An attribute specifying, as part of the XML declaration,
857      * the version number of this document.
858      */
859     public void setXmlVersion(String value) {
860         if(value.equals("1.0") || value.equals("1.1")){
861             //we need to change the flag value only --
862             // when the version set is different than already set.
863             if(!getXmlVersion().equals(value)){
864                 xmlVersionChanged = true ;
865                 //change the normalization value back to false
866                 isNormalized(false);
867                 version = value;
868             }
869         }
870         else{
871             //NOT_SUPPORTED_ERR: Raised if the vesion is set to a value that is not supported by
872             //this document
873             //we dont support any other XML version
874             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
875             throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
876 
877         }
878         if((getXmlVersion()).equals("1.1")){
879             xml11Version = true;
880         }
881         else{
882             xml11Version = false;
883         }
884     }
885 
886     /**
887      * @deprecated This method is internal and only exists for
888      * compatibility with older applications. New applications
889      * should never call this method.
890      */
891     public void setVersion(String value) {
892         setXmlVersion(value);
893     }
894 
895     /**
896      * DOM Level 3 WD - Experimental.
897      * The version of this document (part of XML Declaration)
898      */
899 
900     public String getXmlVersion() {
901         return (version == null)?"1.0":version;
902     }
903 
904     /**
905      * @deprecated This method is internal and only exists for
906      * compatibility with older applications. New applications
907      * should never call this method.
908      */
909     public String getVersion() {
910         return getXmlVersion();
911     }
912 
913     /**
914      * DOM Level 3 CR - Experimental.
915      *
916      * Xmlstandalone - An attribute specifying, as part of the XML declaration,
917      * whether this document is standalone
918      * @exception DOMException
919      *    NOT_SUPPORTED_ERR: Raised if this document does not support the
920      *   "XML" feature.
921      * @since DOM Level 3
922      */
923     public void setXmlStandalone(boolean value)
924                                   throws DOMException {
925             standalone = value;
926     }
927 
928     /**
929      * @deprecated This method is internal and only exists for
930      * compatibility with older applications. New applications
931      * should never call this method.
932      */
933     public void setStandalone(boolean value) {
934         setXmlStandalone(value);
935     }
936 
937     /**
938      * DOM Level 3 WD - Experimental.
939      * standalone that specifies whether this document is standalone
940      * (part of XML Declaration)
941      */
942     public boolean getXmlStandalone() {
943         return standalone;
944     }
945 
946     /**
947      * @deprecated This method is internal and only exists for
948      * compatibility with older applications. New applications
949      * should never call this method.
950      */
951     public boolean getStandalone() {
952         return getXmlStandalone();
953     }
954 
955     /**
956      * DOM Level 3 WD - Experimental.
957      * The location of the document or <code>null</code> if undefined.
958      * <br>Beware that when the <code>Document</code> supports the feature
959      * "HTML" , the href attribute of the HTML BASE element takes precedence
960      * over this attribute.
961      * @since DOM Level 3
962      */
963     public String getDocumentURI(){
964         return fDocumentURI;
965     }
966 
967 
968     /**
969      * DOM Level 3 WD - Experimental.
970      * Renaming node
971      */
972     public Node renameNode(Node n,String namespaceURI,String name)
973     throws DOMException{
974 
975         if (errorChecking && n.getOwnerDocument() != this && n != this) {
976             String msg = DOMMessageFormatter.formatMessage(
977                     DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
978             throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
979         }
980         switch (n.getNodeType()) {
981             case ELEMENT_NODE: {
982                 ElementImpl el = (ElementImpl) n;
983                 if (el instanceof ElementNSImpl) {
984                     ((ElementNSImpl) el).rename(namespaceURI, name);
985 
986                     // fire user data NODE_RENAMED event
987                     callUserDataHandlers(el, null, UserDataHandler.NODE_RENAMED);
988                 }
989                 else {
990                     if (namespaceURI == null) {
991                         if (errorChecking) {
992                             int colon1 = name.indexOf(':');
993                             if(colon1 != -1){
994                                 String msg =
995                                     DOMMessageFormatter.formatMessage(
996                                             DOMMessageFormatter.DOM_DOMAIN,
997                                             "NAMESPACE_ERR",
998                                             null);
999                                 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
1000                             }
1001                             if (!isXMLName(name,xml11Version)) {
1002                                 String msg = DOMMessageFormatter.formatMessage(
1003                                         DOMMessageFormatter.DOM_DOMAIN,
1004                                         "INVALID_CHARACTER_ERR", null);
1005                                 throw new DOMException(DOMException.INVALID_CHARACTER_ERR,
1006                                         msg);
1007                             }
1008                         }
1009                         el.rename(name);
1010 
1011                         // fire user data NODE_RENAMED event
1012                         callUserDataHandlers(el, null,
1013                                 UserDataHandler.NODE_RENAMED);
1014                     }
1015                     else {
1016                         // we need to create a new object
1017                         ElementNSImpl nel =
1018                             new ElementNSImpl(this, namespaceURI, name);
1019 
1020                         // register event listeners on new node
1021                         copyEventListeners(el, nel);
1022 
1023                         // remove user data from old node
1024                         Hashtable data = removeUserDataTable(el);
1025 
1026                         // remove old node from parent if any
1027                         Node parent = el.getParentNode();
1028                         Node nextSib = el.getNextSibling();
1029                         if (parent != null) {
1030                             parent.removeChild(el);
1031                         }
1032                         // move children to new node
1033                         Node child = el.getFirstChild();
1034                         while (child != null) {
1035                             el.removeChild(child);
1036                             nel.appendChild(child);
1037                             child = el.getFirstChild();
1038                         }
1039                         // move specified attributes to new node
1040                         nel.moveSpecifiedAttributes(el);
1041 
1042                         // attach user data to new node
1043                         setUserDataTable(nel, data);
1044 
1045                         // and fire user data NODE_RENAMED event
1046                         callUserDataHandlers(el, nel,
1047                                 UserDataHandler.NODE_RENAMED);
1048 
1049                         // insert new node where old one was
1050                         if (parent != null) {
1051                             parent.insertBefore(nel, nextSib);
1052                         }
1053                         el = nel;
1054                     }
1055                 }
1056                 // fire ElementNameChanged event
1057                 renamedElement((Element) n, el);
1058                 return el;
1059             }
1060             case ATTRIBUTE_NODE: {
1061                 AttrImpl at = (AttrImpl) n;
1062 
1063                 // dettach attr from element
1064                 Element el = at.getOwnerElement();
1065                 if (el != null) {
1066                     el.removeAttributeNode(at);
1067                 }
1068                 if (n instanceof AttrNSImpl) {
1069                     ((AttrNSImpl) at).rename(namespaceURI, name);
1070                     // reattach attr to element
1071                     if (el != null) {
1072                         el.setAttributeNodeNS(at);
1073                     }
1074 
1075                     // fire user data NODE_RENAMED event
1076                     callUserDataHandlers(at, null, UserDataHandler.NODE_RENAMED);
1077                 }
1078                 else {
1079                     if (namespaceURI == null) {
1080                         at.rename(name);
1081                         // reattach attr to element
1082                         if (el != null) {
1083                             el.setAttributeNode(at);
1084                         }
1085 
1086                         // fire user data NODE_RENAMED event
1087                         callUserDataHandlers(at, null, UserDataHandler.NODE_RENAMED);
1088                     }
1089                     else {
1090                         // we need to create a new object
1091                         AttrNSImpl nat = new AttrNSImpl(this, namespaceURI, name);
1092 
1093                         // register event listeners on new node
1094                         copyEventListeners(at, nat);
1095 
1096                         // remove user data from old node
1097                         Hashtable data = removeUserDataTable(at);
1098 
1099                         // move children to new node
1100                         Node child = at.getFirstChild();
1101                         while (child != null) {
1102                             at.removeChild(child);
1103                             nat.appendChild(child);
1104                             child = at.getFirstChild();
1105                         }
1106 
1107                         // attach user data to new node
1108                         setUserDataTable(nat, data);
1109 
1110                         // and fire user data NODE_RENAMED event
1111                         callUserDataHandlers(at, nat, UserDataHandler.NODE_RENAMED);
1112 
1113                         // reattach attr to element
1114                         if (el != null) {
1115                             el.setAttributeNode(nat);
1116                         }
1117                         at = nat;
1118                     }
1119                 }
1120                 // fire AttributeNameChanged event
1121                 renamedAttrNode((Attr) n, at);
1122 
1123                 return at;
1124             }
1125             default: {
1126                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1127                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1128             }
1129         }
1130 
1131     }
1132 
1133 
1134     /**
1135      *  DOM Level 3 WD - Experimental
1136      *  Normalize document.
1137      */
1138     public void normalizeDocument(){
1139         // No need to normalize if already normalized.
1140         if (isNormalized() && !isNormalizeDocRequired()) {
1141             return;
1142         }
1143         if (needsSyncChildren()) {
1144             synchronizeChildren();
1145         }
1146 
1147         if (domNormalizer == null) {
1148             domNormalizer = new DOMNormalizer();
1149         }
1150 
1151         if (fConfiguration == null) {
1152             fConfiguration =  new DOMConfigurationImpl();
1153         }
1154         else {
1155             fConfiguration.reset();
1156         }
1157 
1158         domNormalizer.normalizeDocument(this, fConfiguration);
1159         isNormalized(true);
1160         //set the XMLversion changed value to false -- once we have finished
1161         //doing normalization
1162         xmlVersionChanged = false ;
1163     }
1164 
1165 
1166     /**
1167      * DOM Level 3 CR - Experimental
1168      *
1169      *  The configuration used when <code>Document.normalizeDocument</code> is
1170      * invoked.
1171      * @since DOM Level 3
1172      */
1173     public DOMConfiguration getDomConfig(){
1174         if (fConfiguration == null) {
1175             fConfiguration = new DOMConfigurationImpl();
1176         }
1177         return fConfiguration;
1178     }
1179 
1180 
1181     /**
1182      * Returns the absolute base URI of this node or null if the implementation
1183      * wasn't able to obtain an absolute URI. Note: If the URI is malformed, a
1184      * null is returned.
1185      *
1186      * @return The absolute base URI of this node or null.
1187      * @since DOM Level 3
1188      */
1189     public String getBaseURI() {
1190         if (fDocumentURI != null && fDocumentURI.length() != 0 ) {// attribute value is always empty string
1191             try {
1192                 return new URI(fDocumentURI).toString();
1193             }
1194             catch (com.sun.org.apache.xerces.internal.util.URI.MalformedURIException e){
1195                 // REVISIT: what should happen in this case?
1196                 return null;
1197             }
1198         }
1199         return fDocumentURI;
1200     }
1201 
1202     /**
1203      * DOM Level 3 WD - Experimental.
1204      */
1205     public void setDocumentURI(String documentURI){
1206         fDocumentURI = documentURI;
1207     }
1208 
1209 
1210     //
1211     // DOM L3 LS
1212     //
1213     /**
1214      * DOM Level 3 WD - Experimental.
1215      * Indicates whether the method load should be synchronous or
1216      * asynchronous. When the async attribute is set to <code>true</code>
1217      * the load method returns control to the caller before the document has
1218      * completed loading. The default value of this property is
1219      * <code>false</code>.
1220      * <br>Setting the value of this attribute might throw NOT_SUPPORTED_ERR
1221      * if the implementation doesn't support the mode the attribute is being
1222      * set to. Should the DOM spec define the default value of this
1223      * property? What if implementing both async and sync IO is impractical
1224      * in some systems?  2001-09-14. default is <code>false</code> but we
1225      * need to check with Mozilla and IE.
1226      */
1227     public boolean getAsync() {
1228         return false;
1229     }
1230 
1231     /**
1232      * DOM Level 3 WD - Experimental.
1233      * Indicates whether the method load should be synchronous or
1234      * asynchronous. When the async attribute is set to <code>true</code>
1235      * the load method returns control to the caller before the document has
1236      * completed loading. The default value of this property is
1237      * <code>false</code>.
1238      * <br>Setting the value of this attribute might throw NOT_SUPPORTED_ERR
1239      * if the implementation doesn't support the mode the attribute is being
1240      * set to. Should the DOM spec define the default value of this
1241      * property? What if implementing both async and sync IO is impractical
1242      * in some systems?  2001-09-14. default is <code>false</code> but we
1243      * need to check with Mozilla and IE.
1244      */
1245     public void setAsync(boolean async) {
1246         if (async) {
1247             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1248             throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1249         }
1250     }
1251     /**
1252      * DOM Level 3 WD - Experimental.
1253      * If the document is currently being loaded as a result of the method
1254      * <code>load</code> being invoked the loading and parsing is
1255      * immediately aborted. The possibly partial result of parsing the
1256      * document is discarded and the document is cleared.
1257      */
1258     public void abort() {
1259     }
1260 
1261     /**
1262      * DOM Level 3 WD - Experimental.
1263      *
1264      * Replaces the content of the document with the result of parsing the
1265      * given URI. Invoking this method will either block the caller or
1266      * return to the caller immediately depending on the value of the async
1267      * attribute. Once the document is fully loaded a "load" event (as
1268      * defined in [<a href='http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331'>DOM Level 3 Events</a>]
1269      * , except that the <code>Event.targetNode</code> will be the document,
1270      * not an element) will be dispatched on the document. If an error
1271      * occurs, an implementation dependent "error" event will be dispatched
1272      * on the document. If this method is called on a document that is
1273      * currently loading, the current load is interrupted and the new URI
1274      * load is initiated.
1275      * <br> When invoking this method the parameters used in the
1276      * <code>DOMParser</code> interface are assumed to have their default
1277      * values with the exception that the parameters <code>"entities"</code>
1278      * , <code>"normalize-characters"</code>,
1279      * <code>"check-character-normalization"</code> are set to
1280      * <code>"false"</code>.
1281      * <br> The result of a call to this method is the same the result of a
1282      * call to <code>DOMParser.parseWithContext</code> with an input stream
1283      * referencing the URI that was passed to this call, the document as the
1284      * context node, and the action <code>ACTION_REPLACE_CHILDREN</code>.
1285      * @param uri The URI reference for the XML file to be loaded. If this is
1286      *  a relative URI, the base URI used by the implementation is
1287      *  implementation dependent.
1288      * @return If async is set to <code>true</code> <code>load</code> returns
1289      *   <code>true</code> if the document load was successfully initiated.
1290      *   If an error occurred when initiating the document load,
1291      *   <code>load</code> returns <code>false</code>.If async is set to
1292      *   <code>false</code> <code>load</code> returns <code>true</code> if
1293      *   the document was successfully loaded and parsed. If an error
1294      *   occurred when either loading or parsing the URI, <code>load</code>
1295      *   returns <code>false</code>.
1296      */
1297     public boolean load(String uri) {
1298         return false;
1299     }
1300 
1301     /**
1302      * DOM Level 3 WD - Experimental.
1303      * Replace the content of the document with the result of parsing the
1304      * input string, this method is always synchronous.
1305      * @param source A string containing an XML document.
1306      * @return <code>true</code> if parsing the input string succeeded
1307      *   without errors, otherwise <code>false</code>.
1308      */
1309     public boolean loadXML(String source) {
1310         return false;
1311     }
1312 
1313     /**
1314      * DOM Level 3 WD - Experimental.
1315      * Save the document or the given node and all its descendants to a string
1316      * (i.e. serialize the document or node).
1317      * <br>The parameters used in the <code>LSSerializer</code> interface are
1318      * assumed to have their default values when invoking this method.
1319      * <br> The result of a call to this method is the same the result of a
1320      * call to <code>LSSerializer.writeToString</code> with the document as
1321      * the node to write.
1322      * @param node Specifies what to serialize, if this parameter is
1323      *   <code>null</code> the whole document is serialized, if it's
1324      *   non-null the given node is serialized.
1325      * @return The serialized document or <code>null</code> in case an error
1326      *   occurred.
1327      * @exception DOMException
1328      *   WRONG_DOCUMENT_ERR: Raised if the node passed in as the node
1329      *   parameter is from an other document.
1330      */
1331     public String saveXML(Node node)
1332     throws DOMException {
1333         if ( errorChecking && node != null &&
1334             this != node.getOwnerDocument() ) {
1335             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
1336             throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
1337         }
1338         DOMImplementationLS domImplLS = (DOMImplementationLS)DOMImplementationImpl.getDOMImplementation();
1339         LSSerializer xmlWriter = domImplLS.createLSSerializer();
1340         if (node == null) {
1341             node = this;
1342         }
1343         return xmlWriter.writeToString(node);
1344     }
1345 
1346     /**
1347      * Sets whether the DOM implementation generates mutation events
1348      * upon operations.
1349      */
1350     void setMutationEvents(boolean set) {
1351         // does nothing by default - overidden in subclass
1352     }
1353 
1354     /**
1355      * Returns true if the DOM implementation generates mutation events.
1356      */
1357     boolean getMutationEvents() {
1358         // does nothing by default - overriden in subclass
1359         return false;
1360     }
1361 
1362 
1363 
1364     // non-DOM factory methods
1365 
1366     /**
1367      * NON-DOM
1368      * Factory method; creates a DocumentType having this Document
1369      * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
1370      * DTD information unspecified.)
1371      *
1372      * @param name The name of the Entity we wish to provide a value for.
1373      *
1374      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
1375      * DTDs are not permitted. (HTML not yet implemented.)
1376      */
1377     public DocumentType createDocumentType(String qualifiedName,
1378     String publicID,
1379     String systemID)
1380     throws DOMException {
1381 
1382         return new DocumentTypeImpl(this, qualifiedName, publicID, systemID);
1383 
1384     } // createDocumentType(String):DocumentType
1385 
1386     /**
1387      * NON-DOM
1388      * Factory method; creates an Entity having this Document
1389      * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
1390      * DTD information unspecified.)
1391      *
1392      * @param name The name of the Entity we wish to provide a value for.
1393      *
1394      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
1395      * nonstandard entities are not permitted. (HTML not yet
1396      * implemented.)
1397      */
1398     public Entity createEntity(String name)
1399     throws DOMException {
1400 
1401 
1402         if (errorChecking && !isXMLName(name,xml11Version)) {
1403             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
1404             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
1405         }
1406         return new EntityImpl(this, name);
1407 
1408     } // createEntity(String):Entity
1409 
1410     /**
1411      * NON-DOM
1412      * Factory method; creates a Notation having this Document
1413      * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
1414      * DTD information unspecified.)
1415      *
1416      * @param name The name of the Notation we wish to describe
1417      *
1418      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
1419      * notations are not permitted. (HTML not yet
1420      * implemented.)
1421      */
1422     public Notation createNotation(String name)
1423     throws DOMException {
1424 
1425         if (errorChecking && !isXMLName(name,xml11Version)) {
1426             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
1427             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
1428         }
1429         return new NotationImpl(this, name);
1430 
1431     } // createNotation(String):Notation
1432 
1433     /**
1434      * NON-DOM Factory method: creates an element definition. Element
1435      * definitions hold default attribute values.
1436      */
1437     public ElementDefinitionImpl createElementDefinition(String name)
1438     throws DOMException {
1439 
1440         if (errorChecking && !isXMLName(name,xml11Version)) {
1441             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
1442             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
1443         }
1444         return new ElementDefinitionImpl(this, name);
1445 
1446     } // createElementDefinition(String):ElementDefinitionImpl
1447 
1448     // other non-DOM methods
1449 
1450     /** NON-DOM:  Get the number associated with this document.   Used to
1451      * order documents in the implementation.
1452      */
1453     protected int getNodeNumber() {
1454         if (documentNumber==0) {
1455 
1456             CoreDOMImplementationImpl cd = (CoreDOMImplementationImpl)CoreDOMImplementationImpl.getDOMImplementation();
1457             documentNumber = cd.assignDocumentNumber();
1458         }
1459         return documentNumber;
1460     }
1461 
1462 
1463     /** NON-DOM:  Get a number associated with a node created with respect
1464      * to this document.   Needed for compareDocumentPosition when nodes
1465      * are disconnected.  This is only used on demand.
1466      */
1467     protected int getNodeNumber(Node node) {
1468 
1469         // Check if the node is already in the hash
1470         // If so, retrieve the node number
1471         // If not, assign a number to the node
1472         // Node numbers are negative, from -1 to -n
1473         int num;
1474         if (nodeTable == null) {
1475             nodeTable = new Hashtable();
1476             num = --nodeCounter;
1477             nodeTable.put(node, new Integer(num));
1478         }
1479         else {
1480             Integer n = (Integer)nodeTable.get(node);
1481             if (n== null) {
1482                 num = --nodeCounter;
1483                 nodeTable.put(node, new Integer(num));
1484             }
1485             else
1486                 num = n.intValue();
1487         }
1488         return num;
1489     }
1490 
1491     /**
1492      * Copies a node from another document to this document. The new nodes are
1493      * created using this document's factory methods and are populated with the
1494      * data from the source's accessor methods defined by the DOM interfaces.
1495      * Its behavior is otherwise similar to that of cloneNode.
1496      * <p>
1497      * According to the DOM specifications, document nodes cannot be imported
1498      * and a NOT_SUPPORTED_ERR exception is thrown if attempted.
1499      */
1500     public Node importNode(Node source, boolean deep)
1501     throws DOMException {
1502         return importNode(source, deep, false, null);
1503     } // importNode(Node,boolean):Node
1504 
1505     /**
1506      * Overloaded implementation of DOM's importNode method. This method
1507      * provides the core functionality for the public importNode and cloneNode
1508      * methods.
1509      *
1510      * The reversedIdentifiers parameter is provided for cloneNode to
1511      * preserve the document's identifiers. The Hashtable has Elements as the
1512      * keys and their identifiers as the values. When an element is being
1513      * imported, a check is done for an associated identifier. If one exists,
1514      * the identifier is registered with the new, imported element. If
1515      * reversedIdentifiers is null, the parameter is not applied.
1516      */
1517     private Node importNode(Node source, boolean deep, boolean cloningDoc,
1518     Hashtable reversedIdentifiers)
1519     throws DOMException {
1520         Node newnode=null;
1521                 Hashtable userData = null;
1522 
1523         // Sigh. This doesn't work; too many nodes have private data that
1524         // would have to be manually tweaked. May be able to add local
1525         // shortcuts to each nodetype. Consider ?????
1526         // if(source instanceof NodeImpl &&
1527         //  !(source instanceof DocumentImpl))
1528         // {
1529         //  // Can't clone DocumentImpl since it invokes us...
1530         //  newnode=(NodeImpl)source.cloneNode(false);
1531         //  newnode.ownerDocument=this;
1532         // }
1533         // else
1534                 if(source instanceof NodeImpl)
1535                         userData = ((NodeImpl)source).getUserDataRecord();
1536         int type = source.getNodeType();
1537         switch (type) {
1538             case ELEMENT_NODE: {
1539                 Element newElement;
1540                 boolean domLevel20 = source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0");
1541                 // Create element according to namespace support/qualification.
1542                 if(domLevel20 == false || source.getLocalName() == null)
1543                     newElement = createElement(source.getNodeName());
1544                 else
1545                     newElement = createElementNS(source.getNamespaceURI(),
1546                     source.getNodeName());
1547 
1548                 // Copy element's attributes, if any.
1549                 NamedNodeMap sourceAttrs = source.getAttributes();
1550                 if (sourceAttrs != null) {
1551                     int length = sourceAttrs.getLength();
1552                     for (int index = 0; index < length; index++) {
1553                         Attr attr = (Attr)sourceAttrs.item(index);
1554 
1555                         // NOTE: this methods is used for both importingNode
1556                         // and cloning the document node. In case of the
1557                         // clonning default attributes should be copied.
1558                         // But for importNode defaults should be ignored.
1559                         if (attr.getSpecified() || cloningDoc) {
1560                             Attr newAttr = (Attr)importNode(attr, true, cloningDoc,
1561                             reversedIdentifiers);
1562 
1563                             // Attach attribute according to namespace
1564                             // support/qualification.
1565                             if (domLevel20 == false ||
1566                             attr.getLocalName() == null)
1567                                 newElement.setAttributeNode(newAttr);
1568                             else
1569                                 newElement.setAttributeNodeNS(newAttr);
1570                         }
1571                     }
1572                 }
1573 
1574                 // Register element identifier.
1575                 if (reversedIdentifiers != null) {
1576                     // Does element have an associated identifier?
1577                     Object elementId = reversedIdentifiers.get(source);
1578                     if (elementId != null) {
1579                         if (identifiers == null)
1580                             identifiers = new Hashtable();
1581 
1582                         identifiers.put(elementId, newElement);
1583                     }
1584                 }
1585 
1586                 newnode = newElement;
1587                 break;
1588             }
1589 
1590             case ATTRIBUTE_NODE: {
1591 
1592                 if( source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0") ){
1593                     if (source.getLocalName() == null) {
1594                         newnode = createAttribute(source.getNodeName());
1595                     } else {
1596                         newnode = createAttributeNS(source.getNamespaceURI(),
1597                         source.getNodeName());
1598                     }
1599                 }
1600                 else {
1601                     newnode = createAttribute(source.getNodeName());
1602                 }
1603                 // if source is an AttrImpl from this very same implementation
1604                 // avoid creating the child nodes if possible
1605                 if (source instanceof AttrImpl) {
1606                     AttrImpl attr = (AttrImpl) source;
1607                     if (attr.hasStringValue()) {
1608                         AttrImpl newattr = (AttrImpl) newnode;
1609                         newattr.setValue(attr.getValue());
1610                         deep = false;
1611                     }
1612                     else {
1613                         deep = true;
1614                     }
1615                 }
1616                 else {
1617                     // According to the DOM spec the kids carry the value.
1618                     // However, there are non compliant implementations out
1619                     // there that fail to do so. To avoid ending up with no
1620                     // value at all, in this case we simply copy the text value
1621                     // directly.
1622                     if (source.getFirstChild() == null) {
1623                         newnode.setNodeValue(source.getNodeValue());
1624                         deep = false;
1625                     } else {
1626                         deep = true;
1627                     }
1628                 }
1629                 break;
1630             }
1631 
1632             case TEXT_NODE: {
1633                 newnode = createTextNode(source.getNodeValue());
1634                 break;
1635             }
1636 
1637             case CDATA_SECTION_NODE: {
1638                 newnode = createCDATASection(source.getNodeValue());
1639                 break;
1640             }
1641 
1642             case ENTITY_REFERENCE_NODE: {
1643                 newnode = createEntityReference(source.getNodeName());
1644                 // the subtree is created according to this doc by the method
1645                 // above, so avoid carrying over original subtree
1646                 deep = false;
1647                 break;
1648             }
1649 
1650             case ENTITY_NODE: {
1651                 Entity srcentity = (Entity)source;
1652                 EntityImpl newentity =
1653                 (EntityImpl)createEntity(source.getNodeName());
1654                 newentity.setPublicId(srcentity.getPublicId());
1655                 newentity.setSystemId(srcentity.getSystemId());
1656                 newentity.setNotationName(srcentity.getNotationName());
1657                 // Kids carry additional value,
1658                 // allow deep import temporarily
1659                 newentity.isReadOnly(false);
1660                 newnode = newentity;
1661                 break;
1662             }
1663 
1664             case PROCESSING_INSTRUCTION_NODE: {
1665                 newnode = createProcessingInstruction(source.getNodeName(),
1666                 source.getNodeValue());
1667                 break;
1668             }
1669 
1670             case COMMENT_NODE: {
1671                 newnode = createComment(source.getNodeValue());
1672                 break;
1673             }
1674 
1675             case DOCUMENT_TYPE_NODE: {
1676                 // unless this is used as part of cloning a Document
1677                 // forbid it for the sake of being compliant to the DOM spec
1678                 if (!cloningDoc) {
1679                     String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1680                     throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1681                 }
1682                 DocumentType srcdoctype = (DocumentType)source;
1683                 DocumentTypeImpl newdoctype = (DocumentTypeImpl)
1684                 createDocumentType(srcdoctype.getNodeName(),
1685                 srcdoctype.getPublicId(),
1686                 srcdoctype.getSystemId());
1687                 // Values are on NamedNodeMaps
1688                 NamedNodeMap smap = srcdoctype.getEntities();
1689                 NamedNodeMap tmap = newdoctype.getEntities();
1690                 if(smap != null) {
1691                     for(int i = 0; i < smap.getLength(); i++) {
1692                         tmap.setNamedItem(importNode(smap.item(i), true, true,
1693                         reversedIdentifiers));
1694                     }
1695                 }
1696                 smap = srcdoctype.getNotations();
1697                 tmap = newdoctype.getNotations();
1698                 if (smap != null) {
1699                     for(int i = 0; i < smap.getLength(); i++) {
1700                         tmap.setNamedItem(importNode(smap.item(i), true, true,
1701                         reversedIdentifiers));
1702                     }
1703                 }
1704 
1705                 // NOTE: At this time, the DOM definition of DocumentType
1706                 // doesn't cover Elements and their Attributes. domimpl's
1707                 // extentions in that area will not be preserved, even if
1708                 // copying from domimpl to domimpl. We could special-case
1709                 // that here. Arguably we should. Consider. ?????
1710                 newnode = newdoctype;
1711                 break;
1712             }
1713 
1714             case DOCUMENT_FRAGMENT_NODE: {
1715                 newnode = createDocumentFragment();
1716                 // No name, kids carry value
1717                 break;
1718             }
1719 
1720             case NOTATION_NODE: {
1721                 Notation srcnotation = (Notation)source;
1722                 NotationImpl newnotation =
1723                 (NotationImpl)createNotation(source.getNodeName());
1724                 newnotation.setPublicId(srcnotation.getPublicId());
1725                 newnotation.setSystemId(srcnotation.getSystemId());
1726                 // Kids carry additional value
1727                 newnode = newnotation;
1728                 // No name, no value
1729                 break;
1730             }
1731             case DOCUMENT_NODE : // Can't import document nodes
1732             default: {           // Unknown node type
1733                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1734                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1735             }
1736         }
1737 
1738                 if(userData != null)
1739                         callUserDataHandlers(source, newnode, UserDataHandler.NODE_IMPORTED,userData);
1740 
1741         // If deep, replicate and attach the kids.
1742         if (deep) {
1743             for (Node srckid = source.getFirstChild();
1744             srckid != null;
1745             srckid = srckid.getNextSibling()) {
1746                 newnode.appendChild(importNode(srckid, true, cloningDoc,
1747                 reversedIdentifiers));
1748             }
1749         }
1750         if (newnode.getNodeType() == Node.ENTITY_NODE) {
1751             ((NodeImpl)newnode).setReadOnly(true, true);
1752         }
1753         return newnode;
1754 
1755     } // importNode(Node,boolean,boolean,Hashtable):Node
1756 
1757     /**
1758      * DOM Level 3 WD - Experimental
1759      * Change the node's ownerDocument, and its subtree, to this Document
1760      *
1761      * @param source The node to adopt.
1762      * @see #importNode
1763      **/
1764     public Node adoptNode(Node source) {
1765         NodeImpl node;
1766                 Hashtable userData = null;
1767         try {
1768             node = (NodeImpl) source;
1769         } catch (ClassCastException e) {
1770             // source node comes from a different DOMImplementation
1771             return null;
1772         }
1773 
1774         // Return null if the source is null
1775 
1776         if (source == null ) {
1777                 return null;
1778         } else if (source != null && source.getOwnerDocument() != null) {
1779 
1780             DOMImplementation thisImpl = this.getImplementation();
1781             DOMImplementation otherImpl = source.getOwnerDocument().getImplementation();
1782 
1783             // when the source node comes from a different implementation.
1784             if (thisImpl != otherImpl) {
1785 
1786                 // Adopting from a DefferedDOM to DOM
1787                 if (thisImpl instanceof com.sun.org.apache.xerces.internal.dom.DOMImplementationImpl &&
1788                         otherImpl instanceof com.sun.org.apache.xerces.internal.dom.DeferredDOMImplementationImpl) {
1789                     // traverse the DOM and expand deffered nodes and then allow adoption
1790                     undeferChildren (node);
1791                 } else if ( thisImpl instanceof com.sun.org.apache.xerces.internal.dom.DeferredDOMImplementationImpl
1792                         && otherImpl instanceof com.sun.org.apache.xerces.internal.dom.DOMImplementationImpl) {
1793                     // Adopting from a DOM into a DefferedDOM, this should be okay
1794                 } else {
1795                     // Adopting between two dissimilar DOM's is not allowed
1796                     return null;
1797                 }
1798                 }
1799         }
1800 
1801         switch (node.getNodeType()) {
1802             case ATTRIBUTE_NODE: {
1803                 AttrImpl attr = (AttrImpl) node;
1804                 // remove node from wherever it is
1805                 if( attr.getOwnerElement() != null){
1806                     //1. owner element attribute is set to null
1807                     attr.getOwnerElement().removeAttributeNode(attr);
1808                 }
1809                 //2. specified flag is set to true
1810                 attr.isSpecified(true);
1811                                 userData = node.getUserDataRecord();
1812 
1813                 //3. change ownership
1814                 attr.setOwnerDocument(this);
1815                                 if(userData != null )
1816                                         setUserDataTable(node,userData);
1817                 break;
1818             }
1819             //entity, notation nodes are read only nodes.. so they can't be adopted.
1820             //runtime will fall through to NOTATION_NODE
1821             case ENTITY_NODE:
1822             case NOTATION_NODE:{
1823                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
1824                 throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
1825 
1826             }
1827             //document, documentype nodes can't be adopted.
1828             //runtime will fall through to DocumentTypeNode
1829             case DOCUMENT_NODE:
1830             case DOCUMENT_TYPE_NODE: {
1831                 String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1832                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1833             }
1834             case ENTITY_REFERENCE_NODE: {
1835                                 userData = node.getUserDataRecord();
1836                 // remove node from wherever it is
1837                 Node parent = node.getParentNode();
1838                 if (parent != null) {
1839                     parent.removeChild(source);
1840                 }
1841                 // discard its replacement value
1842                 Node child;
1843                 while ((child = node.getFirstChild()) != null) {
1844                     node.removeChild(child);
1845                 }
1846                 // change ownership
1847                 node.setOwnerDocument(this);
1848                                 if(userData != null)
1849                                         setUserDataTable(node,userData);
1850                 // set its new replacement value if any
1851                 if (docType == null) {
1852                     break;
1853                 }
1854                 NamedNodeMap entities = docType.getEntities();
1855                 Node entityNode = entities.getNamedItem(node.getNodeName());
1856                 if (entityNode == null) {
1857                     break;
1858                 }
1859                 for (child = entityNode.getFirstChild();
1860                 child != null; child = child.getNextSibling()) {
1861                     Node childClone = child.cloneNode(true);
1862                     node.appendChild(childClone);
1863                 }
1864                 break;
1865             }
1866             case ELEMENT_NODE: {
1867                                 userData = node.getUserDataRecord();
1868                 // remove node from wherever it is
1869                 Node parent = node.getParentNode();
1870                 if (parent != null) {
1871                     parent.removeChild(source);
1872                 }
1873                 // change ownership
1874                 node.setOwnerDocument(this);
1875                                 if(userData != null)
1876                                         setUserDataTable(node,userData);
1877                 // reconcile default attributes
1878                 ((ElementImpl)node).reconcileDefaultAttributes();
1879                 break;
1880             }
1881             default: {
1882                                 userData = node.getUserDataRecord();
1883                 // remove node from wherever it is
1884                 Node parent = node.getParentNode();
1885                 if (parent != null) {
1886                     parent.removeChild(source);
1887                 }
1888                 // change ownership
1889                 node.setOwnerDocument(this);
1890                                 if(userData != null)
1891                                         setUserDataTable(node,userData);
1892             }
1893         }
1894 
1895                 //DOM L3 Core CR
1896                 //http://www.w3.org/TR/2003/CR-DOM-Level-3-Core-20031107/core.html#UserDataHandler-ADOPTED
1897                 if(userData != null)
1898                         callUserDataHandlers(source, null, UserDataHandler.NODE_ADOPTED,userData);
1899 
1900         return node;
1901     }
1902 
1903     /**
1904      * Traverses the DOM Tree and expands deferred nodes and their
1905      * children.
1906      *
1907      */
1908     protected void undeferChildren(Node node) {
1909 
1910         Node top = node;
1911 
1912         while (null != node) {
1913 
1914             if (((NodeImpl)node).needsSyncData()) {
1915                 ((NodeImpl)node).synchronizeData();
1916             }
1917 
1918             NamedNodeMap attributes = node.getAttributes();
1919             if (attributes != null) {
1920                 int length = attributes.getLength();
1921                 for (int i = 0; i < length; ++i) {
1922                     undeferChildren(attributes.item(i));
1923                 }
1924             }
1925 
1926             Node nextNode = null;
1927             nextNode = node.getFirstChild();
1928 
1929             while (null == nextNode) {
1930 
1931                 if (top.equals(node))
1932                     break;
1933 
1934                 nextNode = node.getNextSibling();
1935 
1936                 if (null == nextNode) {
1937                     node = node.getParentNode();
1938 
1939                     if ((null == node) || (top.equals(node))) {
1940                         nextNode = null;
1941                         break;
1942                     }
1943                 }
1944             }
1945 
1946             node = nextNode;
1947         }
1948     }
1949 
1950     // identifier maintenence
1951     /**
1952      * Introduced in DOM Level 2
1953      * Returns the Element whose ID is given by elementId. If no such element
1954      * exists, returns null. Behavior is not defined if more than one element
1955      * has this ID.
1956      * <p>
1957      * Note: The DOM implementation must have information that says which
1958      * attributes are of type ID. Attributes with the name "ID" are not of type
1959      * ID unless so defined. Implementations that do not know whether
1960      * attributes are of type ID or not are expected to return null.
1961      * @see #getIdentifier
1962      */
1963     public Element getElementById(String elementId) {
1964         return getIdentifier(elementId);
1965     }
1966 
1967     /**
1968      * Remove all identifiers from the ID table
1969      */
1970     protected final void clearIdentifiers(){
1971         if (identifiers != null){
1972             identifiers.clear();
1973         }
1974     }
1975 
1976     /**
1977      * Registers an identifier name with a specified element node.
1978      * If the identifier is already registered, the new element
1979      * node replaces the previous node. If the specified element
1980      * node is null, removeIdentifier() is called.
1981      *
1982      * @see #getIdentifier
1983      * @see #removeIdentifier
1984      */
1985     public void putIdentifier(String idName, Element element) {
1986 
1987         if (element == null) {
1988             removeIdentifier(idName);
1989             return;
1990         }
1991 
1992         if (needsSyncData()) {
1993             synchronizeData();
1994         }
1995 
1996         if (identifiers == null) {
1997             identifiers = new Hashtable();
1998         }
1999 
2000         identifiers.put(idName, element);
2001 
2002     } // putIdentifier(String,Element)
2003 
2004     /**
2005      * Returns a previously registered element with the specified
2006      * identifier name, or null if no element is registered.
2007      *
2008      * @see #putIdentifier
2009      * @see #removeIdentifier
2010      */
2011     public Element getIdentifier(String idName) {
2012 
2013         if (needsSyncData()) {
2014             synchronizeData();
2015         }
2016 
2017         if (identifiers == null) {
2018             return null;
2019         }
2020         Element elem = (Element) identifiers.get(idName);
2021         if (elem != null) {
2022             // check that the element is in the tree
2023             Node parent = elem.getParentNode();
2024             while (parent != null) {
2025                 if (parent == this) {
2026                     return elem;
2027                 }
2028                 parent = parent.getParentNode();
2029             }
2030         }
2031         return null;
2032     } // getIdentifier(String):Element
2033 
2034     /**
2035      * Removes a previously registered element with the specified
2036      * identifier name.
2037      *
2038      * @see #putIdentifier
2039      * @see #getIdentifier
2040      */
2041     public void removeIdentifier(String idName) {
2042 
2043         if (needsSyncData()) {
2044             synchronizeData();
2045         }
2046 
2047         if (identifiers == null) {
2048             return;
2049         }
2050 
2051         identifiers.remove(idName);
2052 
2053     } // removeIdentifier(String)
2054 
2055     /** Returns an enumeration registered of identifier names. */
2056     public Enumeration getIdentifiers() {
2057 
2058         if (needsSyncData()) {
2059             synchronizeData();
2060         }
2061 
2062         if (identifiers == null) {
2063             identifiers = new Hashtable();
2064         }
2065 
2066         return identifiers.keys();
2067 
2068     } // getIdentifiers():Enumeration
2069 
2070     //
2071     // DOM2: Namespace methods
2072     //
2073 
2074     /**
2075      * Introduced in DOM Level 2. <p>
2076      * Creates an element of the given qualified name and namespace URI.
2077      * If the given namespaceURI is null or an empty string and the
2078      * qualifiedName has a prefix that is "xml", the created element
2079      * is bound to the predefined namespace
2080      * "http://www.w3.org/XML/1998/namespace" [Namespaces].
2081      * @param namespaceURI The namespace URI of the element to
2082      *                     create.
2083      * @param qualifiedName The qualified name of the element type to
2084      *                      instantiate.
2085      * @return Element A new Element object with the following attributes:
2086      * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
2087      * name contains an invalid character.
2088      * @throws DOMException NAMESPACE_ERR: Raised if the qualifiedName has a
2089      *                      prefix that is "xml" and the namespaceURI is
2090      *                      neither null nor an empty string nor
2091      *                      "http://www.w3.org/XML/1998/namespace", or
2092      *                      if the qualifiedName has a prefix different
2093      *                      from "xml" and the namespaceURI is null or an
2094      *                      empty string.
2095      * @since WD-DOM-Level-2-19990923
2096      */
2097     public Element createElementNS(String namespaceURI, String qualifiedName)
2098     throws DOMException {
2099         return new ElementNSImpl(this, namespaceURI, qualifiedName);
2100     }
2101 
2102     /**
2103      * NON-DOM: a factory method used by the Xerces DOM parser
2104      * to create an element.
2105      *
2106      * @param namespaceURI The namespace URI of the element to
2107      *                     create.
2108      * @param qualifiedName The qualified name of the element type to
2109      *                      instantiate.
2110      * @param localpart  The local name of the attribute to instantiate.
2111      *
2112      * @return Element A new Element object with the following attributes:
2113      * @exception DOMException INVALID_CHARACTER_ERR: Raised if the specified
2114      *                   name contains an invalid character.
2115      */
2116     public Element createElementNS(String namespaceURI, String qualifiedName,
2117     String localpart)
2118     throws DOMException {
2119         return new ElementNSImpl(this, namespaceURI, qualifiedName, localpart);
2120     }
2121 
2122     /**
2123      * Introduced in DOM Level 2. <p>
2124      * Creates an attribute of the given qualified name and namespace URI.
2125      * If the given namespaceURI is null or an empty string and the
2126      * qualifiedName has a prefix that is "xml", the created element
2127      * is bound to the predefined namespace
2128      * "http://www.w3.org/XML/1998/namespace" [Namespaces].
2129      *
2130      * @param namespaceURI  The namespace URI of the attribute to
2131      *                      create. When it is null or an empty string,
2132      *                      this method behaves like createAttribute.
2133      * @param qualifiedName The qualified name of the attribute to
2134      *                      instantiate.
2135      * @return Attr         A new Attr object.
2136      * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
2137      * name contains an invalid character.
2138      * @since WD-DOM-Level-2-19990923
2139      */
2140     public Attr createAttributeNS(String namespaceURI, String qualifiedName)
2141     throws DOMException {
2142         return new AttrNSImpl(this, namespaceURI, qualifiedName);
2143     }
2144 
2145     /**
2146      * NON-DOM: a factory method used by the Xerces DOM parser
2147      * to create an element.
2148      *
2149      * @param namespaceURI  The namespace URI of the attribute to
2150      *                      create. When it is null or an empty string,
2151      *                      this method behaves like createAttribute.
2152      * @param qualifiedName The qualified name of the attribute to
2153      *                      instantiate.
2154      * @param localpart     The local name of the attribute to instantiate.
2155      *
2156      * @return Attr         A new Attr object.
2157      * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
2158      * name contains an invalid character.
2159      */
2160     public Attr createAttributeNS(String namespaceURI, String qualifiedName,
2161     String localpart)
2162     throws DOMException {
2163         return new AttrNSImpl(this, namespaceURI, qualifiedName, localpart);
2164     }
2165 
2166     /**
2167      * Introduced in DOM Level 2. <p>
2168      * Returns a NodeList of all the Elements with a given local name and
2169      * namespace URI in the order in which they would be encountered in a
2170      * preorder traversal of the Document tree.
2171      * @param namespaceURI  The namespace URI of the elements to match
2172      *                      on. The special value "*" matches all
2173      *                      namespaces. When it is null or an empty
2174      *                      string, this method behaves like
2175      *                      getElementsByTagName.
2176      * @param localName     The local name of the elements to match on.
2177      *                      The special value "*" matches all local names.
2178      * @return NodeList     A new NodeList object containing all the matched
2179      *                      Elements.
2180      * @since WD-DOM-Level-2-19990923
2181      */
2182     public NodeList getElementsByTagNameNS(String namespaceURI,
2183     String localName) {
2184         return new DeepNodeListImpl(this, namespaceURI, localName);
2185     }
2186 
2187     //
2188     // Object methods
2189     //
2190 
2191     /** Clone. */
2192     public Object clone() throws CloneNotSupportedException {
2193         CoreDocumentImpl newdoc = (CoreDocumentImpl) super.clone();
2194         newdoc.docType = null;
2195         newdoc.docElement = null;
2196         return newdoc;
2197     }
2198 
2199     //
2200     // Public static methods
2201     //
2202 
2203     /**
2204      * Check the string against XML's definition of acceptable names for
2205      * elements and attributes and so on using the XMLCharacterProperties
2206      * utility class
2207      */
2208 
2209     public static final boolean isXMLName(String s, boolean xml11Version) {
2210 
2211         if (s == null) {
2212             return false;
2213         }
2214         if(!xml11Version)
2215             return XMLChar.isValidName(s);
2216         else
2217             return XML11Char.isXML11ValidName(s);
2218 
2219     } // isXMLName(String):boolean
2220 
2221     /**
2222      * Checks if the given qualified name is legal with respect
2223      * to the version of XML to which this document must conform.
2224      *
2225      * @param prefix prefix of qualified name
2226      * @param local local part of qualified name
2227      */
2228     public static final boolean isValidQName(String prefix, String local, boolean xml11Version) {
2229 
2230         // check that both prefix and local part match NCName
2231         if (local == null) return false;
2232         boolean validNCName = false;
2233 
2234         if (!xml11Version) {
2235             validNCName = (prefix == null || XMLChar.isValidNCName(prefix))
2236                 && XMLChar.isValidNCName(local);
2237         }
2238         else {
2239             validNCName = (prefix == null || XML11Char.isXML11ValidNCName(prefix))
2240                 && XML11Char.isXML11ValidNCName(local);
2241         }
2242 
2243         return validNCName;
2244     }
2245     //
2246     // Protected methods
2247     //
2248 
2249     /**
2250      * Uses the kidOK lookup table to check whether the proposed
2251      * tree structure is legal.
2252      */
2253     protected boolean isKidOK(Node parent, Node child) {
2254         if (allowGrammarAccess &&
2255         parent.getNodeType() == Node.DOCUMENT_TYPE_NODE) {
2256             return child.getNodeType() == Node.ELEMENT_NODE;
2257         }
2258         return 0 != (kidOK[parent.getNodeType()] & 1 << child.getNodeType());
2259     }
2260 
2261     /**
2262      * Denotes that this node has changed.
2263      */
2264     protected void changed() {
2265         changes++;
2266     }
2267 
2268     /**
2269      * Returns the number of changes to this node.
2270      */
2271     protected int changes() {
2272         return changes;
2273     }
2274 
2275     //  NodeListCache pool
2276 
2277     /**
2278      * Returns a NodeListCache for the given node.
2279      */
2280     NodeListCache getNodeListCache(ParentNode owner) {
2281         if (fFreeNLCache == null) {
2282             return new NodeListCache(owner);
2283         }
2284         NodeListCache c = fFreeNLCache;
2285         fFreeNLCache = fFreeNLCache.next;
2286         c.fChild = null;
2287         c.fChildIndex = -1;
2288         c.fLength = -1;
2289         // revoke previous ownership
2290         if (c.fOwner != null) {
2291             c.fOwner.fNodeListCache = null;
2292         }
2293         c.fOwner = owner;
2294         // c.next = null; not necessary, except for confused people...
2295         return c;
2296     }
2297 
2298     /**
2299      * Puts the given NodeListCache in the free list.
2300      * Note: The owner node can keep using it until we reuse it
2301      */
2302     void freeNodeListCache(NodeListCache c) {
2303         c.next = fFreeNLCache;
2304         fFreeNLCache = c;
2305     }
2306 
2307 
2308 
2309     /**
2310      * Associate an object to a key on this node. The object can later be
2311      * retrieved from this node by calling <code>getUserData</code> with the
2312      * same key.
2313      * @param n The node to associate the object to.
2314      * @param key The key to associate the object to.
2315      * @param data The object to associate to the given key, or
2316      *   <code>null</code> to remove any existing association to that key.
2317      * @param handler The handler to associate to that key, or
2318      *   <code>null</code>.
2319      * @return Returns the <code>DOMObject</code> previously associated to
2320      *   the given key on this node, or <code>null</code> if there was none.
2321      * @since DOM Level 3
2322      *
2323      * REVISIT: we could use a free list of UserDataRecord here
2324      */
2325     public Object setUserData(Node n, String key,
2326     Object data, UserDataHandler handler) {
2327         if (data == null) {
2328             if (userData != null) {
2329                 Hashtable t = (Hashtable) userData.get(n);
2330                 if (t != null) {
2331                     Object o = t.remove(key);
2332                     if (o != null) {
2333                         UserDataRecord r = (UserDataRecord) o;
2334                         return r.fData;
2335                     }
2336                 }
2337             }
2338             return null;
2339         }
2340         else {
2341             Hashtable t;
2342             if (userData == null) {
2343                 userData = new Hashtable();
2344                 t = new Hashtable();
2345                 userData.put(n, t);
2346             }
2347             else {
2348                 t = (Hashtable) userData.get(n);
2349                 if (t == null) {
2350                     t = new Hashtable();
2351                     userData.put(n, t);
2352                 }
2353             }
2354             Object o = t.put(key, new UserDataRecord(data, handler));
2355             if (o != null) {
2356                 UserDataRecord r = (UserDataRecord) o;
2357                 return r.fData;
2358             }
2359             return null;
2360         }
2361     }
2362 
2363 
2364     /**
2365      * Retrieves the object associated to a key on a this node. The object
2366      * must first have been set to this node by calling
2367      * <code>setUserData</code> with the same key.
2368      * @param n The node the object is associated to.
2369      * @param key The key the object is associated to.
2370      * @return Returns the <code>DOMObject</code> associated to the given key
2371      *   on this node, or <code>null</code> if there was none.
2372      * @since DOM Level 3
2373      */
2374     public Object getUserData(Node n, String key) {
2375         if (userData == null) {
2376             return null;
2377         }
2378         Hashtable t = (Hashtable) userData.get(n);
2379         if (t == null) {
2380             return null;
2381         }
2382         Object o = t.get(key);
2383         if (o != null) {
2384             UserDataRecord r = (UserDataRecord) o;
2385             return r.fData;
2386         }
2387         return null;
2388     }
2389 
2390         protected Hashtable getUserDataRecord(Node n){
2391         if (userData == null) {
2392             return null;
2393         }
2394         Hashtable t = (Hashtable) userData.get(n);
2395         if (t == null) {
2396             return null;
2397         }
2398                 return t;
2399         }
2400 
2401         /**
2402      * Remove user data table for the given node.
2403      * @param n The node this operation applies to.
2404      * @return The removed table.
2405      */
2406     Hashtable removeUserDataTable(Node n) {
2407         if (userData == null) {
2408             return null;
2409         }
2410         return (Hashtable) userData.get(n);
2411     }
2412 
2413     /**
2414      * Set user data table for the given node.
2415      * @param n The node this operation applies to.
2416      * @param data The user data table.
2417      */
2418     void setUserDataTable(Node n, Hashtable data) {
2419                 if (userData == null)
2420                         userData = new Hashtable();
2421         if (data != null) {
2422             userData.put(n, data);
2423         }
2424     }
2425 
2426     /**
2427      * Call user data handlers when a node is deleted (finalized)
2428      * @param n The node this operation applies to.
2429      * @param c The copy node or null.
2430      * @param operation The operation - import, clone, or delete.
2431      */
2432     void callUserDataHandlers(Node n, Node c, short operation) {
2433         if (userData == null) {
2434             return;
2435         }
2436         //Hashtable t = (Hashtable) userData.get(n);
2437                 if(n instanceof NodeImpl){
2438                         Hashtable t = ((NodeImpl)n).getUserDataRecord();
2439                         if (t == null || t.isEmpty()) {
2440                                 return;
2441                         }
2442                         callUserDataHandlers(n, c, operation,t);
2443                 }
2444     }
2445 
2446         /**
2447      * Call user data handlers when a node is deleted (finalized)
2448      * @param n The node this operation applies to.
2449      * @param c The copy node or null.
2450      * @param operation The operation - import, clone, or delete.
2451          * @param handlers Data associated with n.
2452         */
2453         void callUserDataHandlers(Node n, Node c, short operation,Hashtable userData) {
2454         if (userData == null || userData.isEmpty()) {
2455             return;
2456         }
2457         Enumeration keys = userData.keys();
2458         while (keys.hasMoreElements()) {
2459             String key = (String) keys.nextElement();
2460             UserDataRecord r = (UserDataRecord) userData.get(key);
2461             if (r.fHandler != null) {
2462                 r.fHandler.handle(operation, key, r.fData, n, c);
2463             }
2464         }
2465     }
2466 
2467         /**
2468      * Call user data handlers to let them know the nodes they are related to
2469      * are being deleted. The alternative would be to do that on Node but
2470      * because the nodes are used as the keys we have a reference to them that
2471      * prevents them from being gc'ed until the document is. At the same time,
2472      * doing it here has the advantage of avoiding a finalize() method on Node,
2473      * which would affect all nodes and not just the ones that have a user
2474      * data.
2475      */
2476     // Temporarily comment out this method, because
2477     // 1. It seems that finalizers are not guaranteed to be called, so the
2478     //    functionality is not implemented.
2479     // 2. It affects the performance greatly in multi-thread environment.
2480     // -SG
2481     /*public void finalize() {
2482         if (userData == null) {
2483             return;
2484         }
2485         Enumeration nodes = userData.keys();
2486         while (nodes.hasMoreElements()) {
2487             Object node = nodes.nextElement();
2488             Hashtable t = (Hashtable) userData.get(node);
2489             if (t != null && !t.isEmpty()) {
2490                 Enumeration keys = t.keys();
2491                 while (keys.hasMoreElements()) {
2492                     String key = (String) keys.nextElement();
2493                     UserDataRecord r = (UserDataRecord) t.get(key);
2494                     if (r.fHandler != null) {
2495                         r.fHandler.handle(UserDataHandler.NODE_DELETED,
2496                                           key, r.fData, null, null);
2497                     }
2498                 }
2499             }
2500         }
2501     }*/
2502 
2503     protected final void checkNamespaceWF( String qname, int colon1,
2504     int colon2) {
2505 
2506         if (!errorChecking) {
2507             return;
2508         }
2509         // it is an error for NCName to have more than one ':'
2510         // check if it is valid QName [Namespace in XML production 6]
2511         // :camera , nikon:camera:minolta, camera:
2512         if (colon1 == 0 || colon1 == qname.length() - 1 || colon2 != colon1) {
2513             String msg =
2514             DOMMessageFormatter.formatMessage(
2515             DOMMessageFormatter.DOM_DOMAIN,
2516             "NAMESPACE_ERR",
2517             null);
2518             throw new DOMException(DOMException.NAMESPACE_ERR, msg);
2519         }
2520     }
2521     protected final void checkDOMNSErr(String prefix,
2522     String namespace) {
2523         if (errorChecking) {
2524             if (namespace == null) {
2525                 String msg =
2526                 DOMMessageFormatter.formatMessage(
2527                 DOMMessageFormatter.DOM_DOMAIN,
2528                 "NAMESPACE_ERR",
2529                 null);
2530                 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
2531             }
2532             else if (prefix.equals("xml")
2533             && !namespace.equals(NamespaceContext.XML_URI)) {
2534                 String msg =
2535                 DOMMessageFormatter.formatMessage(
2536                 DOMMessageFormatter.DOM_DOMAIN,
2537                 "NAMESPACE_ERR",
2538                 null);
2539                 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
2540             }
2541             else if (
2542             prefix.equals("xmlns")
2543             && !namespace.equals(NamespaceContext.XMLNS_URI)
2544             || (!prefix.equals("xmlns")
2545             && namespace.equals(NamespaceContext.XMLNS_URI))) {
2546                 String msg =
2547                 DOMMessageFormatter.formatMessage(
2548                 DOMMessageFormatter.DOM_DOMAIN,
2549                 "NAMESPACE_ERR",
2550                 null);
2551                 throw new DOMException(DOMException.NAMESPACE_ERR, msg);
2552             }
2553         }
2554     }
2555 
2556     /**
2557      * Checks if the given qualified name is legal with respect
2558      * to the version of XML to which this document must conform.
2559      *
2560      * @param prefix prefix of qualified name
2561      * @param local local part of qualified name
2562      */
2563     protected final void checkQName(String prefix, String local) {
2564         if (!errorChecking) {
2565             return;
2566         }
2567 
2568                 // check that both prefix and local part match NCName
2569         boolean validNCName = false;
2570         if (!xml11Version) {
2571             validNCName = (prefix == null || XMLChar.isValidNCName(prefix))
2572                 && XMLChar.isValidNCName(local);
2573         }
2574         else {
2575             validNCName = (prefix == null || XML11Char.isXML11ValidNCName(prefix))
2576                 && XML11Char.isXML11ValidNCName(local);
2577         }
2578 
2579         if (!validNCName) {
2580             // REVISIT: add qname parameter to the message
2581             String msg =
2582             DOMMessageFormatter.formatMessage(
2583             DOMMessageFormatter.DOM_DOMAIN,
2584             "INVALID_CHARACTER_ERR",
2585             null);
2586             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
2587         }
2588     }
2589 
2590     /**
2591      * We could have more xml versions in future , but for now we could
2592      * do with this to handle XML 1.0 and 1.1
2593      */
2594     boolean isXML11Version(){
2595         return xml11Version;
2596     }
2597 
2598     boolean isNormalizeDocRequired(){
2599         // REVISIT: Implement to optimize when normalization
2600         // is required
2601         return true;
2602     }
2603 
2604     //we should be checking the (elements, attribute, entity etc.) names only when
2605     //version of the document is changed.
2606     boolean isXMLVersionChanged(){
2607         return xmlVersionChanged ;
2608     }
2609     /**
2610      * NON-DOM: kept for backward compatibility
2611      * Store user data related to a given node
2612      * This is a place where we could use weak references! Indeed, the node
2613      * here won't be GC'ed as long as some user data is attached to it, since
2614      * the userData table will have a reference to the node.
2615      */
2616     protected void setUserData(NodeImpl n, Object data) {
2617         setUserData(n, "XERCES1DOMUSERDATA", data, null);
2618     }
2619 
2620     /**
2621      * NON-DOM: kept for backward compatibility
2622      * Retreive user data related to a given node
2623      */
2624     protected Object getUserData(NodeImpl n) {
2625         return getUserData(n, "XERCES1DOMUSERDATA");
2626     }
2627 
2628 
2629     // Event related methods overidden in subclass
2630 
2631     protected void addEventListener(NodeImpl node, String type,
2632     EventListener listener,
2633     boolean useCapture) {
2634         // does nothing by default - overidden in subclass
2635     }
2636 
2637     protected void removeEventListener(NodeImpl node, String type,
2638     EventListener listener,
2639     boolean useCapture) {
2640         // does nothing by default - overidden in subclass
2641     }
2642 
2643     protected void copyEventListeners(NodeImpl src, NodeImpl tgt) {
2644         // does nothing by default - overidden in subclass
2645     }
2646 
2647     protected boolean dispatchEvent(NodeImpl node, Event event) {
2648         // does nothing by default - overidden in subclass
2649         return false;
2650     }
2651 
2652     // Notification methods overidden in subclasses
2653 
2654     /**
2655      * A method to be called when some text was changed in a text node,
2656      * so that live objects can be notified.
2657      */
2658     void replacedText(NodeImpl node) {
2659     }
2660 
2661     /**
2662      * A method to be called when some text was deleted from a text node,
2663      * so that live objects can be notified.
2664      */
2665     void deletedText(NodeImpl node, int offset, int count) {
2666     }
2667 
2668     /**
2669      * A method to be called when some text was inserted into a text node,
2670      * so that live objects can be notified.
2671      */
2672     void insertedText(NodeImpl node, int offset, int count) {
2673     }
2674 
2675     /**
2676      * A method to be called when a character data node is about to be modified
2677      */
2678     void modifyingCharacterData(NodeImpl node, boolean replace) {
2679     }
2680 
2681     /**
2682      * A method to be called when a character data node has been modified
2683      */
2684     void modifiedCharacterData(NodeImpl node, String oldvalue, String value, boolean replace) {
2685     }
2686 
2687     /**
2688      * A method to be called when a node is about to be inserted in the tree.
2689      */
2690     void insertingNode(NodeImpl node, boolean replace) {
2691     }
2692 
2693     /**
2694      * A method to be called when a node has been inserted in the tree.
2695      */
2696     void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) {
2697     }
2698 
2699     /**
2700      * A method to be called when a node is about to be removed from the tree.
2701      */
2702     void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) {
2703     }
2704 
2705     /**
2706      * A method to be called when a node has been removed from the tree.
2707      */
2708     void removedNode(NodeImpl node, boolean replace) {
2709     }
2710 
2711     /**
2712      * A method to be called when a node is about to be replaced in the tree.
2713      */
2714     void replacingNode(NodeImpl node) {
2715     }
2716 
2717     /**
2718      * A method to be called when a node has been replaced in the tree.
2719      */
2720     void replacedNode(NodeImpl node) {
2721     }
2722 
2723     /**
2724      * A method to be called when a character data node is about to be replaced
2725      */
2726     void replacingData(NodeImpl node) {
2727     }
2728 
2729     /**
2730      *  method to be called when a character data node has been replaced.
2731      */
2732     void replacedCharacterData(NodeImpl node, String oldvalue, String value) {
2733     }
2734 
2735 
2736     /**
2737      * A method to be called when an attribute value has been modified
2738      */
2739     void modifiedAttrValue(AttrImpl attr, String oldvalue) {
2740     }
2741 
2742     /**
2743      * A method to be called when an attribute node has been set
2744      */
2745     void setAttrNode(AttrImpl attr, AttrImpl previous) {
2746     }
2747 
2748     /**
2749      * A method to be called when an attribute node has been removed
2750      */
2751     void removedAttrNode(AttrImpl attr, NodeImpl oldOwner, String name) {
2752     }
2753 
2754     /**
2755      * A method to be called when an attribute node has been renamed
2756      */
2757     void renamedAttrNode(Attr oldAt, Attr newAt) {
2758     }
2759 
2760     /**
2761      * A method to be called when an element has been renamed
2762      */
2763     void renamedElement(Element oldEl, Element newEl) {
2764     }
2765 
2766 } // class CoreDocumentImpl