KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > dom > CoreDocumentImpl


1  /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package com.sun.org.apache.xerces.internal.dom;
59
60 import java.io.Serializable JavaDoc;
61 import java.util.Enumeration JavaDoc;
62 import java.util.Hashtable JavaDoc;
63
64 import org.w3c.dom.DOMConfiguration JavaDoc;
65 import org.w3c.dom.UserDataHandler JavaDoc;
66 import com.sun.org.apache.xerces.internal.util.XMLChar;
67 import com.sun.org.apache.xerces.internal.util.XML11Char;
68 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
69 import org.w3c.dom.Attr JavaDoc;
70 import org.w3c.dom.CDATASection JavaDoc;
71 import org.w3c.dom.Comment JavaDoc;
72 import org.w3c.dom.DOMException JavaDoc;
73 import org.w3c.dom.DOMImplementation JavaDoc;
74 import org.w3c.dom.Document JavaDoc;
75 import org.w3c.dom.DocumentFragment JavaDoc;
76 import org.w3c.dom.DocumentType JavaDoc;
77 import org.w3c.dom.Element JavaDoc;
78 import org.w3c.dom.Entity JavaDoc;
79 import org.w3c.dom.EntityReference JavaDoc;
80 import org.w3c.dom.NamedNodeMap JavaDoc;
81 import org.w3c.dom.Node JavaDoc;
82 import org.w3c.dom.NodeList JavaDoc;
83 import org.w3c.dom.Notation JavaDoc;
84 import org.w3c.dom.ProcessingInstruction JavaDoc;
85 import org.w3c.dom.Text JavaDoc;
86 import org.w3c.dom.events.Event JavaDoc;
87 import org.w3c.dom.events.EventListener JavaDoc;
88 import org.w3c.dom.ls.DOMImplementationLS JavaDoc;
89 import org.w3c.dom.ls.LSSerializer JavaDoc;
90
91 /**
92  * The Document interface represents the entire HTML or XML document.
93  * Conceptually, it is the root of the document tree, and provides the
94  * primary access to the document's data.
95  * <P>
96  * Since elements, text nodes, comments, processing instructions,
97  * etc. cannot exist outside the context of a Document, the Document
98  * interface also contains the factory methods needed to create these
99  * objects. The Node objects created have a ownerDocument attribute
100  * which associates them with the Document within whose context they
101  * were created.
102  * <p>
103  * The CoreDocumentImpl class only implements the DOM Core. Additional modules
104  * are supported by the more complete DocumentImpl subclass.
105  * <p>
106  * <b>Note:</b> When any node in the document is serialized, the
107  * entire document is serialized along with it.
108  *
109  * @author Arnaud Le Hors, IBM
110  * @author Joe Kesselman, IBM
111  * @author Andy Clark, IBM
112  * @author Ralf Pfeiffer, IBM
113  * @version $Id: CoreDocumentImpl.java,v 1.71 2004/04/26 14:44:56 venu Exp $
114  * @since PR-DOM-Level-1-19980818.
115  */

116
117
118 public class CoreDocumentImpl
119 extends ParentNode implements Document JavaDoc {
120
121     /**TODO::
122      * 1. Change XML11Char method names similar to XMLChar. That will prevent lot
123      * of dirty version checking code.
124      *
125      * 2. IMO during cloneNode qname/isXMLName check should not be made.
126      */

127     //
128
// Constants
129
//
130

131     /** Serialization version. */
132     static final long serialVersionUID = 0;
133
134     //
135
// Data
136
//
137

138     // document information
139

140     /** Document type. */
141     protected DocumentTypeImpl docType;
142
143     /** Document element. */
144     protected ElementImpl docElement;
145
146     /** NodeListCache free list */
147     transient NodeListCache fFreeNLCache;
148
149     /**Experimental DOM Level 3 feature: Document encoding */
150     protected String JavaDoc encoding;
151
152     /**Experimental DOM Level 3 feature: Document actualEncoding */
153     protected String JavaDoc actualEncoding;
154
155     /**Experimental DOM Level 3 feature: Document version */
156     protected String JavaDoc version;
157
158     /**Experimental DOM Level 3 feature: Document standalone */
159     protected boolean standalone;
160
161     /**Experimental DOM Level 3 feature: documentURI */
162     protected String JavaDoc fDocumentURI;
163
164     //Revisit :: change to a better data structure.
165
/** Table for user data attached to this document nodes. */
166     protected Hashtable JavaDoc userData;
167
168
169     /** Identifiers. */
170     protected Hashtable JavaDoc identifiers;
171
172     // DOM Level 3: normalizeDocument
173
transient DOMNormalizer domNormalizer = null;
174     transient DOMConfigurationImpl fConfiguration= null;
175
176     // support of XPath API
177
transient Object JavaDoc fXPathEvaluator = null;
178
179     /** Table for quick check of child insertion. */
180     private final static int[] kidOK;
181
182     /**
183      * Number of alterations made to this document since its creation.
184      * Serves as a "dirty bit" so that live objects such as NodeList can
185      * recognize when an alteration has been made and discard its cached
186      * state information.
187      * <p>
188      * Any method that alters the tree structure MUST cause or be
189      * accompanied by a call to changed(), to inform it that any outstanding
190      * NodeLists may have to be updated.
191      * <p>
192      * (Required because NodeList is simultaneously "live" and integer-
193      * indexed -- a bad decision in the DOM's design.)
194      * <p>
195      * Note that changes which do not affect the tree's structure -- changing
196      * the node's name, for example -- do _not_ have to call changed().
197      * <p>
198      * Alternative implementation would be to use a cryptographic
199      * Digest value rather than a count. This would have the advantage that
200      * "harmless" changes (those producing equal() trees) would not force
201      * NodeList to resynchronize. Disadvantage is that it's slightly more prone
202      * to "false negatives", though that's the difference between "wildly
203      * unlikely" and "absurdly unlikely". IF we start maintaining digests,
204      * we should consider taking advantage of them.
205      *
206      * Note: This used to be done a node basis, so that we knew what
207      * subtree changed. But since only DeepNodeList really use this today,
208      * the gain appears to be really small compared to the cost of having
209      * an int on every (parent) node plus having to walk up the tree all the
210      * way to the root to mark the branch as changed everytime a node is
211      * changed.
212      * So we now have a single counter global to the document. It means that
213      * some objects may flush their cache more often than necessary, but this
214      * makes nodes smaller and only the document needs to be marked as changed.
215      */

216     protected int changes = 0;
217
218     // experimental
219

220     /** Allow grammar access. */
221     protected boolean allowGrammarAccess;
222
223     /** Bypass error checking. */
224     protected boolean errorChecking = true;
225
226     //Did version change at any point when the document was created ?
227
//this field helps us to optimize when normalizingDocument.
228
protected boolean xmlVersionChanged = false ;
229
230     /** The following are required for compareDocumentPosition
231      */

232     // Document number. Documents are ordered across the implementation using
233
// positive integer values. Documents are assigned numbers on demand.
234
private int documentNumber=0;
235     // Node counter and table. Used to assign numbers to nodes for this
236
// document. Node number values are negative integers. Nodes are
237
// assigned numbers on demand.
238
private int nodeCounter = 0;
239     private Hashtable JavaDoc nodeTable;
240     private boolean xml11Version = false; //by default 1.0
241
//
242
// Static initialization
243
//
244

245     static {
246
247         kidOK = new int[13];
248
249         kidOK[DOCUMENT_NODE] =
250         1 << ELEMENT_NODE | 1 << PROCESSING_INSTRUCTION_NODE |
251         1 << COMMENT_NODE | 1 << DOCUMENT_TYPE_NODE;
252
253         kidOK[DOCUMENT_FRAGMENT_NODE] =
254         kidOK[ENTITY_NODE] =
255         kidOK[ENTITY_REFERENCE_NODE] =
256         kidOK[ELEMENT_NODE] =
257         1 << ELEMENT_NODE | 1 << PROCESSING_INSTRUCTION_NODE |
258         1 << COMMENT_NODE | 1 << TEXT_NODE |
259         1 << CDATA_SECTION_NODE | 1 << ENTITY_REFERENCE_NODE ;
260
261
262         kidOK[ATTRIBUTE_NODE] =
263         1 << TEXT_NODE | 1 << ENTITY_REFERENCE_NODE;
264
265         kidOK[DOCUMENT_TYPE_NODE] =
266         kidOK[PROCESSING_INSTRUCTION_NODE] =
267         kidOK[COMMENT_NODE] =
268         kidOK[TEXT_NODE] =
269         kidOK[CDATA_SECTION_NODE] =
270         kidOK[NOTATION_NODE] =
271         0;
272
273     } // static
274

275     //
276
// Constructors
277
//
278

279     /**
280      * NON-DOM: Actually creating a Document is outside the DOM's spec,
281      * since it has to operate in terms of a particular implementation.
282      */

283     public CoreDocumentImpl() {
284         this(false);
285     }
286
287     /** Constructor. */
288     public CoreDocumentImpl(boolean grammarAccess) {
289         super(null);
290         ownerDocument = this;
291         allowGrammarAccess = grammarAccess;
292     }
293
294     /**
295      * For DOM2 support.
296      * The createDocument factory method is in DOMImplementation.
297      */

298     public CoreDocumentImpl(DocumentType JavaDoc doctype) {
299         this(doctype, false);
300     }
301
302     /** For DOM2 support. */
303     public CoreDocumentImpl(DocumentType JavaDoc doctype, boolean grammarAccess) {
304         this(grammarAccess);
305         if (doctype != null) {
306             DocumentTypeImpl doctypeImpl;
307             try {
308                 doctypeImpl = (DocumentTypeImpl) doctype;
309             } catch (ClassCastException JavaDoc e) {
310                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
311                 throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
312             }
313             doctypeImpl.ownerDocument = this;
314             appendChild(doctype);
315         }
316     }
317
318     //
319
// Node methods
320
//
321

322     // even though ownerDocument refers to this in this implementation
323
// the DOM Level 2 spec says it must be null, so make it appear so
324
final public Document JavaDoc getOwnerDocument() {
325         return null;
326     }
327
328     /** Returns the node type. */
329     public short getNodeType() {
330         return Node.DOCUMENT_NODE;
331     }
332
333     /** Returns the node name. */
334     public String JavaDoc getNodeName() {
335         return "#document";
336     }
337
338     /**
339      * Deep-clone a document, including fixing ownerDoc for the cloned
340      * children. Note that this requires bypassing the WRONG_DOCUMENT_ERR
341      * protection. I've chosen to implement it by calling importNode
342      * which is DOM Level 2.
343      *
344      * @return org.w3c.dom.Node
345      * @param deep boolean, iff true replicate children
346      */

347     public Node JavaDoc cloneNode(boolean deep) {
348
349         CoreDocumentImpl newdoc = new CoreDocumentImpl();
350         callUserDataHandlers(this, newdoc, UserDataHandler.NODE_CLONED);
351         cloneNode(newdoc, deep);
352
353         return newdoc;
354
355     } // cloneNode(boolean):Node
356

357
358     /**
359      * internal method to share code with subclass
360      **/

361     protected void cloneNode(CoreDocumentImpl newdoc, boolean deep) {
362
363         // clone the children by importing them
364
if (needsSyncChildren()) {
365             synchronizeChildren();
366         }
367
368         if (deep) {
369             Hashtable JavaDoc reversedIdentifiers = null;
370
371             if (identifiers != null) {
372                 // Build a reverse mapping from element to identifier.
373
reversedIdentifiers = new Hashtable JavaDoc();
374                 Enumeration JavaDoc elementIds = identifiers.keys();
375                 while (elementIds.hasMoreElements()) {
376                     Object JavaDoc elementId = elementIds.nextElement();
377                     reversedIdentifiers.put(identifiers.get(elementId),
378                     elementId);
379                 }
380             }
381
382             // Copy children into new document.
383
for (ChildNode kid = firstChild; kid != null;
384             kid = kid.nextSibling) {
385                 newdoc.appendChild(newdoc.importNode(kid, true, true,
386                 reversedIdentifiers));
387             }
388         }
389
390         // experimental
391
newdoc.allowGrammarAccess = allowGrammarAccess;
392         newdoc.errorChecking = errorChecking;
393
394     } // cloneNode(CoreDocumentImpl,boolean):void
395

396     /**
397      * Since a Document may contain at most one top-level Element child,
398      * and at most one DocumentType declaraction, we need to subclass our
399      * add-children methods to implement this constraint.
400      * Since appendChild() is implemented as insertBefore(,null),
401      * altering the latter fixes both.
402      * <p>
403      * While I'm doing so, I've taken advantage of the opportunity to
404      * cache documentElement and docType so we don't have to
405      * search for them.
406      *
407      * REVISIT: According to the spec it is not allowed to alter neither the
408      * document element nor the document type in any way
409      */

410     public Node JavaDoc insertBefore(Node JavaDoc newChild, Node JavaDoc refChild)
411     throws DOMException JavaDoc {
412
413         // Only one such child permitted
414
int type = newChild.getNodeType();
415         if (errorChecking) {
416             if((type == Node.ELEMENT_NODE && docElement != null) ||
417             (type == Node.DOCUMENT_TYPE_NODE && docType != null)) {
418                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null);
419                 throw new DOMException JavaDoc(DOMException.HIERARCHY_REQUEST_ERR, msg);
420             }
421         }
422         // Adopt orphan doctypes
423
if (newChild.getOwnerDocument() == null &&
424         newChild instanceof DocumentTypeImpl) {
425             ((DocumentTypeImpl) newChild).ownerDocument = this;
426         }
427         super.insertBefore(newChild,refChild);
428
429         // If insert succeeded, cache the kid appropriately
430
if (type == Node.ELEMENT_NODE) {
431             docElement = (ElementImpl)newChild;
432         }
433         else if (type == Node.DOCUMENT_TYPE_NODE) {
434             docType = (DocumentTypeImpl)newChild;
435         }
436
437         return newChild;
438
439     } // insertBefore(Node,Node):Node
440

