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