441     /**
442      * Since insertBefore caches the docElement (and, currently, docType),
443      * removeChild has to know how to undo the cache
444      *
445      * REVISIT: According to the spec it is not allowed to alter neither the
446      * document element nor the document type in any way
447      */

448     public Node JavaDoc removeChild(Node JavaDoc oldChild) throws DOMException JavaDoc {
449
450         super.removeChild(oldChild);
451
452         // If remove succeeded, un-cache the kid appropriately
453
int type = oldChild.getNodeType();
454         if(type == Node.ELEMENT_NODE) {
455             docElement = null;
456         }
457         else if (type == Node.DOCUMENT_TYPE_NODE) {
458             docType = null;
459         }
460
461         return oldChild;
462
463     } // removeChild(Node):Node
464

465     /**
466      * Since we cache the docElement (and, currently, docType),
467      * replaceChild has to update the cache
468      *
469      * REVISIT: According to the spec it is not allowed to alter neither the
470      * document element nor the document type in any way
471      */

472     public Node JavaDoc replaceChild(Node JavaDoc newChild, Node JavaDoc oldChild)
473     throws DOMException JavaDoc {
474
475         // Adopt orphan doctypes
476
if (newChild.getOwnerDocument() == null &&
477         newChild instanceof DocumentTypeImpl) {
478             ((DocumentTypeImpl) newChild).ownerDocument = this;
479         }
480         int type = oldChild.getNodeType();
481         int newType = newChild.getNodeType();
482         if (errorChecking &&((docType != null &&
483             oldChild.getNodeType() != Node.DOCUMENT_TYPE_NODE &&
484             newChild.getNodeType() == Node.DOCUMENT_TYPE_NODE)
485             || (docElement != null &&
486             oldChild.getNodeType() != Node.ELEMENT_NODE &&
487             newChild.getNodeType() == Node.ELEMENT_NODE))) {
488                 throw new DOMException JavaDoc(
489                 DOMException.HIERARCHY_REQUEST_ERR,
490                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null));
491         }
492         super.replaceChild(newChild, oldChild);
493
494         if(type == Node.ELEMENT_NODE) {
495             docElement = (ElementImpl)newChild;
496         }
497         else if (type == Node.DOCUMENT_TYPE_NODE) {
498             docType = (DocumentTypeImpl)newChild;
499         }
500         return oldChild;
501     } // replaceChild(Node,Node):Node
502

503     /*
504      * Get Node text content
505      * @since DOM Level 3
506      */

507     public String JavaDoc getTextContent() throws DOMException JavaDoc {
508         return null;
509     }
510
511     /*
512      * Set Node text content
513      * @since DOM Level 3
514      */

515     public void setTextContent(String JavaDoc textContent)
516     throws DOMException JavaDoc {
517         // no-op
518
}
519
520     /**
521      * @since DOM Level 3
522      */

523     public Object JavaDoc getFeature(String JavaDoc feature, String JavaDoc version) {
524         
525         boolean anyVersion = version == null || version.length() == 0;
526         
527         if ((feature.equalsIgnoreCase("XPath")
528             || feature.equalsIgnoreCase("+XPath")) &&
529             (anyVersion || version.equals("3.0"))) {
530
531             try {
532                 Class JavaDoc xpathClass = ObjectFactory.findProviderClass(
533                 "com.sun.org.apache.xpath.internal.domapi.XPathEvaluatorImpl",
534                 ObjectFactory.findClassLoader(), true);
535                 fXPathEvaluator = xpathClass.newInstance();
536                 java.lang.reflect.Method JavaDoc setDocument = xpathClass.getMethod("setDoc", new Class JavaDoc[]{Document JavaDoc.class});
537                 setDocument.invoke(fXPathEvaluator, new Object JavaDoc[]{this});
538                 return fXPathEvaluator;
539             }
540             catch (Exception JavaDoc e){
541                 return null;
542             }
543         }
544         return super.getFeature(feature, version);
545     }
546
547     //
548
// Document methods
549
//
550

551     // factory methods
552

553     /**
554      * Factory method; creates an Attribute having this Document as its
555      * OwnerDoc.
556      *
557      * @param name The name of the attribute. Note that the attribute's value
558      * is _not_ established at the factory; remember to set it!
559      *
560      * @throws DOMException(INVALID_NAME_ERR) if the attribute name is not
561      * acceptable.
562      */

563     public Attr JavaDoc createAttribute(String JavaDoc name)
564     throws DOMException JavaDoc {
565
566         if (errorChecking && !isXMLName(name,xml11Version)) {
567             String JavaDoc msg =
568                 DOMMessageFormatter.formatMessage(
569                     DOMMessageFormatter.DOM_DOMAIN,
570                     "INVALID_CHARACTER_ERR",
571                     null);
572             throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR, msg);
573         }
574         return new AttrImpl(this, name);
575
576     } // createAttribute(String):Attr
577

578     /**
579      * Factory method; creates a CDATASection having this Document as
580      * its OwnerDoc.
581      *
582      * @param data The initial contents of the CDATA
583      *
584      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents. (HTML
585      * not yet implemented.)
586      */

587     public CDATASection JavaDoc createCDATASection(String JavaDoc data)
588     throws DOMException JavaDoc {
589         return new CDATASectionImpl(this, data);
590     }
591
592     /**
593      * Factory method; creates a Comment having this Document as its
594      * OwnerDoc.
595      *
596      * @param data The initial contents of the Comment. */

597     public Comment JavaDoc createComment(String JavaDoc data) {
598         return new CommentImpl(this, data);
599     }
600
601     /**
602      * Factory method; creates a DocumentFragment having this Document
603      * as its OwnerDoc.
604      */

605     public DocumentFragment JavaDoc createDocumentFragment() {
606         return new DocumentFragmentImpl(this);
607     }
608
609     /**
610      * Factory method; creates an Element having this Document
611      * as its OwnerDoc.
612      *
613      * @param tagName The name of the element type to instantiate. For
614      * XML, this is case-sensitive. For HTML, the tagName parameter may
615      * be provided in any case, but it must be mapped to the canonical
616      * uppercase form by the DOM implementation.
617      *
618      * @throws DOMException(INVALID_NAME_ERR) if the tag name is not
619      * acceptable.
620      */

621     public Element JavaDoc createElement(String JavaDoc tagName)
622     throws DOMException JavaDoc {
623
624         if (errorChecking && !isXMLName(tagName,xml11Version)) {
625             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
626             throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR, msg);
627         }
628         return new ElementImpl(this, tagName);
629
630     } // createElement(String):Element
631

632     /**
633      * Factory method; creates an EntityReference having this Document
634      * as its OwnerDoc.
635      *
636      * @param name The name of the Entity we wish to refer to
637      *
638      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
639      * nonstandard entities are not permitted. (HTML not yet
640      * implemented.)
641      */

642     public EntityReference JavaDoc createEntityReference(String JavaDoc name)
643     throws DOMException JavaDoc {
644
645         if (errorChecking && !isXMLName(name,xml11Version)) {
646             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
647             throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR, msg);
648         }
649         return new EntityReferenceImpl(this, name);
650
651     } // createEntityReference(String):EntityReference
652

653     /**
654      * Factory method; creates a ProcessingInstruction having this Document
655      * as its OwnerDoc.
656      *
657      * @param target The target "processor channel"
658      * @param data Parameter string to be passed to the target.
659      *
660      * @throws DOMException(INVALID_NAME_ERR) if the target name is not
661      * acceptable.
662      *
663      * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents. (HTML
664      * not yet implemented.)
665      */

666     public ProcessingInstruction JavaDoc createProcessingInstruction(String JavaDoc target,
667     String JavaDoc data)
668     throws DOMException JavaDoc {
669
670         if (errorChecking && !isXMLName(target,xml11Version)) {
671             String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
672             throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR, msg);
673         }
674         return new ProcessingInstructionImpl(this, target, data);
675
676     } // createProcessingInstruction(String,String):ProcessingInstruction
677

678     /**
679      * Factory method; creates a Text node having this Document as its
680      * OwnerDoc.
681      *
682      * @param data The initial contents of the Text.
683      */

684     public Text JavaDoc createTextNode(String JavaDoc data) {
685         return new TextImpl(this, data);
686     }
687
688     // other document methods
689

690     /**
691      * For XML, this provides access to the Document Type Definition.
692      * For HTML documents, and XML documents which don't specify a DTD,
693      * it will be null.
694      */

695     public DocumentType JavaDoc getDoctype() {
696         if (needsSyncChildren()) {
697             synchronizeChildren();
698         }
699         return docType;
700     }
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      */

712     public Element JavaDoc 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      */

728     public NodeList JavaDoc getElementsByTagName(String JavaDoc 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      */

738     public DOMImplementation JavaDoc 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
769     public void setErrorChecking(boolean check) {
770         errorChecking = check;
771
772     }
773
774     /*
775      * DOM Level 3 WD - Experimental.
776      */

777     public void setStrictErrorChecking(boolean check) {
778         errorChecking = check;
779     }
780
781     /**
782      * Returns true if the DOM implementation performs error checking.
783      */

784     public boolean getErrorChecking() {
785         return errorChecking;
786     }
787
788     /*
789      * DOM Level 3 WD - Experimental.
790      */

791     public boolean getStrictErrorChecking() {
792         return errorChecking;
793     }
794
795
796     /**
797      * DOM Level 3 CR - Experimental. (Was getActualEncoding)
798      *
799      * An attribute specifying the encoding used for this document
800      * at the time of the parsing. This is <code>null</code> when
801      * it is not known, such as when the <code>Document</code> was
802      * created in memory.
803      * @since DOM Level 3
804      */

805     public String JavaDoc getInputEncoding() {
806         return actualEncoding;
807     }
808
809     /**
810      * DOM Internal
811      * (Was a DOM L3 Core WD public interface method setActualEncoding )
812      *
813      * An attribute specifying the actual encoding of this document. This is
814      * <code>null</code> otherwise.
815      * <br> This attribute represents the property [character encoding scheme]
816      * defined in .
817      */

818     public void setInputEncoding(String JavaDoc value) {
819         actualEncoding = value;
820     }
821
822     /**
823      * DOM Internal
824      * (Was a DOM L3 Core WD public interface method setXMLEncoding )
825      *
826      * An attribute specifying, as part of the XML declaration,
827      * the encoding of this document. This is null when unspecified.
828      */

829     public void setXmlEncoding(String JavaDoc value) {
830         encoding = value;
831     }
832
833     /**
834      * DOM Level 3 WD - Experimental.
835      * The encoding of this document (part of XML Declaration)
836      */

837     public String JavaDoc getXmlEncoding() {
838         return encoding;
839     }
840
841     /**
842      * DOM Level 3 CR - Experimental.
843      * version - An attribute specifying, as part of the XML declaration,
844      * the version number of this document.
845      */

846     public void setXmlVersion(String JavaDoc value) {
847         if(value.equals("1.0") || value.equals("1.1")){
848             //we need to change the flag value only --
849
// when the version set is different than already set.
850
if(!getXmlVersion().equals(value)){
851                 xmlVersionChanged = true ;
852                 //change the normalization value back to false
853
isNormalized(false);
854                 version = value;
855             }
856         }
857         else{
858             //NOT_SUPPORTED_ERR: Raised if the vesion is set to a value that is not supported by
859
//this document
860
//we dont support any other XML version
861
String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
862             throw new DOMException JavaDoc(DOMException.NOT_SUPPORTED_ERR, msg);
863
864         }
865         if((getXmlVersion()).equals("1.1")){
866             xml11Version = true;
867         }
868         else{
869             xml11Version = false;
870         }
871     }
872
873     /**
874      * DOM Level 3 WD - Experimental.
875      * The version of this document (part of XML Declaration)
876      */

877     public String JavaDoc getXmlVersion() {
878         return (version == null)?"1.0":version;
879     }
880
881     /**
882      * DOM Level 3 CR - Experimental.
883      *
884      * Xmlstandalone - An attribute specifying, as part of the XML declaration,
885      * whether this document is standalone
886      * @exception DOMException
887      * NOT_SUPPORTED_ERR: Raised if this document does not support the
888      * "XML" feature.
889      * @since DOM Level 3
890      */

891     public void setXmlStandalone(boolean value)
892                                   throws DOMException JavaDoc {
893             standalone = value;
894     }
895
896     /**
897      * DOM Level 3 WD - Experimental.
898      * standalone that specifies whether this document is standalone
899      * (part of XML Declaration)
900      */

901     public boolean getXmlStandalone() {
902         return standalone;
903     }
904
905
906     /**
907      * DOM Level 3 WD - Experimental.
908      * The location of the document or <code>null</code> if undefined.
909      * <br>Beware that when the <code>Document</code> supports the feature
910      * "HTML" , the href attribute of the HTML BASE element takes precedence
911      * over this attribute.
912      * @since DOM Level 3
913      */

914     public String JavaDoc getDocumentURI(){
915         return fDocumentURI;
916     }
917
918
919     /**
920      * DOM Level 3 WD - Experimental.
921      * Renaming node
922      */

923     public Node JavaDoc renameNode(Node JavaDoc n,String JavaDoc namespaceURI,String JavaDoc name)
924     throws DOMException JavaDoc{
925
926         if (n.getOwnerDocument() != this && n != this) {
927             String JavaDoc msg = DOMMessageFormatter.formatMessage(
928             DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
929             throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
930         }
931         switch (n.getNodeType()) {
932             case ELEMENT_NODE: {
933                 ElementImpl el = (ElementImpl) n;
934                 if (el instanceof ElementNSImpl) {
935                     ((ElementNSImpl) el).rename(namespaceURI, name);
936                     
937                     // fire user data NODE_RENAMED event
938
callUserDataHandlers(el, null,
939                     UserDataHandler.NODE_RENAMED);
940                 }
941                 else {
942                     if (namespaceURI == null) {
943                         int colon1 = name.indexOf(':');
944                         if(colon1 != -1){
945                             String JavaDoc msg =
946                             DOMMessageFormatter.formatMessage(
947                             DOMMessageFormatter.DOM_DOMAIN,
948                             "NAMESPACE_ERR",
949                             null);
950                             throw new DOMException JavaDoc(DOMException.NAMESPACE_ERR, msg);
951                         }
952                         if (errorChecking && !isXMLName(name,xml11Version)) {
953                             String JavaDoc msg = DOMMessageFormatter.formatMessage(
954                             DOMMessageFormatter.DOM_DOMAIN,
955                             "INVALID_CHARACTER_ERR", null);
956                             throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR,
957                             msg);
958                         }
959                         el.rename(name);
960                         
961                         // fire user data NODE_RENAMED event
962
callUserDataHandlers(el, null,
963                         UserDataHandler.NODE_RENAMED);
964                     }
965                     else {
966                         // we need to create a new object
967
ElementNSImpl nel =
968                         new ElementNSImpl(this, namespaceURI, name);
969
970                         // register event listeners on new node
971
copyEventListeners(el, nel);
972
973                         // remove user data from old node
974
Hashtable JavaDoc data = removeUserDataTable(el);
975
976                         // remove old node from parent if any
977
Node JavaDoc parent = el.getParentNode();
978                         Node JavaDoc nextSib = el.getNextSibling();
979                         if (parent != null) {
980                             parent.removeChild(el);
981                         }
982                         // move children to new node
983
Node JavaDoc child = el.getFirstChild();
984                         while (child != null) {
985                             el.removeChild(child);
986                             nel.appendChild(child);
987                             child = el.getFirstChild();
988                         }
989                         // move specified attributes to new node
990
nel.moveSpecifiedAttributes(el);
991
992                         // attach user data to new node
993
setUserDataTable(nel, data);
994
995                         // and fire user data NODE_RENAMED event
996
callUserDataHandlers(el, nel,
997                         UserDataHandler.NODE_RENAMED);
998
999                         // insert new node where old one was
1000
if (parent != null) {
1001                            parent.insertBefore(nel, nextSib);
1002                        }
1003                        el = nel;
1004                    }
1005                }
1006                // fire ElementNameChanged event
1007
renamedElement((Element JavaDoc) n, el);
1008                return el;
1009            }
1010            case ATTRIBUTE_NODE: {
1011                AttrImpl at = (AttrImpl) n;
1012
1013                // dettach attr from element
1014
Element JavaDoc el = at.getOwnerElement();
1015                if (el != null) {
1016                    el.removeAttributeNode(at);
1017                }
1018                if (n instanceof AttrNSImpl) {
1019                    ((AttrNSImpl) at).rename(namespaceURI, name);
1020                    // reattach attr to element
1021
if (el != null) {
1022                        el.setAttributeNodeNS(at);
1023                    }
1024                    
1025                    // fire user data NODE_RENAMED event
1026
callUserDataHandlers(at, null,
1027                    UserDataHandler.NODE_RENAMED);
1028                }
1029                else {
1030                    if (namespaceURI == null) {
1031                        at.rename(name);
1032                        // reattach attr to element
1033
if (el != null) {
1034                            el.setAttributeNode(at);
1035                        }
1036                        
1037                        // fire user data NODE_RENAMED event
1038
callUserDataHandlers(at, null,
1039                        UserDataHandler.NODE_RENAMED);
1040                    }
1041                    else {
1042                        // we need to create a new object
1043
AttrNSImpl nat =
1044                        new AttrNSImpl(this, namespaceURI, name);
1045
1046                        // register event listeners on new node
1047
copyEventListeners(at, nat);
1048
1049                        // remove user data from old node
1050
Hashtable JavaDoc data = removeUserDataTable(at);
1051
1052                        // move children to new node
1053
Node JavaDoc child = at.getFirstChild();
1054                        while (child != null) {
1055                            at.removeChild(child);
1056                            nat.appendChild(child);
1057                            child = at.getFirstChild();
1058                        }
1059
1060                        // attach user data to new node
1061
setUserDataTable(nat, data);
1062
1063                        // and fire user data NODE_RENAMED event
1064
callUserDataHandlers(at, nat,
1065                        UserDataHandler.NODE_RENAMED);
1066
1067                        // reattach attr to element
1068
if (el != null) {
1069                            el.setAttributeNode(nat);
1070                        }
1071                        at = nat;
1072                    }
1073                }
1074                // fire AttributeNameChanged event
1075
renamedAttrNode((Attr JavaDoc) n, at);
1076
1077                return at;
1078            }
1079            default: {
1080                String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1081                throw new DOMException JavaDoc(DOMException.NOT_SUPPORTED_ERR, msg);
1082            }
1083        }
1084
1085    }
1086
1087
1088    /**
1089     * DOM Level 3 WD - Experimental
1090     * Normalize document.
1091     */

1092    public void normalizeDocument(){
1093        // No need to normalize if already normalized.
1094
if (isNormalized() && !isNormalizeDocRequired()) {
1095            return;
1096        }
1097        if (needsSyncChildren()) {
1098            synchronizeChildren();
1099        }
1100
1101        if (domNormalizer == null) {
1102            domNormalizer = new DOMNormalizer();
1103        }
1104
1105        if (fConfiguration == null) {
1106            fConfiguration = new DOMConfigurationImpl();
1107        }
1108        else {
1109            fConfiguration.reset();
1110        }
1111
1112        domNormalizer.normalizeDocument(this, fConfiguration);
1113        isNormalized(true);
1114        //set the XMLversion changed value to false -- once we have finished
1115
//doing normalization
1116
xmlVersionChanged = false ;
1117    }
1118
1119
1120    /**
1121     * DOM Level 3 CR - Experimental
1122     *
1123     * The configuration used when <code>Document.normalizeDocument</code> is
1124     * invoked.
1125     * @since DOM Level 3
1126     */

1127    public DOMConfiguration JavaDoc getDomConfig(){
1128        if (fConfiguration == null) {
1129            fConfiguration = new DOMConfigurationImpl();
1130        }
1131        return fConfiguration;
1132    }
1133
1134
1135    /**
1136     * DOM Level 3 WD - Experimental.
1137     * Retrieve baseURI
1138     */

1139    public String JavaDoc getBaseURI() {
1140        return fDocumentURI;
1141    }
1142
1143    /**
1144     * DOM Level 3 WD - Experimental.
1145     */

1146    public void setDocumentURI(String JavaDoc documentURI){
1147        fDocumentURI = documentURI;
1148    }
1149
1150
1151    //
1152
// DOM L3 LS
1153
//
1154
/**
1155     * DOM Level 3 WD - Experimental.
1156     * Indicates whether the method load should be synchronous or
1157     * asynchronous. When the async attribute is set to <code>true</code>
1158     * the load method returns control to the caller before the document has
1159     * completed loading. The default value of this property is
1160     * <code>false</code>.
1161     * <br>Setting the value of this attribute might throw NOT_SUPPORTED_ERR
1162     * if the implementation doesn't support the mode the attribute is being
1163     * set to. Should the DOM spec define the default value of this
1164     * property? What if implementing both async and sync IO is impractical
1165     * in some systems? 2001-09-14. default is <code>false</code> but we
1166     * need to check with Mozilla and IE.
1167     */

1168    public boolean getAsync() {
1169        return false;
1170    }
1171
1172    /**
1173     * DOM Level 3 WD - Experimental.
1174     * Indicates whether the method load should be synchronous or
1175     * asynchronous. When the async attribute is set to <code>true</code>
1176     * the load method returns control to the caller before the document has
1177     * completed loading. The default value of this property is
1178     * <code>false</code>.
1179     * <br>Setting the value of this attribute might throw NOT_SUPPORTED_ERR
1180     * if the implementation doesn't support the mode the attribute is being
1181     * set to. Should the DOM spec define the default value of this
1182     * property? What if implementing both async and sync IO is impractical
1183     * in some systems? 2001-09-14. default is <code>false</code> but we
1184     * need to check with Mozilla and IE.
1185     */

1186    public void setAsync(boolean async) {
1187        if (async) {
1188            String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1189            throw new DOMException JavaDoc(DOMException.NOT_SUPPORTED_ERR, msg);
1190        }
1191    }
1192    /**
1193     * DOM Level 3 WD - Experimental.
1194     * If the document is currently being loaded as a result of the method
1195     * <code>load</code> being invoked the loading and parsing is
1196     * immediately aborted. The possibly partial result of parsing the
1197     * document is discarded and the document is cleared.
1198     */

1199    public void abort() {
1200    }
1201
1202    /**
1203     * DOM Level 3 WD - Experimental.
1204     *
1205     * Replaces the content of the document with the result of parsing the
1206     * given URI. Invoking this method will either block the caller or
1207     * return to the caller immediately depending on the value of the async
1208     * attribute. Once the document is fully loaded a "load" event (as
1209     * defined in [<a HREF='http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331'>DOM Level 3 Events</a>]
1210     * , except that the <code>Event.targetNode</code> will be the document,
1211     * not an element) will be dispatched on the document. If an error
1212     * occurs, an implementation dependent "error" event will be dispatched
1213     * on the document. If this method is called on a document that is
1214     * currently loading, the current load is interrupted and the new URI
1215     * load is initiated.
1216     * <br> When invoking this method the parameters used in the
1217     * <code>DOMParser</code> interface are assumed to have their default
1218     * values with the exception that the parameters <code>"entities"</code>
1219     * , <code>"normalize-characters"</code>,
1220     * <code>"check-character-normalization"</code> are set to
1221     * <code>"false"</code>.
1222     * <br> The result of a call to this method is the same the result of a
1223     * call to <code>DOMParser.parseWithContext</code> with an input stream
1224     * referencing the URI that was passed to this call, the document as the
1225     * context node, and the action <code>ACTION_REPLACE_CHILDREN</code>.
1226     * @param uri The URI reference for the XML file to be loaded. If this is
1227     * a relative URI, the base URI used by the implementation is
1228     * implementation dependent.
1229     * @return If async is set to <code>true</code> <code>load</code> returns
1230     * <code>true</code> if the document load was successfully initiated.
1231     * If an error occurred when initiating the document load,
1232     * <code>load</code> returns <code>false</code>.If async is set to
1233     * <code>false</code> <code>load</code> returns <code>true</code> if
1234     * the document was successfully loaded and parsed. If an error
1235     * occurred when either loading or parsing the URI, <code>load</code>
1236     * returns <code>false</code>.
1237     */

1238    public boolean load(String JavaDoc uri) {
1239        return false;
1240    }
1241
1242    /**
1243     * DOM Level 3 WD - Experimental.
1244     * Replace the content of the document with the result of parsing the
1245     * input string, this method is always synchronous.
1246     * @param source A string containing an XML document.
1247     * @return <code>true</code> if parsing the input string succeeded
1248     * without errors, otherwise <code>false</code>.
1249     */

1250    public boolean loadXML(String JavaDoc source) {
1251        return false;
1252    }
1253
1254    /**
1255     * DOM Level 3 WD - Experimental.
1256     * Save the document or the given node and all its descendants to a string
1257     * (i.e. serialize the document or node).
1258     * <br>The parameters used in the <code>LSSerializer</code> interface are
1259     * assumed to have their default values when invoking this method.
1260     * <br> The result of a call to this method is the same the result of a
1261     * call to <code>LSSerializer.writeToString</code> with the document as
1262     * the node to write.
1263     * @param node Specifies what to serialize, if this parameter is
1264     * <code>null</code> the whole document is serialized, if it's
1265     * non-null the given node is serialized.
1266     * @return The serialized document or <code>null</code> in case an error
1267     * occurred.
1268     * @exception DOMException
1269     * WRONG_DOCUMENT_ERR: Raised if the node passed in as the node
1270     * parameter is from an other document.
1271     */

1272    public String JavaDoc saveXML(Node JavaDoc node)
1273    throws DOMException JavaDoc {
1274        if ( node != null &&
1275        this != node.getOwnerDocument() ) {
1276            String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null);
1277            throw new DOMException JavaDoc(DOMException.WRONG_DOCUMENT_ERR, msg);
1278        }
1279        DOMImplementationLS JavaDoc domImplLS = (DOMImplementationLS JavaDoc)DOMImplementationImpl.getDOMImplementation();
1280        LSSerializer JavaDoc xmlWriter = domImplLS.createLSSerializer();
1281        if (node == null) {
1282            node = this;
1283        }
1284        return xmlWriter.writeToString(node);
1285    }
1286
1287
1288    /**
1289     * Sets whether the DOM implementation generates mutation events
1290     * upon operations.
1291     */

1292    void setMutationEvents(boolean set) {
1293        // does nothing by default - overidden in subclass
1294
}
1295
1296    /**
1297     * Returns true if the DOM implementation generates mutation events.
1298     */

1299    boolean getMutationEvents() {
1300        // does nothing by default - overriden in subclass
1301
return false;
1302    }
1303
1304
1305
1306    // non-DOM factory methods
1307

1308    /**
1309     * NON-DOM
1310     * Factory method; creates a DocumentType having this Document
1311     * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
1312     * DTD information unspecified.)
1313     *
1314     * @param name The name of the Entity we wish to provide a value for.
1315     *
1316     * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
1317     * DTDs are not permitted. (HTML not yet implemented.)
1318     */

1319    public DocumentType JavaDoc createDocumentType(String JavaDoc qualifiedName,
1320    String JavaDoc publicID,
1321    String JavaDoc systemID)
1322    throws DOMException JavaDoc {
1323
1324        return new DocumentTypeImpl(this, qualifiedName, publicID, systemID);
1325
1326    } // createDocumentType(String):DocumentType
1327

1328    /**
1329     * NON-DOM
1330     * Factory method; creates an Entity having this Document
1331     * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
1332     * DTD information unspecified.)
1333     *
1334     * @param name The name of the Entity we wish to provide a value for.
1335     *
1336     * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
1337     * nonstandard entities are not permitted. (HTML not yet
1338     * implemented.)
1339     */

1340    public Entity JavaDoc createEntity(String JavaDoc name)
1341    throws DOMException JavaDoc {
1342
1343
1344        if (errorChecking && !isXMLName(name,xml11Version)) {
1345            String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
1346            throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR, msg);
1347        }
1348        return new EntityImpl(this, name);
1349
1350    } // createEntity(String):Entity
1351

1352    /**
1353     * NON-DOM
1354     * Factory method; creates a Notation having this Document
1355     * as its OwnerDoc. (REC-DOM-Level-1-19981001 left the process of building
1356     * DTD information unspecified.)
1357     *
1358     * @param name The name of the Notation we wish to describe
1359     *
1360     * @throws DOMException(NOT_SUPPORTED_ERR) for HTML documents, where
1361     * notations are not permitted. (HTML not yet
1362     * implemented.)
1363     */

1364    public Notation JavaDoc createNotation(String JavaDoc name)
1365    throws DOMException JavaDoc {
1366
1367        if (errorChecking && !isXMLName(name,xml11Version)) {
1368            String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
1369            throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR, msg);
1370        }
1371        return new NotationImpl(this, name);
1372
1373    } // createNotation(String):Notation
1374

1375    /**
1376     * NON-DOM Factory method: creates an element definition. Element
1377     * definitions hold default attribute values.
1378     */

1379    public ElementDefinitionImpl createElementDefinition(String JavaDoc name)
1380    throws DOMException JavaDoc {
1381
1382        if (errorChecking && !isXMLName(name,xml11Version)) {
1383            String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null);
1384            throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR, msg);
1385        }
1386        return new ElementDefinitionImpl(this, name);
1387
1388    } // createElementDefinition(String):ElementDefinitionImpl
1389

1390    // other non-DOM methods
1391

1392    /** NON-DOM: Get the number associated with this document. Used to
1393     * order documents in the implementation.
1394     */

1395    protected int getNodeNumber() {
1396        if (documentNumber==0) {
1397
1398            CoreDOMImplementationImpl cd = (CoreDOMImplementationImpl)CoreDOMImplementationImpl.getDOMImplementation();
1399            documentNumber = cd.assignDocumentNumber();
1400        }
1401        return documentNumber;
1402    }
1403
1404
1405    /** NON-DOM: Get a number associated with a node created with respect
1406     * to this document. Needed for compareDocumentPosition when nodes
1407     * are disconnected. This is only used on demand.
1408     */

1409    protected int getNodeNumber(Node JavaDoc node) {
1410
1411        // Check if the node is already in the hash
1412
// If so, retrieve the node number
1413
// If not, assign a number to the node
1414
// Node numbers are negative, from -1 to -n
1415
int num;
1416        if (nodeTable == null) {
1417            nodeTable = new Hashtable JavaDoc();
1418            num = --nodeCounter;
1419            nodeTable.put(node, new Integer JavaDoc(num));
1420        }
1421        else {
1422            Integer JavaDoc n = (Integer JavaDoc)nodeTable.get(node);
1423            if (n== null) {
1424                num = --nodeCounter;
1425                nodeTable.put(node, new Integer JavaDoc(num));
1426            }
1427            else
1428                num = n.intValue();
1429        }
1430        return num;
1431    }
1432
1433    /**
1434     * Copies a node from another document to this document. The new nodes are
1435     * created using this document's factory methods and are populated with the
1436     * data from the source's accessor methods defined by the DOM interfaces.
1437     * Its behavior is otherwise similar to that of cloneNode.
1438     * <p>
1439     * According to the DOM specifications, document nodes cannot be imported
1440     * and a NOT_SUPPORTED_ERR exception is thrown if attempted.
1441     */

1442    public Node JavaDoc importNode(Node JavaDoc source, boolean deep)
1443    throws DOMException JavaDoc {
1444        return importNode(source, deep, false, null);
1445    } // importNode(Node,boolean):Node
1446

1447    /**
1448     * Overloaded implementation of DOM's importNode method. This method
1449     * provides the core functionality for the public importNode and cloneNode
1450     * methods.
1451     *
1452     * The reversedIdentifiers parameter is provided for cloneNode to
1453     * preserve the document's identifiers. The Hashtable has Elements as the
1454     * keys and their identifiers as the values. When an element is being
1455     * imported, a check is done for an associated identifier. If one exists,
1456     * the identifier is registered with the new, imported element. If
1457     * reversedIdentifiers is null, the parameter is not applied.
1458     */

1459    private Node JavaDoc importNode(Node JavaDoc source, boolean deep, boolean cloningDoc,
1460    Hashtable JavaDoc reversedIdentifiers)
1461    throws DOMException JavaDoc {
1462        Node JavaDoc newnode=null;
1463        Hashtable JavaDoc userData = null;
1464
1465        // Sigh. This doesn't work; too many nodes have private data that
1466
// would have to be manually tweaked. May be able to add local
1467
// shortcuts to each nodetype. Consider ?????
1468
// if(source instanceof NodeImpl &&
1469
// !(source instanceof DocumentImpl))
1470
// {
1471
// // Can't clone DocumentImpl since it invokes us...
1472
// newnode=(NodeImpl)source.cloneNode(false);
1473
// newnode.ownerDocument=this;
1474
// }
1475
// else
1476
if(source instanceof NodeImpl)
1477            userData = ((NodeImpl)source).getUserDataRecord();
1478        int type = source.getNodeType();
1479        switch (type) {
1480            case ELEMENT_NODE: {
1481                Element JavaDoc newElement;
1482                boolean domLevel20 = source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0");
1483                // Create element according to namespace support/qualification.
1484
if(domLevel20 == false || source.getLocalName() == null)
1485                    newElement = createElement(source.getNodeName());
1486                else
1487                    newElement = createElementNS(source.getNamespaceURI(),
1488                    source.getNodeName());
1489
1490                // Copy element's attributes, if any.
1491
NamedNodeMap JavaDoc sourceAttrs = source.getAttributes();
1492                if (sourceAttrs != null) {
1493                    int length = sourceAttrs.getLength();
1494                    for (int index = 0; index < length; index++) {
1495                        Attr JavaDoc attr = (Attr JavaDoc)sourceAttrs.item(index);
1496
1497                        // NOTE: this methods is used for both importingNode
1498
// and cloning the document node. In case of the
1499
// clonning default attributes should be copied.
1500
// But for importNode defaults should be ignored.
1501
if (attr.getSpecified() || cloningDoc) {
1502                            Attr JavaDoc newAttr = (Attr JavaDoc)importNode(attr, true, cloningDoc,
1503                            reversedIdentifiers);
1504
1505                            // Attach attribute according to namespace
1506
// support/qualification.
1507
if (domLevel20 == false ||
1508                            attr.getLocalName() == null)
1509                                newElement.setAttributeNode(newAttr);
1510                            else
1511                                newElement.setAttributeNodeNS(newAttr);
1512                        }
1513                    }
1514                }
1515
1516                // Register element identifier.
1517
if (reversedIdentifiers != null) {
1518                    // Does element have an associated identifier?
1519
Object JavaDoc elementId = reversedIdentifiers.get(source);
1520                    if (elementId != null) {
1521                        if (identifiers == null)
1522                            identifiers = new Hashtable JavaDoc();
1523
1524                        identifiers.put(elementId, newElement);
1525                    }
1526                }
1527
1528                newnode = newElement;
1529                break;
1530            }
1531
1532            case ATTRIBUTE_NODE: {
1533
1534                if( source.getOwnerDocument().getImplementation().hasFeature("XML", "2.0") ){
1535                    if (source.getLocalName() == null) {
1536                        newnode = createAttribute(source.getNodeName());
1537                    } else {
1538                        newnode = createAttributeNS(source.getNamespaceURI(),
1539                        source.getNodeName());
1540                    }
1541                }
1542                else {
1543                    newnode = createAttribute(source.getNodeName());
1544                }
1545                // if source is an AttrImpl from this very same implementation
1546
// avoid creating the child nodes if possible
1547
if (source instanceof AttrImpl) {
1548                    AttrImpl attr = (AttrImpl) source;
1549                    if (attr.hasStringValue()) {
1550                        AttrImpl newattr = (AttrImpl) newnode;
1551                        newattr.setValue(attr.getValue());
1552                        deep = false;
1553                    }
1554                    else {
1555                        deep = true;
1556                    }
1557                }
1558                else {
1559                    // According to the DOM spec the kids carry the value.
1560
// However, there are non compliant implementations out
1561
// there that fail to do so. To avoid ending up with no
1562
// value at all, in this case we simply copy the text value
1563
// directly.
1564
if (source.getFirstChild() == null) {
1565                        newnode.setNodeValue(source.getNodeValue());
1566                        deep = false;
1567                    } else {
1568                        deep = true;
1569                    }
1570                }
1571                break;
1572            }
1573
1574            case TEXT_NODE: {
1575                newnode = createTextNode(source.getNodeValue());
1576                break;
1577            }
1578
1579            case CDATA_SECTION_NODE: {
1580                newnode = createCDATASection(source.getNodeValue());
1581                break;
1582            }
1583
1584            case ENTITY_REFERENCE_NODE: {
1585                newnode = createEntityReference(source.getNodeName());
1586                // the subtree is created according to this doc by the method
1587
// above, so avoid carrying over original subtree
1588
deep = false;
1589                break;
1590            }
1591
1592            case ENTITY_NODE: {
1593                Entity JavaDoc srcentity = (Entity JavaDoc)source;
1594                EntityImpl newentity =
1595                (EntityImpl)createEntity(source.getNodeName());
1596                newentity.setPublicId(srcentity.getPublicId());
1597                newentity.setSystemId(srcentity.getSystemId());
1598                newentity.setNotationName(srcentity.getNotationName());
1599                // Kids carry additional value,
1600
// allow deep import temporarily
1601
newentity.isReadOnly(false);
1602                newnode = newentity;
1603                break;
1604            }
1605
1606            case PROCESSING_INSTRUCTION_NODE: {
1607                newnode = createProcessingInstruction(source.getNodeName(),
1608                source.getNodeValue());
1609                break;
1610            }
1611
1612            case COMMENT_NODE: {
1613                newnode = createComment(source.getNodeValue());
1614                break;
1615            }
1616
1617            case DOCUMENT_TYPE_NODE: {
1618                // unless this is used as part of cloning a Document
1619
// forbid it for the sake of being compliant to the DOM spec
1620
if (!cloningDoc) {
1621                    String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1622                    throw new DOMException JavaDoc(DOMException.NOT_SUPPORTED_ERR, msg);
1623                }
1624                DocumentType JavaDoc srcdoctype = (DocumentType JavaDoc)source;
1625                DocumentTypeImpl newdoctype = (DocumentTypeImpl)
1626                createDocumentType(srcdoctype.getNodeName(),
1627                srcdoctype.getPublicId(),
1628                srcdoctype.getSystemId());
1629                // Values are on NamedNodeMaps
1630
NamedNodeMap JavaDoc smap = srcdoctype.getEntities();
1631                NamedNodeMap JavaDoc tmap = newdoctype.getEntities();
1632                if(smap != null) {
1633                    for(int i = 0; i < smap.getLength(); i++) {
1634                        tmap.setNamedItem(importNode(smap.item(i), true, true,
1635                        reversedIdentifiers));
1636                    }
1637                }
1638                smap = srcdoctype.getNotations();
1639                tmap = newdoctype.getNotations();
1640                if (smap != null) {
1641                    for(int i = 0; i < smap.getLength(); i++) {
1642                        tmap.setNamedItem(importNode(smap.item(i), true, true,
1643                        reversedIdentifiers));
1644                    }
1645                }
1646
1647                // NOTE: At this time, the DOM definition of DocumentType
1648
// doesn't cover Elements and their Attributes. domimpl's
1649
// extentions in that area will not be preserved, even if
1650
// copying from domimpl to domimpl. We could special-case
1651
// that here. Arguably we should. Consider. ?????
1652
newnode = newdoctype;
1653                break;
1654            }
1655
1656            case DOCUMENT_FRAGMENT_NODE: {
1657                newnode = createDocumentFragment();
1658                // No name, kids carry value
1659
break;
1660            }
1661
1662            case NOTATION_NODE: {
1663                Notation JavaDoc srcnotation = (Notation JavaDoc)source;
1664                NotationImpl newnotation =
1665                (NotationImpl)createNotation(source.getNodeName());
1666                newnotation.setPublicId(srcnotation.getPublicId());
1667                newnotation.setSystemId(srcnotation.getSystemId());
1668                // Kids carry additional value
1669
newnode = newnotation;
1670                // No name, no value
1671
break;
1672            }
1673            case DOCUMENT_NODE : // Can't import document nodes
1674
default: { // Unknown node type
1675
String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1676                throw new DOMException JavaDoc(DOMException.NOT_SUPPORTED_ERR, msg);
1677            }
1678        }
1679
1680        if(userData != null)
1681            callUserDataHandlers(source, newnode, UserDataHandler.NODE_IMPORTED,userData);
1682
1683        // If deep, replicate and attach the kids.
1684
if (deep) {
1685            for (Node JavaDoc srckid = source.getFirstChild();
1686            srckid != null;
1687            srckid = srckid.getNextSibling()) {
1688                newnode.appendChild(importNode(srckid, true, cloningDoc,
1689                reversedIdentifiers));
1690            }
1691        }
1692        if (newnode.getNodeType() == Node.ENTITY_NODE) {
1693            ((NodeImpl)newnode).setReadOnly(true, true);
1694        }
1695        return newnode;
1696
1697    } // importNode(Node,boolean,boolean,Hashtable):Node
1698

1699    /**
1700     * DOM Level 3 WD - Experimental
1701     * Change the node's ownerDocument, and its subtree, to this Document
1702     *
1703     * @param source The node to adopt.
1704     * @see #importNode
1705     **/

1706    public Node JavaDoc adoptNode(Node JavaDoc source) {
1707        NodeImpl node;
1708        Hashtable JavaDoc userData = null;
1709        try {
1710            node = (NodeImpl) source;
1711        } catch (ClassCastException JavaDoc e) {
1712            // source node comes from a different DOMImplementation
1713
return null;
1714        }
1715        switch (node.getNodeType()) {
1716            case ATTRIBUTE_NODE: {
1717                AttrImpl attr = (AttrImpl) node;
1718                // remove node from wherever it is
1719
if( attr.getOwnerElement() != null){
1720                    //1. owner element attribute is set to null
1721
attr.getOwnerElement().removeAttributeNode(attr);
1722                }
1723                //2. specified flag is set to true
1724
attr.isSpecified(true);
1725
1726                userData = node.getUserDataRecord();
1727
1728                //3. change ownership
1729
attr.setOwnerDocument(this);
1730                if(userData != null )
1731                    setUserDataTable(node,userData);
1732                break;
1733            }
1734            //entity, notation nodes are read only nodes.. so they can't be adopted.
1735
//runtime will fall through to NOTATION_NODE
1736
case ENTITY_NODE:
1737            case NOTATION_NODE:{
1738                String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null);
1739                throw new DOMException JavaDoc(DOMException.NO_MODIFICATION_ALLOWED_ERR, msg);
1740
1741            }
1742            //document, documentype nodes can't be adopted.
1743
//runtime will fall through to DocumentTypeNode
1744
case DOCUMENT_NODE:
1745            case DOCUMENT_TYPE_NODE: {
1746                String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null);
1747                throw new DOMException JavaDoc(DOMException.NOT_SUPPORTED_ERR, msg);
1748            }
1749            case ENTITY_REFERENCE_NODE: {
1750                userData = node.getUserDataRecord();
1751                Node JavaDoc parent = node.getParentNode();
1752                if (parent != null) {
1753                    parent.removeChild(source);
1754                }
1755                // discard its replacement value
1756
Node JavaDoc child;
1757                while ((child = node.getFirstChild()) != null) {
1758                    node.removeChild(child);
1759                }
1760                // change ownership
1761
node.setOwnerDocument(this);
1762                if(userData != null)
1763                    setUserDataTable(node,userData);
1764                // set its new replacement value if any
1765
if (docType == null) {
1766                    break;
1767                }
1768                NamedNodeMap JavaDoc entities = docType.getEntities();
1769                Node JavaDoc entityNode = entities.getNamedItem(node.getNodeName());
1770                if (entityNode == null) {
1771                    break;
1772                }
1773                EntityImpl entity = (EntityImpl) entityNode;
1774                for (child = entityNode.getFirstChild();
1775                child != null; child = child.getNextSibling()) {
1776                    Node JavaDoc childClone = child.cloneNode(true);
1777                    node.appendChild(childClone);
1778                }
1779                break;
1780            }
1781            case ELEMENT_NODE: {
1782                userData = node.getUserDataRecord();
1783                // remove node from wherever it is
1784
Node JavaDoc parent = node.getParentNode();
1785                if (parent != null) {
1786                    parent.removeChild(source);
1787                }
1788                // change ownership
1789
if(userData != null)
1790                    setUserDataTable(node,userData);
1791                node.setOwnerDocument(this);
1792                // reconcile default attributes
1793
((ElementImpl)node).reconcileDefaultAttributes();
1794                break;
1795            }
1796            default: {
1797                // remove node from wherever it is
1798
userData = node.getUserDataRecord();
1799                Node JavaDoc parent = node.getParentNode();
1800                if (parent != null) {
1801                    parent.removeChild(source);
1802                }
1803                if(userData != null)
1804                    setUserDataTable(node,userData);
1805                // change ownership
1806
node.setOwnerDocument(this);
1807                if(userData != null)
1808                    setUserDataTable(node,userData);
1809            }
1810        }
1811
1812        //DOM L3 Core CR
1813
//http://www.w3.org/TR/2003/CR-DOM-Level-3-Core-20031107/core.html#UserDataHandler-ADOPTED
1814
if(userData != null)
1815            callUserDataHandlers(source, null, UserDataHandler.NODE_ADOPTED,userData);
1816
1817        return node;
1818    }
1819
1820    // identifier maintenence
1821
/**
1822     * Introduced in DOM Level 2
1823     * Returns the Element whose ID is given by elementId. If no such element
1824     * exists, returns null. Behavior is not defined if more than one element
1825     * has this ID.
1826     * <p>
1827     * Note: The DOM implementation must have information that says which
1828     * attributes are of type ID. Attributes with the name "ID" are not of type
1829     * ID unless so defined. Implementations that do not know whether
1830     * attributes are of type ID or not are expected to return null.
1831     * @see #getIdentifier
1832     */

1833    public Element JavaDoc getElementById(String JavaDoc elementId) {
1834        return getIdentifier(elementId);
1835    }
1836
1837    /**
1838     * Remove all identifiers from the ID table
1839     */

1840    protected final void clearIdentifiers(){
1841        if (identifiers != null){
1842            identifiers.clear();
1843        }
1844    }
1845
1846    /**
1847     * Registers an identifier name with a specified element node.
1848     * If the identifier is already registered, the new element
1849     * node replaces the previous node. If the specified element
1850     * node is null, removeIdentifier() is called.
1851     *
1852     * @see #getIdentifier
1853     * @see #removeIdentifier
1854     */

1855    public void putIdentifier(String JavaDoc idName, Element JavaDoc element) {
1856
1857        if (element == null) {
1858            removeIdentifier(idName);
1859            return;
1860        }
1861
1862        if (needsSyncData()) {
1863            synchronizeData();
1864        }
1865
1866        if (identifiers == null) {
1867            identifiers = new Hashtable JavaDoc();
1868        }
1869
1870        identifiers.put(idName, element);
1871
1872    } // putIdentifier(String,Element)
1873

1874    /**
1875     * Returns a previously registered element with the specified
1876     * identifier name, or null if no element is registered.
1877     *
1878     * @see #putIdentifier
1879     * @see #removeIdentifier
1880     */

1881    public Element JavaDoc getIdentifier(String JavaDoc idName) {
1882
1883        if (needsSyncData()) {
1884            synchronizeData();
1885        }
1886
1887        if (identifiers == null) {
1888            return null;
1889        }
1890        Element JavaDoc elem = (Element JavaDoc) identifiers.get(idName);
1891        if (elem != null) {
1892            // check that the element is in the tree
1893
Node JavaDoc parent = elem.getParentNode();
1894            while (parent != null) {
1895                if (parent == this) {
1896                    return elem;
1897                }
1898                parent = parent.getParentNode();
1899            }
1900        }
1901        return null;
1902    } // getIdentifier(String):Element
1903

1904    /**
1905     * Removes a previously registered element with the specified
1906     * identifier name.
1907     *
1908     * @see #putIdentifier
1909     * @see #getIdentifier
1910     */

1911    public void removeIdentifier(String JavaDoc idName) {
1912
1913        if (needsSyncData()) {
1914            synchronizeData();
1915        }
1916
1917        if (identifiers == null) {
1918            return;
1919        }
1920
1921        identifiers.remove(idName);
1922
1923    } // removeIdentifier(String)
1924

1925    /** Returns an enumeration registered of identifier names. */
1926    public Enumeration JavaDoc getIdentifiers() {
1927
1928        if (needsSyncData()) {
1929            synchronizeData();
1930        }
1931
1932        if (identifiers == null) {
1933            identifiers = new Hashtable JavaDoc();
1934        }
1935
1936        return identifiers.keys();
1937
1938    } // getIdentifiers():Enumeration
1939

1940    //
1941
// DOM2: Namespace methods
1942
//
1943

1944    /**
1945     * Introduced in DOM Level 2. <p>
1946     * Creates an element of the given qualified name and namespace URI.
1947     * If the given namespaceURI is null or an empty string and the
1948     * qualifiedName has a prefix that is "xml", the created element
1949     * is bound to the predefined namespace
1950     * "http://www.w3.org/XML/1998/namespace" [Namespaces].
1951     * @param namespaceURI The namespace URI of the element to
1952     * create.
1953     * @param qualifiedName The qualified name of the element type to
1954     * instantiate.
1955     * @return Element A new Element object with the following attributes:
1956     * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
1957     * name contains an invalid character.
1958     * @throws DOMException NAMESPACE_ERR: Raised if the qualifiedName has a
1959     * prefix that is "xml" and the namespaceURI is
1960     * neither null nor an empty string nor
1961     * "http://www.w3.org/XML/1998/namespace", or
1962     * if the qualifiedName has a prefix different
1963     * from "xml" and the namespaceURI is null or an
1964     * empty string.
1965     * @since WD-DOM-Level-2-19990923
1966     */

1967    public Element JavaDoc createElementNS(String JavaDoc namespaceURI, String JavaDoc qualifiedName)
1968    throws DOMException JavaDoc {
1969        return new ElementNSImpl(this, namespaceURI, qualifiedName);
1970    }
1971
1972    /**
1973     * NON-DOM: a factory method used by the Xerces DOM parser
1974     * to create an element.
1975     *
1976     * @param namespaceURI The namespace URI of the element to
1977     * create.
1978     * @param qualifiedName The qualified name of the element type to
1979     * instantiate.
1980     * @param localpart The local name of the attribute to instantiate.
1981     *
1982     * @return Element A new Element object with the following attributes:
1983     * @exception DOMException INVALID_CHARACTER_ERR: Raised if the specified
1984     * name contains an invalid character.
1985     */

1986    public Element JavaDoc createElementNS(String JavaDoc namespaceURI, String JavaDoc qualifiedName,
1987    String JavaDoc localpart)
1988    throws DOMException JavaDoc {
1989        return new ElementNSImpl(this, namespaceURI, qualifiedName, localpart);
1990    }
1991
1992    /**
1993     * Introduced in DOM Level 2. <p>
1994     * Creates an attribute of the given qualified name and namespace URI.
1995     * If the given namespaceURI is null or an empty string and the
1996     * qualifiedName has a prefix that is "xml", the created element
1997     * is bound to the predefined namespace
1998     * "http://www.w3.org/XML/1998/namespace" [Namespaces].
1999     *
2000     * @param namespaceURI The namespace URI of the attribute to
2001     * create. When it is null or an empty string,
2002     * this method behaves like createAttribute.
2003     * @param qualifiedName The qualified name of the attribute to
2004     * instantiate.
2005     * @return Attr A new Attr object.
2006     * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
2007     * name contains an invalid character.
2008     * @since WD-DOM-Level-2-19990923
2009     */

2010    public Attr JavaDoc createAttributeNS(String JavaDoc namespaceURI, String JavaDoc qualifiedName)
2011    throws DOMException JavaDoc {
2012        return new AttrNSImpl(this, namespaceURI, qualifiedName);
2013    }
2014
2015    /**
2016     * NON-DOM: a factory method used by the Xerces DOM parser
2017     * to create an element.
2018     *
2019     * @param namespaceURI The namespace URI of the attribute to
2020     * create. When it is null or an empty string,
2021     * this method behaves like createAttribute.
2022     * @param qualifiedName The qualified name of the attribute to
2023     * instantiate.
2024     * @param localpart The local name of the attribute to instantiate.
2025     *
2026     * @return Attr A new Attr object.
2027     * @throws DOMException INVALID_CHARACTER_ERR: Raised if the specified
2028     * name contains an invalid character.
2029     */

2030    public Attr JavaDoc createAttributeNS(String JavaDoc namespaceURI, String JavaDoc qualifiedName,
2031    String JavaDoc localpart)
2032    throws DOMException JavaDoc {
2033        return new AttrNSImpl(this, namespaceURI, qualifiedName, localpart);
2034    }
2035
2036    /**
2037     * Introduced in DOM Level 2. <p>
2038     * Returns a NodeList of all the Elements with a given local name and
2039     * namespace URI in the order in which they would be encountered in a
2040     * preorder traversal of the Document tree.
2041     * @param namespaceURI The namespace URI of the elements to match
2042     * on. The special value "*" matches all
2043     * namespaces. When it is null or an empty
2044     * string, this method behaves like
2045     * getElementsByTagName.
2046     * @param localName The local name of the elements to match on.
2047     * The special value "*" matches all local names.
2048     * @return NodeList A new NodeList object containing all the matched
2049     * Elements.
2050     * @since WD-DOM-Level-2-19990923
2051     */

2052    public NodeList JavaDoc getElementsByTagNameNS(String JavaDoc namespaceURI,
2053    String JavaDoc localName) {
2054        return new DeepNodeListImpl(this, namespaceURI, localName);
2055    }
2056
2057    //
2058
// Object methods
2059
//
2060

2061    /** Clone. */
2062    public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
2063        CoreDocumentImpl newdoc = (CoreDocumentImpl) super.clone();
2064        newdoc.docType = null;
2065        newdoc.docElement = null;
2066        return newdoc;
2067    }
2068
2069    //
2070
// Public static methods
2071
//
2072

2073    /**
2074     * Check the string against XML's definition of acceptable names for
2075     * elements and attributes and so on using the XMLCharacterProperties
2076     * utility class
2077     */

2078
2079    public static final boolean isXMLName(String JavaDoc s, boolean xml11Version) {
2080
2081        if (s == null) {
2082            return false;
2083        }
2084        if(!xml11Version)
2085            return XMLChar.isValidName(s);
2086        else
2087            return XML11Char.isXML11ValidName(s);
2088
2089    } // isXMLName(String):boolean
2090

2091    /**
2092     * Checks if the given qualified name is legal with respect
2093     * to the version of XML to which this document must conform.
2094     *
2095     * @param prefix prefix of qualified name
2096     * @param local local part of qualified name
2097     */

2098    public static final boolean isValidQName(String JavaDoc prefix, String JavaDoc local, boolean xml11Version) {
2099
2100        // check that both prefix and local part match NCName
2101
if (local == null) return false;
2102        boolean validNCName = false;
2103
2104        if (!xml11Version) {
2105            validNCName = (prefix == null || XMLChar.isValidNCName(prefix))
2106                && XMLChar.isValidNCName(local);
2107        }
2108        else {
2109            validNCName = (prefix == null || XML11Char.isXML11ValidNCName(prefix))
2110                && XML11Char.isXML11ValidNCName(local);
2111        }
2112
2113        return validNCName;
2114    }
2115    //
2116
// Protected methods
2117
//
2118

2119    /**
2120     * Uses the kidOK lookup table to check whether the proposed
2121     * tree structure is legal.
2122     */

2123    protected boolean isKidOK(Node JavaDoc parent, Node JavaDoc child) {
2124        if (allowGrammarAccess &&
2125        parent.getNodeType() == Node.DOCUMENT_TYPE_NODE) {
2126            return child.getNodeType() == Node.ELEMENT_NODE;
2127        }
2128        return 0 != (kidOK[parent.getNodeType()] & 1 << child.getNodeType());
2129    }
2130
2131    /**
2132     * Denotes that this node has changed.
2133     */

2134    protected void changed() {
2135        changes++;
2136    }
2137
2138    /**
2139     * Returns the number of changes to this node.
2140     */

2141    protected int changes() {
2142        return changes;
2143    }
2144
2145    // NodeListCache pool
2146

2147    /**
2148     * Returns a NodeListCache for the given node.
2149     */

2150    NodeListCache getNodeListCache(ParentNode owner) {
2151        if (fFreeNLCache == null) {
2152            return new NodeListCache(owner);
2153        }
2154        NodeListCache c = fFreeNLCache;
2155        fFreeNLCache = fFreeNLCache.next;
2156        c.fChild = null;
2157        c.fChildIndex = -1;
2158        c.fLength = -1;
2159        // revoke previous ownership
2160
if (c.fOwner != null) {
2161            c.fOwner.fNodeListCache = null;
2162        }
2163        c.fOwner = owner;
2164        // c.next = null; not necessary, except for confused people...
2165
return c;
2166    }
2167
2168    /**
2169     * Puts the given NodeListCache in the free list.
2170     * Note: The owner node can keep using it until we reuse it
2171     */

2172    void freeNodeListCache(NodeListCache c) {
2173        c.next = fFreeNLCache;
2174        fFreeNLCache = c;
2175    }
2176
2177
2178
2179    /**
2180     * Associate an object to a key on this node. The object can later be
2181     * retrieved from this node by calling <code>getUserData</code> with the
2182     * same key.
2183     * @param n The node to associate the object to.
2184     * @param key The key to associate the object to.
2185     * @param data The object to associate to the given key, or
2186     * <code>null</code> to remove any existing association to that key.
2187     * @param handler The handler to associate to that key, or
2188     * <code>null</code>.
2189     * @return Returns the <code>DOMObject</code> previously associated to
2190     * the given key on this node, or <code>null</code> if there was none.
2191     * @since DOM Level 3
2192     *
2193     * REVISIT: we could use a free list of UserDataRecord here
2194     */

2195    public Object JavaDoc setUserData(Node JavaDoc n, String JavaDoc key,
2196    Object JavaDoc data, UserDataHandler JavaDoc handler) {
2197        if (data == null) {
2198            if (userData != null) {
2199                Hashtable JavaDoc t = (Hashtable JavaDoc) userData.get(n);
2200                if (t != null) {
2201                    Object JavaDoc o = t.remove(key);
2202                    if (o != null) {
2203                        UserDataRecord r = (UserDataRecord) o;
2204                        return r.fData;
2205                    }
2206                }
2207            }
2208            return null;
2209        }
2210        else {
2211            Hashtable JavaDoc t;
2212            if (userData == null) {
2213                userData = new Hashtable JavaDoc();
2214                t = new Hashtable JavaDoc();
2215                userData.put(n, t);
2216            }
2217            else {
2218                t = (Hashtable JavaDoc) userData.get(n);
2219                if (t == null) {
2220                    t = new Hashtable JavaDoc();
2221                    userData.put(n, t);
2222                }
2223            }
2224            Object JavaDoc o = t.put(key, new UserDataRecord(data, handler));
2225            if (o != null) {
2226                UserDataRecord r = (UserDataRecord) o;
2227                return r.fData;
2228            }
2229            return null;
2230        }
2231    }
2232    
2233
2234    /**
2235     * Retrieves the object associated to a key on a this node. The object
2236     * must first have been set to this node by calling
2237     * <code>setUserData</code> with the same key.
2238     * @param n The node the object is associated to.
2239     * @param key The key the object is associated to.
2240     * @return Returns the <code>DOMObject</code> associated to the given key
2241     * on this node, or <code>null</code> if there was none.
2242     * @since DOM Level 3
2243     */

2244    public Object JavaDoc getUserData(Node JavaDoc n, String JavaDoc key) {
2245        if (userData == null) {
2246            return null;
2247        }
2248        Hashtable JavaDoc t = (Hashtable JavaDoc) userData.get(n);
2249        if (t == null) {
2250            return null;
2251        }
2252        Object JavaDoc o = t.get(key);
2253        if (o != null) {
2254            UserDataRecord r = (UserDataRecord) o;
2255            return r.fData;
2256        }
2257        return null;
2258    }
2259
2260    protected Hashtable JavaDoc getUserDataRecord(Node JavaDoc n){
2261        if (userData == null) {
2262            return null;
2263        }
2264        Hashtable JavaDoc t = (Hashtable JavaDoc) userData.get(n);
2265        if (t == null) {
2266            return null;
2267        }
2268        return t;
2269    }
2270    
2271    /**
2272     * Remove user data table for the given node.
2273     * @param n The node this operation applies to.
2274     * @return The removed table.
2275     */

2276    Hashtable JavaDoc removeUserDataTable(Node JavaDoc n) {
2277        if (userData == null) {
2278            return null;
2279        }
2280        return (Hashtable JavaDoc) userData.get(n);
2281    }
2282
2283    /**
2284     * Set user data table for the given node.
2285     * @param n The node this operation applies to.
2286     * @param data The user data table.
2287     */

2288    void setUserDataTable(Node JavaDoc n, Hashtable JavaDoc data) {
2289        if (userData == null)
2290            userData = new Hashtable JavaDoc();
2291        if (data != null) {
2292            userData.put(n, data);
2293        }
2294    }
2295
2296    /**
2297     * Call user data handlers when a node is deleted (finalized)
2298     * @param n The node this operation applies to.
2299     * @param c The copy node or null.
2300     * @param operation The operation - import, clone, or delete.
2301     */

2302    void callUserDataHandlers(Node JavaDoc n, Node JavaDoc c, short operation) {
2303        if (userData == null) {
2304            return;
2305        }
2306        //Hashtable t = (Hashtable) userData.get(n);
2307
if(n instanceof NodeImpl){
2308            Hashtable JavaDoc t = ((NodeImpl)n).getUserDataRecord();
2309            if (t == null || t.isEmpty()) {
2310                return;
2311            }
2312            callUserDataHandlers(n, c, operation,t);
2313        }
2314    }
2315
2316    /**
2317     * Call user data handlers when a node is deleted (finalized)
2318     * @param n The node this operation applies to.
2319     * @param c The copy node or null.
2320     * @param operation The operation - import, clone, or delete.
2321     * @param handlers Data associated with n.
2322    */

2323    void callUserDataHandlers(Node JavaDoc n, Node JavaDoc c, short operation,Hashtable JavaDoc userData) {
2324        if (userData == null || userData.isEmpty()) {
2325            return;
2326        }
2327        Enumeration JavaDoc keys = userData.keys();
2328        while (keys.hasMoreElements()) {
2329            String JavaDoc key = (String JavaDoc) keys.nextElement();
2330            UserDataRecord r = (UserDataRecord) userData.get(key);
2331            if (r.fHandler != null) {
2332                r.fHandler.handle(operation, key, r.fData, n, c);
2333            }
2334        }
2335    }
2336    
2337    /**
2338     * Call user data handlers to let them know the nodes they are related to
2339     * are being deleted. The alternative would be to do that on Node but
2340     * because the nodes are used as the keys we have a reference to them that
2341     * prevents them from being gc'ed until the document is. At the same time,
2342     * doing it here has the advantage of avoiding a finalize() method on Node,
2343     * which would affect all nodes and not just the ones that have a user
2344     * data.
2345     */

2346    // Temporarily comment out this method, because
2347
// 1. It seems that finalizers are not guaranteed to be called, so the
2348
// functionality is not implemented.
2349
// 2. It affects the performance greatly in multi-thread environment.
2350
// -SG
2351
/*public void finalize() {
2352        if (userData == null) {
2353            return;
2354        }
2355        Enumeration nodes = userData.keys();
2356        while (nodes.hasMoreElements()) {
2357            Object node = nodes.nextElement();
2358            Hashtable t = (Hashtable) userData.get(node);
2359            if (t != null && !t.isEmpty()) {
2360                Enumeration keys = t.keys();
2361                while (keys.hasMoreElements()) {
2362                    String key = (String) keys.nextElement();
2363                    UserDataRecord r = (UserDataRecord) t.get(key);
2364                    if (r.fHandler != null) {
2365                        r.fHandler.handle(UserDataHandler.NODE_DELETED,
2366                                          key, r.fData, null, null);
2367                    }
2368                }
2369            }
2370        }
2371    }*/

2372
2373    protected final void checkNamespaceWF( String JavaDoc qname, int colon1,
2374    int colon2) {
2375
2376        if (!errorChecking) {
2377            return;
2378        }
2379        // it is an error for NCName to have more than one ':'
2380
// check if it is valid QName [Namespace in XML production 6]
2381
// :camera , nikon:camera:minolta, camera:
2382
if (colon1 == 0 || colon1 == qname.length() - 1 || colon2 != colon1) {
2383            String JavaDoc msg =
2384            DOMMessageFormatter.formatMessage(
2385            DOMMessageFormatter.DOM_DOMAIN,
2386            "NAMESPACE_ERR",
2387            null);
2388            throw new DOMException JavaDoc(DOMException.NAMESPACE_ERR, msg);
2389        }
2390    }
2391    protected final void checkDOMNSErr(String JavaDoc prefix,
2392    String JavaDoc namespace) {
2393        if (errorChecking) {
2394            if (namespace == null) {
2395                String JavaDoc msg =
2396                DOMMessageFormatter.formatMessage(
2397                DOMMessageFormatter.DOM_DOMAIN,
2398                "NAMESPACE_ERR",
2399                null);
2400                throw new DOMException JavaDoc(DOMException.NAMESPACE_ERR, msg);
2401            }
2402            else if (prefix.equals("xml")
2403            && !namespace.equals(NamespaceContext.XML_URI)) {
2404                String JavaDoc msg =
2405                DOMMessageFormatter.formatMessage(
2406                DOMMessageFormatter.DOM_DOMAIN,
2407                "NAMESPACE_ERR",
2408                null);
2409                throw new DOMException JavaDoc(DOMException.NAMESPACE_ERR, msg);
2410            }
2411            else if (
2412            prefix.equals("xmlns")
2413            && !namespace.equals(NamespaceContext.XMLNS_URI)
2414            || (!prefix.equals("xmlns")
2415            && namespace.equals(NamespaceContext.XMLNS_URI))) {
2416                String JavaDoc msg =
2417                DOMMessageFormatter.formatMessage(
2418                DOMMessageFormatter.DOM_DOMAIN,
2419                "NAMESPACE_ERR",
2420                null);
2421                throw new DOMException JavaDoc(DOMException.NAMESPACE_ERR, msg);
2422            }
2423        }
2424    }
2425
2426    /**
2427     * Checks if the given qualified name is legal with respect
2428     * to the version of XML to which this document must conform.
2429     *
2430     * @param prefix prefix of qualified name
2431     * @param local local part of qualified name
2432     */

2433    protected final void checkQName(String JavaDoc prefix, String JavaDoc local) {
2434        if (!errorChecking) {
2435            return;
2436        }
2437
2438        // check that both prefix and local part match NCName
2439
boolean validNCName = false;
2440        if (!xml11Version) {
2441            validNCName = (prefix == null || XMLChar.isValidNCName(prefix))
2442                && XMLChar.isValidNCName(local);
2443        }
2444        else {
2445            validNCName = (prefix == null || XML11Char.isXML11ValidNCName(prefix))
2446                && XML11Char.isXML11ValidNCName(local);
2447        }
2448
2449        if (!validNCName) {
2450            // REVISIT: add qname parameter to the message
2451
String JavaDoc msg =
2452            DOMMessageFormatter.formatMessage(
2453            DOMMessageFormatter.DOM_DOMAIN,
2454            "INVALID_CHARACTER_ERR",
2455            null);
2456            throw new DOMException JavaDoc(DOMException.INVALID_CHARACTER_ERR, msg);
2457        }
2458    }
2459
2460    /**
2461     * We could have more xml versions in future , but for now we could
2462     * do with this to handle XML 1.0 and 1.1
2463     */

2464    boolean isXML11Version(){
2465        return xml11Version;
2466    }
2467
2468    boolean isNormalizeDocRequired(){
2469        // REVISIT: Implement to optimize when normalization
2470
// is required
2471
return true;
2472    }
2473
2474    //we should be checking the (elements, attribute, entity etc.) names only when
2475
//version of the document is changed.
2476
boolean isXMLVersionChanged(){
2477        return xmlVersionChanged ;
2478    }
2479    /**
2480     * NON-DOM: kept for backward compatibility
2481     * Store user data related to a given node
2482     * This is a place where we could use weak references! Indeed, the node
2483     * here won't be GC'ed as long as some user data is attached to it, since
2484     * the userData table will have a reference to the node.
2485     */

2486    protected void setUserData(NodeImpl n, Object JavaDoc data) {
2487        setUserData(n, "XERCES1DOMUSERDATA", data, null);
2488    }
2489
2490    /**
2491     * NON-DOM: kept for backward compatibility
2492     * Retreive user data related to a given node
2493     */

2494    protected Object JavaDoc getUserData(NodeImpl n) {
2495        return getUserData(n, "XERCES1DOMUSERDATA");
2496    }
2497
2498
2499    // Event related methods overidden in subclass
2500

2501    protected void addEventListener(NodeImpl node, String JavaDoc type,
2502    EventListener JavaDoc listener,
2503    boolean useCapture) {
2504        // does nothing by default - overidden in subclass
2505
}
2506
2507    protected void removeEventListener(NodeImpl node, String JavaDoc type,
2508    EventListener JavaDoc listener,
2509    boolean useCapture) {
2510        // does nothing by default - overidden in subclass
2511
}
2512
2513    protected void copyEventListeners(NodeImpl src, NodeImpl tgt) {
2514        // does nothing by default - overidden in subclass
2515
}
2516
2517    protected boolean dispatchEvent(NodeImpl node, Event JavaDoc event) {
2518        // does nothing by default - overidden in subclass
2519
return false;
2520    }
2521
2522    // Notification methods overidden in subclasses
2523

2524    /**
2525     * A method to be called when some text was changed in a text node,
2526     * so that live objects can be notified.
2527     */

2528    void replacedText(NodeImpl node) {
2529    }
2530
2531    /**
2532     * A method to be called when some text was deleted from a text node,
2533     * so that live objects can be notified.
2534     */

2535    void deletedText(NodeImpl node, int offset, int count) {
2536    }
2537
2538    /**
2539     * A method to be called when some text was inserted into a text node,
2540     * so that live objects can be notified.
2541     */

2542    void insertedText(NodeImpl node, int offset, int count) {
2543    }
2544
2545    /**
2546     * A method to be called when a character data node has been modified
2547     */

2548    void modifyingCharacterData(NodeImpl node) {
2549    }
2550
2551    /**
2552     * A method to be called when a character data node has been modified
2553     */

2554    void modifiedCharacterData(NodeImpl node, String JavaDoc oldvalue, String JavaDoc value) {
2555    }
2556
2557    /**
2558     * A method to be called when a node is about to be inserted in the tree.
2559     */

2560    void insertingNode(NodeImpl node, boolean replace) {
2561    }
2562
2563    /**
2564     * A method to be called when a node has been inserted in the tree.
2565     */

2566    void insertedNode(NodeImpl node, NodeImpl newInternal, boolean replace) {
2567    }
2568
2569    /**
2570     * A method to be called when a node is about to be removed from the tree.
2571     */

2572    void removingNode(NodeImpl node, NodeImpl oldChild, boolean replace) {
2573    }
2574
2575    /**
2576     * A method to be called when a node has been removed from the tree.
2577     */

2578    void removedNode(NodeImpl node, boolean replace) {
2579    }
2580
2581    /**
2582     * A method to be called when a node is about to be replaced in the tree.
2583     */

2584    void replacingNode(NodeImpl node) {
2585    }
2586
2587    /**
2588     * A method to be called when a node has been replaced in the tree.
2589     */

2590    void replacedNode(NodeImpl node) {
2591    }
2592
2593    /**
2594     * A method to be called when an attribute value has been modified
2595     */

2596    void modifiedAttrValue(AttrImpl attr, String JavaDoc oldvalue) {
2597    }
2598
2599    /**
2600     * A method to be called when an attribute node has been set
2601     */

2602    void setAttrNode(AttrImpl attr, AttrImpl previous) {
2603    }
2604
2605    /**
2606     * A method to be called when an attribute node has been removed
2607     */

2608    void removedAttrNode(AttrImpl attr, NodeImpl oldOwner, String JavaDoc name) {
2609    }
2610
2611    /**
2612     * A method to be called when an attribute node has been renamed
2613     */

2614    void renamedAttrNode(Attr JavaDoc oldAt, Attr JavaDoc newAt) {
2615    }
2616
2617    /**
2618     * A method to be called when an element has been renamed
2619     */

2620    void renamedElement(Element JavaDoc oldEl, Element JavaDoc newEl) {
2621    }
2622
2623} // class CoreDocumentImpl
2624
Popular Tags