2 Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
40 import java
.util
.Iterator
;
41 import javax
.xml
.XMLConstants
;
43 import org
.w3c
.dom
.Attr
;
44 import org
.w3c
.dom
.CDATASection
;
45 import org
.w3c
.dom
.Comment
;
46 import org
.w3c
.dom
.Document
;
47 import org
.w3c
.dom
.DocumentFragment
;
48 import org
.w3c
.dom
.DocumentType
;
49 import org
.w3c
.dom
.DOMConfiguration
;
50 import org
.w3c
.dom
.DOMImplementation
;
51 import org
.w3c
.dom
.DOMException
;
52 import org
.w3c
.dom
.Element
;
53 import org
.w3c
.dom
.Entity
;
54 import org
.w3c
.dom
.EntityReference
;
55 import org
.w3c
.dom
.NamedNodeMap
;
56 import org
.w3c
.dom
.Node
;
57 import org
.w3c
.dom
.Notation
;
58 import org
.w3c
.dom
.ProcessingInstruction
;
59 import org
.w3c
.dom
.Text
;
60 import org
.w3c
.dom
.UserDataHandler
;
61 import org
.w3c
.dom
.traversal
.DocumentTraversal
;
62 import org
.w3c
.dom
.traversal
.NodeFilter
;
63 import org
.w3c
.dom
.traversal
.NodeIterator
;
64 import org
.w3c
.dom
.traversal
.TreeWalker
;
65 import org
.w3c
.dom
.xpath
.XPathEvaluator
;
66 import org
.w3c
.dom
.xpath
.XPathException
;
67 import org
.w3c
.dom
.xpath
.XPathExpression
;
68 import org
.w3c
.dom
.xpath
.XPathNSResolver
;
71 * <p> "Document" and "DocumentTraversal" implementation.
73 * <p> Note that when this checks names for legality, it uses an
74 * approximation of the XML rules, not the real ones. Specifically,
75 * it uses Unicode rules, with sufficient tweaks to pass a majority
76 * of basic XML conformance tests. (The huge XML character tables are
77 * hairy to implement.)
79 * @author David Brownell
80 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
82 public class DomDocument
84 implements Document
, DocumentTraversal
, XPathEvaluator
87 private final DOMImplementation implementation
;
88 private boolean checkingCharacters
= true;
89 boolean checkingWellformedness
= true;
91 boolean building
; // if true, skip mutation events in the tree
93 DomDocumentConfiguration config
;
97 String version
= "1.0";
102 * Constructs a Document node, associating it with an instance
103 * of the DomImpl class.
105 * <p> Note that this constructor disables character checking.
106 * It is normally used when connecting a DOM to an XML parser,
107 * and duplicating such checks is undesirable. When used for
108 * purposes other than connecting to a parser, you should
109 * re-enable that checking.
111 * @see #setCheckingCharacters
119 * Constructs a Document node, associating it with the specified
120 * implementation. This should only be used in conjunction with
121 * a specialized implementation; it will normally be called by
122 * that implementation.
125 * @see #setCheckingCharacters
127 protected DomDocument(DOMImplementation impl
)
129 super(DOCUMENT_NODE
, null);
130 implementation
= impl
;
134 * Sets the <code>building</code> flag.
135 * Mutation events in the document are not reported.
137 public void setBuilding(boolean flag
)
143 * Sets whether to check for document well-formedness.
144 * If true, an exception will be raised if a second doctype or root
145 * element node is added to the document.
147 public void setCheckWellformedness(boolean flag
)
149 checkingWellformedness
= flag
;
154 * Returns the constant "#document".
156 final public String
getNodeName()
163 * Returns the document's root element, or null.
165 final public Element
getDocumentElement()
167 for (DomNode ctx
= first
; ctx
!= null; ctx
= ctx
.next
)
169 if (ctx
.nodeType
== ELEMENT_NODE
)
171 return (Element
) ctx
;
179 * Returns the document's DocumentType, or null.
181 final public DocumentType
getDoctype()
183 for (DomNode ctx
= first
; ctx
!= null; ctx
= ctx
.next
)
185 if (ctx
.nodeType
== DOCUMENT_TYPE_NODE
)
187 return (DocumentType
) ctx
;
195 * Returns the document's DOMImplementation.
197 final public DOMImplementation
getImplementation()
199 return implementation
;
203 * <b>DOM L1 (relocated in DOM L2)</b>
204 * Returns the element with the specified "ID" attribute, or null.
206 * <p>Returns null unless {@link Consumer} was used to populate internal
207 * DTD declaration information, using package-private APIs. If that
208 * internal DTD information is available, the document may be searched for
209 * the element with that ID.
211 public Element
getElementById(String id
)
213 if (id
== null || id
.length() == 0)
217 DomDoctype doctype
= (DomDoctype
) getDoctype();
218 if (doctype
!= null && !doctype
.hasIds())
223 // yes, this is linear in size of document.
224 // it'd be easy enough to maintain a hashtable.
225 Node current
= getDocumentElement();
232 while (current
!= this)
235 if (current
.getNodeType() == ELEMENT_NODE
)
237 DomElement element
= (DomElement
) current
;
240 DTDElementTypeInfo info
=
241 doctype
.getElementTypeInfo(current
.getNodeName());
243 id
.equals(element
.getAttribute(info
.idAttrName
)))
247 else if (element
.userIdAttrs
!= null)
249 for (Iterator i
= element
.userIdAttrs
.iterator();
252 Node idAttr
= (Node
) i
.next();
253 if (id
.equals(idAttr
.getNodeValue()))
261 String xmlId
= element
.getAttribute("xml:id");
264 xmlId
= element
.getAttributeNS(XMLConstants
.XML_NS_URI
,
267 if (id
.equals(xmlId
))
274 if (current
.hasChildNodes())
276 current
= current
.getFirstChild();
281 temp
= current
.getNextSibling();
291 temp
= current
.getParentNode();
297 temp
= current
.getNextSibling();
299 while (temp
== null);
305 private void checkNewChild(Node newChild
)
307 if (newChild
.getNodeType() == ELEMENT_NODE
308 && getDocumentElement() != null)
310 throw new DomDOMException(DOMException
.HIERARCHY_REQUEST_ERR
,
311 "document element already present: " +
312 getDocumentElement(), newChild
, 0);
314 if (newChild
.getNodeType() == DOCUMENT_TYPE_NODE
315 && getDoctype() != null)
317 throw new DomDOMException(DOMException
.HIERARCHY_REQUEST_ERR
,
318 "document type already present: " +
319 getDoctype(), newChild
, 0);
325 * Appends the specified node to this node's list of children,
326 * enforcing the constraints that there be only one root element
327 * and one document type child.
329 public Node
appendChild(Node newChild
)
331 if (checkingWellformedness
)
333 checkNewChild(newChild
);
335 return super.appendChild(newChild
);
340 * Inserts the specified node in this node's list of children,
341 * enforcing the constraints that there be only one root element
342 * and one document type child.
344 public Node
insertBefore(Node newChild
, Node refChild
)
346 if (checkingWellformedness
)
348 checkNewChild(newChild
);
350 return super.insertBefore(newChild
, refChild
);
355 * Replaces the specified node in this node's list of children,
356 * enforcing the constraints that there be only one root element
357 * and one document type child.
359 public Node
replaceChild(Node newChild
, Node refChild
)
361 if (checkingWellformedness
&&
362 ((newChild
.getNodeType() == ELEMENT_NODE
&&
363 refChild
.getNodeType() != ELEMENT_NODE
) ||
364 (newChild
.getNodeType() == DOCUMENT_TYPE_NODE
&&
365 refChild
.getNodeType() != DOCUMENT_TYPE_NODE
)))
367 checkNewChild(newChild
);
369 return super.replaceChild(newChild
, refChild
);
372 // NOTE: DOM can't really tell when the name of an entity,
373 // notation, or PI must follow the namespace rules (excluding
374 // colons) instead of the XML rules (which allow them without
375 // much restriction). That's an API issue. verifyXmlName
376 // aims to enforce the XML rules, not the namespace rules.
379 * Throws a DOM exception if the specified name is not a legal XML 1.0
381 * @deprecated This method is deprecated and may be removed in future
382 * versions of GNU JAXP
384 public static void verifyXmlName(String name
)
386 // XXX why is this public?
387 checkName(name
, false);
390 static void checkName(String name
, boolean xml11
)
394 throw new DomDOMException(DOMException
.NAMESPACE_ERR
, name
, null, 0);
396 int len
= name
.length();
399 throw new DomDOMException(DOMException
.NAMESPACE_ERR
, name
, null, 0);
402 // dog: rewritten to use the rules for XML 1.0 and 1.1
404 // Name start character
405 char c
= name
.charAt(0);
409 if ((c
< 0x0041 || c
> 0x005a) &&
410 (c
< 0x0061 || c
> 0x007a) &&
411 c
!= ':' && c
!= '_' &&
412 (c
< 0x00c0 || c
> 0x00d6) &&
413 (c
< 0x00d8 || c
> 0x00f6) &&
414 (c
< 0x00f8 || c
> 0x02ff) &&
415 (c
< 0x0370 || c
> 0x037d) &&
416 (c
< 0x037f || c
> 0x1fff) &&
417 (c
< 0x200c || c
> 0x200d) &&
418 (c
< 0x2070 || c
> 0x218f) &&
419 (c
< 0x2c00 || c
> 0x2fef) &&
420 (c
< 0x3001 || c
> 0xd7ff) &&
421 (c
< 0xf900 || c
> 0xfdcf) &&
422 (c
< 0xfdf0 || c
> 0xfffd) &&
423 (c
< 0x10000 || c
> 0xeffff))
425 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
432 int type
= Character
.getType(c
);
435 case Character
.LOWERCASE_LETTER
: // Ll
436 case Character
.UPPERCASE_LETTER
: // Lu
437 case Character
.OTHER_LETTER
: // Lo
438 case Character
.TITLECASE_LETTER
: // Lt
439 case Character
.LETTER_NUMBER
: // Nl
440 if ((c
> 0xf900 && c
< 0xfffe) ||
441 (c
>= 0x20dd && c
<= 0x20e0))
443 // Compatibility area and Unicode 2.0 exclusions
444 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
449 if (c
!= ':' && c
!= '_' && (c
< 0x02bb || c
> 0x02c1) &&
450 c
!= 0x0559 && c
!= 0x06e5 && c
!= 0x06e6)
452 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
458 // Subsequent characters
459 for (int i
= 1; i
< len
; i
++)
465 if ((c
< 0x0041 || c
> 0x005a) &&
466 (c
< 0x0061 || c
> 0x007a) &&
467 (c
< 0x0030 || c
> 0x0039) &&
468 c
!= ':' && c
!= '_' && c
!= '-' && c
!= '.' &&
469 (c
< 0x00c0 || c
> 0x00d6) &&
470 (c
< 0x00d8 || c
> 0x00f6) &&
471 (c
< 0x00f8 || c
> 0x02ff) &&
472 (c
< 0x0370 || c
> 0x037d) &&
473 (c
< 0x037f || c
> 0x1fff) &&
474 (c
< 0x200c || c
> 0x200d) &&
475 (c
< 0x2070 || c
> 0x218f) &&
476 (c
< 0x2c00 || c
> 0x2fef) &&
477 (c
< 0x3001 || c
> 0xd7ff) &&
478 (c
< 0xf900 || c
> 0xfdcf) &&
479 (c
< 0xfdf0 || c
> 0xfffd) &&
480 (c
< 0x10000 || c
> 0xeffff) &&
482 (c
< 0x0300 || c
> 0x036f) &&
483 (c
< 0x203f || c
> 0x2040))
485 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
, name
,
492 int type
= Character
.getType(c
);
495 case Character
.LOWERCASE_LETTER
: // Ll
496 case Character
.UPPERCASE_LETTER
: // Lu
497 case Character
.DECIMAL_DIGIT_NUMBER
: // Nd
498 case Character
.OTHER_LETTER
: // Lo
499 case Character
.TITLECASE_LETTER
: // Lt
500 case Character
.LETTER_NUMBER
: // Nl
501 case Character
.COMBINING_SPACING_MARK
: // Mc
502 case Character
.ENCLOSING_MARK
: // Me
503 case Character
.NON_SPACING_MARK
: // Mn
504 case Character
.MODIFIER_LETTER
: // Lm
505 if ((c
> 0xf900 && c
< 0xfffe) ||
506 (c
>= 0x20dd && c
<= 0x20e0))
508 // Compatibility area and Unicode 2.0 exclusions
509 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
514 if (c
!= '-' && c
!= '.' && c
!= ':' && c
!= '_' &&
515 c
!= 0x0387 && (c
< 0x02bb || c
> 0x02c1) &&
516 c
!= 0x0559 && c
!= 0x06e5 && c
!= 0x06e6 && c
!= 0x00b7)
518 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
525 // FIXME characters with a font or compatibility decomposition (i.e.
526 // those with a "compatibility formatting tag" in field 5 of the
527 // database -- marked by field 5 beginning with a "<") are not allowed.
531 static void checkNCName(String name
, boolean xml11
)
533 checkName(name
, xml11
);
534 int len
= name
.length();
535 int index
= name
.indexOf(':');
538 if (index
== 0 || index
== (len
- 1) ||
539 name
.lastIndexOf(':') != index
)
541 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
548 static void checkChar(String value
, boolean xml11
)
550 char[] chars
= value
.toCharArray();
551 checkChar(chars
, 0, chars
.length
, xml11
);
554 static void checkChar(char[] buf
, int off
, int len
, boolean xml11
)
556 for (int i
= 0; i
< len
; i
++)
560 // assume surrogate pairing checks out OK, for simplicity
561 if ((c
>= 0x0020 && c
<= 0xd7ff) ||
562 (c
== 0x000a || c
== 0x000d || c
== 0x0009) ||
563 (c
>= 0xe000 && c
<= 0xfffd) ||
564 (c
>= 0x10000 && c
<= 0x10ffff))
570 if ((c
>= 0x0001 && c
<= 0x001f) ||
571 (c
>= 0x007f && c
<= 0x0084) ||
572 (c
>= 0x0086 && c
<= 0x009f))
577 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
578 new String(buf
, off
, len
), null, c
);
584 * Returns a newly created element with the specified name.
586 public Element
createElement(String name
)
590 if (checkingCharacters
)
592 checkName(name
, "1.1".equals(version
));
594 if (name
.startsWith("xml:"))
596 element
= createElementNS(null, name
);
600 DomElement domElement
= new DomElement(this, null, name
);
601 domElement
.localName
= null;
602 element
= domElement
;
604 defaultAttributes(element
, name
);
610 * Returns a newly created element with the specified name
611 * and namespace information.
613 public Element
createElementNS(String namespaceURI
, String name
)
615 if (checkingCharacters
)
617 checkNCName(name
, "1.1".equals(version
));
620 if ("".equals(namespaceURI
))
624 if (name
.startsWith("xml:"))
626 if (namespaceURI
!= null
627 && !XMLConstants
.XML_NS_URI
.equals(namespaceURI
))
629 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
630 "xml namespace is always " +
631 XMLConstants
.XML_NS_URI
, this, 0);
633 namespaceURI
= XMLConstants
.XML_NS_URI
;
635 else if (XMLConstants
.XMLNS_ATTRIBUTE
.equals(name
) ||
636 name
.startsWith("xmlns:"))
638 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
639 "xmlns is reserved", this, 0);
641 else if (namespaceURI
== null && name
.indexOf(':') != -1)
643 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
644 "prefixed name '" + name
+
645 "' needs a URI", this, 0);
648 Element element
= new DomElement(this, namespaceURI
, name
);
649 defaultAttributes(element
, name
);
653 private void defaultAttributes(Element element
, String name
)
655 DomDoctype doctype
= (DomDoctype
) getDoctype();
661 // default any attributes that need it
662 DTDElementTypeInfo info
= doctype
.getElementTypeInfo(name
);
665 for (Iterator i
= info
.attributes(); i
!= null && i
.hasNext(); )
667 DTDAttributeTypeInfo attr
= (DTDAttributeTypeInfo
) i
.next();
668 DomAttr node
= (DomAttr
) createAttribute(attr
.name
);
670 String value
= attr
.value
;
675 node
.setValue(value
);
676 node
.setSpecified(false);
677 element
.setAttributeNode(node
);
684 * Returns a newly created document fragment.
686 public DocumentFragment
createDocumentFragment()
688 return new DomDocumentFragment(this);
693 * Returns a newly created text node with the specified value.
695 public Text
createTextNode(String value
)
697 if (checkingCharacters
)
699 checkChar(value
, "1.1".equals(version
));
701 return new DomText(this, value
);
705 * Returns a newly created text node with the specified value.
707 public Text
createTextNode(char[] buf
, int off
, int len
)
709 if (checkingCharacters
)
711 checkChar(buf
, off
, len
, "1.1".equals(version
));
713 return new DomText(this, buf
, off
, len
);
718 * Returns a newly created comment node with the specified value.
720 public Comment
createComment(String value
)
722 if (checkingCharacters
)
724 checkChar(value
, "1.1".equals(version
));
726 return new DomComment(this, value
);
731 * Returns a newly created CDATA section node with the specified value.
733 public CDATASection
createCDATASection(String value
)
735 if (checkingCharacters
)
737 checkChar(value
, "1.1".equals(version
));
739 return new DomCDATASection(this, value
);
743 * Returns a newly created CDATA section node with the specified value.
745 public CDATASection
createCDATASection(char[] buf
, int off
, int len
)
747 if (checkingCharacters
)
749 checkChar(buf
, off
, len
, "1.1".equals(version
));
751 return new DomCDATASection(this, buf
, off
, len
);
756 * Returns a newly created processing instruction.
758 public ProcessingInstruction
createProcessingInstruction(String target
,
761 if (checkingCharacters
)
763 boolean xml11
= "1.1".equals(version
);
764 checkName(target
, xml11
);
765 if ("xml".equalsIgnoreCase(target
))
767 throw new DomDOMException(DOMException
.SYNTAX_ERR
,
768 "illegal PI target name",
771 checkChar(data
, xml11
);
773 return new DomProcessingInstruction(this, target
, data
);
778 * Returns a newly created attribute with the specified name.
780 public Attr
createAttribute(String name
)
782 if (checkingCharacters
)
784 checkName(name
, "1.1".equals(version
));
786 if (name
.startsWith("xml:"))
788 return createAttributeNS(XMLConstants
.XML_NS_URI
, name
);
790 else if (XMLConstants
.XMLNS_ATTRIBUTE
.equals(name
) ||
791 name
.startsWith("xmlns:"))
793 return createAttributeNS(XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
, name
);
797 DomAttr ret
= new DomAttr(this, null, name
);
798 ret
.localName
= null;
805 * Returns a newly created attribute with the specified name
806 * and namespace information.
808 public Attr
createAttributeNS(String namespaceURI
, String name
)
810 if (checkingCharacters
)
812 checkNCName(name
, "1.1".equals(version
));
815 if ("".equals(namespaceURI
))
819 if (name
.startsWith ("xml:"))
821 if (namespaceURI
== null)
823 namespaceURI
= XMLConstants
.XML_NS_URI
;
825 else if (!XMLConstants
.XML_NS_URI
.equals(namespaceURI
))
827 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
828 "xml namespace is always " +
829 XMLConstants
.XML_NS_URI
,
833 else if (XMLConstants
.XMLNS_ATTRIBUTE
.equals(name
) ||
834 name
.startsWith("xmlns:"))
836 if (namespaceURI
== null)
838 namespaceURI
= XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
;
840 else if (!XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
.equals(namespaceURI
))
842 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
843 "xmlns namespace must be " +
844 XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
,
848 else if (namespaceURI
== null && name
.indexOf(':') != -1)
850 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
851 "prefixed name needs a URI: " + name
, this, 0);
853 return new DomAttr(this, namespaceURI
, name
);
858 * Returns a newly created reference to the specified entity.
859 * The caller should populate this with the appropriate children
860 * and then mark it as readonly.
862 * @see DomNode#makeReadonly
864 public EntityReference
createEntityReference(String name
)
866 DomEntityReference ret
= new DomEntityReference(this, name
);
867 DocumentType doctype
= getDoctype();
870 DomEntity ent
= (DomEntity
) doctype
.getEntities().getNamedItem(name
);
873 for (DomNode ctx
= ent
.first
; ctx
!= null; ctx
= ctx
.next
)
875 ret
.appendChild(ctx
.cloneNode(true));
885 * Makes a copy of the specified node, with all nodes "owned" by
886 * this document and with children optionally copied. This type
887 * of standard utility has become, well, a standard utility.
889 * <p> Note that EntityReference nodes created through this method (either
890 * directly, or recursively) never have children, and that there is no
891 * portable way to associate them with such children.
893 * <p> Note also that there is no requirement that the specified node
894 * be associated with a different document. This differs from the
895 * <em>cloneNode</em> operation in that the node itself is not given
896 * an opportunity to participate, so that any information managed
897 * by node subclasses will be lost.
899 public Node
importNode(Node src
, boolean deep
)
902 switch (src
.getNodeType())
905 dst
= createTextNode(src
.getNodeValue());
907 case CDATA_SECTION_NODE
:
908 dst
= createCDATASection(src
.getNodeValue());
911 dst
= createComment(src
.getNodeValue());
913 case PROCESSING_INSTRUCTION_NODE
:
914 dst
= createProcessingInstruction(src
.getNodeName(),
918 // NOTE: There's no standard way to create
919 // these, or add them to a doctype. Useless.
920 Notation notation
= (Notation
) src
;
921 dst
= new DomNotation(this, notation
.getNodeName(),
922 notation
.getPublicId(),
923 notation
.getSystemId());
926 // NOTE: There's no standard way to create
927 // these, or add them to a doctype. Useless.
928 Entity entity
= (Entity
) src
;
929 dst
= new DomEntity(this, entity
.getNodeName(),
930 entity
.getPublicId(),
931 entity
.getSystemId(),
932 entity
.getNotationName());
935 for (Node ctx
= src
.getFirstChild(); ctx
!= null;
936 ctx
= ctx
.getNextSibling())
938 dst
.appendChild(importNode(ctx
, deep
));
942 case ENTITY_REFERENCE_NODE
:
943 dst
= createEntityReference(src
.getNodeName());
945 case DOCUMENT_FRAGMENT_NODE
:
946 dst
= new DomDocumentFragment(this);
949 for (Node ctx
= src
.getFirstChild(); ctx
!= null;
950 ctx
= ctx
.getNextSibling())
952 dst
.appendChild(importNode(ctx
, deep
));
957 String attr_nsuri
= src
.getNamespaceURI();
958 if (attr_nsuri
!= null)
960 dst
= createAttributeNS(attr_nsuri
, src
.getNodeName());
964 dst
= createAttribute(src
.getNodeName());
966 // this is _always_ done regardless of "deep" setting
967 for (Node ctx
= src
.getFirstChild(); ctx
!= null;
968 ctx
= ctx
.getNextSibling())
970 dst
.appendChild(importNode(ctx
, false));
974 String elem_nsuri
= src
.getNamespaceURI();
975 if (elem_nsuri
!= null)
977 dst
= createElementNS(elem_nsuri
, src
.getNodeName());
981 dst
= createElement(src
.getNodeName());
983 NamedNodeMap srcAttrs
= src
.getAttributes();
984 NamedNodeMap dstAttrs
= dst
.getAttributes();
985 int len
= srcAttrs
.getLength();
986 for (int i
= 0; i
< len
; i
++)
988 Attr a
= (Attr
) srcAttrs
.item(i
);
991 // maybe update defaulted attributes
992 dflt
= (Attr
) dstAttrs
.getNamedItem(a
.getNodeName());
995 String newval
= a
.getNodeValue();
996 if (!dflt
.getNodeValue().equals(newval
)
997 || a
.getSpecified () == true)
999 dflt
.setNodeValue (newval
);
1004 dstAttrs
.setNamedItem((Attr
) importNode(a
, false));
1008 for (Node ctx
= src
.getFirstChild(); ctx
!= null;
1009 ctx
= ctx
.getNextSibling())
1011 dst
.appendChild(importNode(ctx
, true));
1015 // can't import document or doctype nodes
1017 case DOCUMENT_TYPE_NODE
:
1019 // can't import unrecognized or nonstandard nodes
1021 throw new DomDOMException(DOMException
.NOT_SUPPORTED_ERR
, null, src
, 0);
1024 // FIXME cleanup a bit -- for deep copies, copy those
1025 // children in one place, here (code sharing is healthy)
1027 if (src
instanceof DomNode
)
1029 ((DomNode
) src
).notifyUserDataHandlers(UserDataHandler
.NODE_IMPORTED
,
1036 * <b>DOM L2 (Traversal)</b>
1037 * Returns a newly created node iterator. Don't forget to detach
1038 * this iterator when you're done using it!
1042 public NodeIterator
createNodeIterator(Node root
,
1045 boolean expandEntities
)
1047 return new DomNodeIterator(root
, whatToShow
, filter
, expandEntities
,
1051 public TreeWalker
createTreeWalker(Node root
,
1054 boolean expandEntities
)
1056 return new DomNodeIterator(root
, whatToShow
, filter
, expandEntities
,
1060 // DOM Level 3 methods
1065 public String
getInputEncoding()
1067 return inputEncoding
;
1070 public void setInputEncoding(String inputEncoding
)
1072 this.inputEncoding
= inputEncoding
;
1078 public String
getXmlEncoding()
1083 public void setXmlEncoding(String encoding
)
1085 this.encoding
= encoding
;
1088 public boolean getXmlStandalone()
1093 public void setXmlStandalone(boolean xmlStandalone
)
1095 standalone
= xmlStandalone
;
1098 public String
getXmlVersion()
1103 public void setXmlVersion(String xmlVersion
)
1105 if (xmlVersion
== null)
1109 if ("1.0".equals(xmlVersion
) ||
1110 "1.1".equals(xmlVersion
))
1112 version
= xmlVersion
;
1116 throw new DomDOMException(DOMException
.NOT_SUPPORTED_ERR
);
1120 public boolean getStrictErrorChecking()
1122 return checkingCharacters
;
1125 public void setStrictErrorChecking(boolean strictErrorChecking
)
1127 checkingCharacters
= strictErrorChecking
;
1130 public String
lookupPrefix(String namespaceURI
)
1132 Node root
= getDocumentElement();
1133 return (root
== null) ?
null : root
.lookupPrefix(namespaceURI
);
1136 public boolean isDefaultNamespace(String namespaceURI
)
1138 Node root
= getDocumentElement();
1139 return (root
== null) ?
false : root
.isDefaultNamespace(namespaceURI
);
1142 public String
lookupNamespaceURI(String prefix
)
1144 Node root
= getDocumentElement();
1145 return (root
== null) ?
null : root
.lookupNamespaceURI(prefix
);
1148 public String
getBaseURI()
1150 return getDocumentURI();
1152 Node root = getDocumentElement();
1155 NamedNodeMap attrs = root.getAttributes();
1156 Node xmlBase = attrs.getNamedItemNS(XMLConstants.XML_NS_URI, "base");
1157 if (xmlBase != null)
1159 return xmlBase.getNodeValue();
1166 public String
getDocumentURI()
1171 public void setDocumentURI(String documentURI
)
1173 systemId
= documentURI
;
1176 public Node
adoptNode(Node source
)
1178 int sourceNodeType
= source
.getNodeType();
1179 switch (sourceNodeType
)
1182 case DOCUMENT_TYPE_NODE
:
1183 throw new DomDOMException(DOMException
.NOT_SUPPORTED_ERR
);
1186 throw new DomDOMException(DOMException
.NO_MODIFICATION_ALLOWED_ERR
);
1188 if (source
instanceof DomNode
)
1191 DomNode src
= (DomNode
) source
;
1193 if (dst
.parent
!= null)
1195 dst
= (DomNode
) dst
.cloneNode(true);
1198 src
.notifyUserDataHandlers(UserDataHandler
.NODE_ADOPTED
, src
, dst
);
1203 // Some other implementation
1205 switch (sourceNodeType
)
1207 case Node
.ATTRIBUTE_NODE
:
1209 Attr src
= (Attr
) source
;
1210 String nodeName
= src
.getNodeName();
1211 String localName
= src
.getLocalName();
1212 String namespaceUri
= src
.getNamespaceURI();
1213 dst
= (localName
== null) ?
1214 createAttribute(nodeName
) :
1215 createAttributeNS(namespaceUri
, nodeName
);
1216 adoptChildren(src
, dst
);
1219 case Node
.CDATA_SECTION_NODE
:
1221 CDATASection src
= (CDATASection
) source
;
1222 dst
= createCDATASection(src
.getData());
1225 case Node
.COMMENT_NODE
:
1227 Comment src
= (Comment
) source
;
1228 dst
= createComment(src
.getData());
1231 case Node
.DOCUMENT_FRAGMENT_NODE
:
1233 DocumentFragment src
= (DocumentFragment
) source
;
1234 dst
= createDocumentFragment();
1235 adoptChildren(src
, dst
);
1238 case Node
.ELEMENT_NODE
:
1240 Element src
= (Element
) source
;
1241 String nodeName
= src
.getNodeName();
1242 String localName
= src
.getLocalName();
1243 String namespaceUri
= src
.getNamespaceURI();
1244 dst
= (localName
== null) ?
1245 createElement(nodeName
) :
1246 createElementNS(namespaceUri
, nodeName
);
1247 adoptAttributes(src
, dst
);
1248 adoptChildren(src
, dst
);
1251 case Node
.ENTITY_REFERENCE_NODE
:
1253 EntityReference src
= (EntityReference
) source
;
1254 dst
= createEntityReference(src
.getNodeName());
1255 adoptChildren(src
, dst
);
1258 case Node
.PROCESSING_INSTRUCTION_NODE
:
1260 ProcessingInstruction src
= (ProcessingInstruction
) source
;
1261 dst
= createProcessingInstruction(src
.getTarget(),
1265 case Node
.TEXT_NODE
:
1267 Text src
= (Text
) source
;
1268 dst
= createTextNode(src
.getData());
1276 void adoptChildren(Node src
, Node dst
)
1278 Node node
= src
.getFirstChild();
1279 while (node
!= null)
1281 Node next
= node
.getNextSibling();
1282 dst
.appendChild(adoptNode(node
));
1287 void adoptAttributes(Node src
, Node dst
)
1289 NamedNodeMap srcAttrs
= src
.getAttributes();
1290 NamedNodeMap dstAttrs
= dst
.getAttributes();
1291 int len
= srcAttrs
.getLength();
1292 for (int i
= 0; i
< len
; i
++)
1294 Node node
= srcAttrs
.item(i
);
1295 String localName
= node
.getLocalName();
1296 if (localName
== null)
1298 dstAttrs
.setNamedItem(adoptNode(node
));
1302 dstAttrs
.setNamedItemNS(adoptNode(node
));
1307 public DOMConfiguration
getDomConfig()
1311 config
= new DomDocumentConfiguration();
1316 public void normalizeDocument()
1318 boolean save
= building
;
1320 normalizeNode(this);
1324 void normalizeNode(DomNode node
)
1329 switch (node
.nodeType
)
1331 case CDATA_SECTION_NODE
:
1332 if (!config
.cdataSections
)
1334 // replace CDATA section with text node
1335 Text text
= createTextNode(node
.getNodeValue());
1336 node
.parent
.insertBefore(text
, node
);
1337 node
.parent
.removeChild(node
);
1338 // merge adjacent text nodes
1339 String data
= text
.getWholeText();
1340 node
= (DomNode
) text
.replaceWholeText(data
);
1342 else if (config
.splitCdataSections
)
1344 String value
= node
.getNodeValue();
1345 int i
= value
.indexOf("]]>");
1348 Node node2
= createCDATASection(value
.substring(0, i
));
1349 node
.parent
.insertBefore(node2
, node
);
1350 value
= value
.substring(i
+ 3);
1351 node
.setNodeValue(value
);
1352 i
= value
.indexOf("]]>");
1357 if (!config
.comments
)
1359 node
.parent
.removeChild(node
);
1363 if (!config
.elementContentWhitespace
&&
1364 ((Text
) node
).isElementContentWhitespace())
1366 node
.parent
.removeChild(node
);
1369 case ENTITY_REFERENCE_NODE
:
1370 if (!config
.entities
)
1372 for (DomNode ctx
= node
.first
; ctx
!= null; )
1374 DomNode ctxNext
= ctx
.next
;
1375 node
.parent
.insertBefore(ctx
, node
);
1378 node
.parent
.removeChild(node
);
1382 if (!config
.namespaceDeclarations
)
1384 DomNamedNodeMap attrs
=
1385 (DomNamedNodeMap
) node
.getAttributes();
1386 boolean aro
= attrs
.readonly
;
1387 attrs
.readonly
= false; // Ensure we can delete if necessary
1388 int len
= attrs
.getLength();
1389 for (int i
= 0; i
< len
; i
++)
1391 Node attr
= attrs
.item(i
);
1392 String namespace
= attr
.getNamespaceURI();
1393 if (XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
.equals(namespace
))
1395 attrs
.removeNamedItemNS(namespace
,
1396 attr
.getLocalName());
1401 attrs
.readonly
= aro
;
1406 for (DomNode ctx
= node
.first
; ctx
!= null; )
1408 DomNode ctxNext
= ctx
.next
;
1414 public Node
renameNode(Node n
, String namespaceURI
, String qualifiedName
)
1417 if (n
instanceof DomNsNode
)
1419 DomNsNode src
= (DomNsNode
) n
;
1422 throw new DomDOMException(DOMException
.NOT_FOUND_ERR
);
1424 if (src
.owner
!= this)
1426 throw new DomDOMException(DOMException
.WRONG_DOCUMENT_ERR
,
1429 boolean xml11
= "1.1".equals(version
);
1430 checkName(qualifiedName
, xml11
);
1431 int ci
= qualifiedName
.indexOf(':');
1432 if ("".equals(namespaceURI
))
1434 namespaceURI
= null;
1436 if (namespaceURI
!= null)
1438 checkNCName(qualifiedName
, xml11
);
1439 String prefix
= (ci
== -1) ?
"" :
1440 qualifiedName
.substring(0, ci
);
1441 if (XMLConstants
.XML_NS_PREFIX
.equals(prefix
) &&
1442 !XMLConstants
.XML_NS_URI
.equals(namespaceURI
))
1444 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
1445 "xml namespace must be " +
1446 XMLConstants
.XML_NS_URI
, src
, 0);
1448 else if (src
.nodeType
== ATTRIBUTE_NODE
&&
1449 (XMLConstants
.XMLNS_ATTRIBUTE
.equals(prefix
) ||
1450 XMLConstants
.XMLNS_ATTRIBUTE
.equals(qualifiedName
)) &&
1451 !XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
.equals(namespaceURI
))
1453 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
1454 "xmlns namespace must be " +
1455 XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
, src
, 0);
1457 if (XMLConstants
.XML_NS_URI
.equals(namespaceURI
) &&
1458 !XMLConstants
.XML_NS_PREFIX
.equals(prefix
))
1460 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
1461 "xml namespace must be " +
1462 XMLConstants
.XML_NS_URI
, src
, 0);
1464 else if (src
.nodeType
== ATTRIBUTE_NODE
&&
1465 XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
.equals(namespaceURI
) &&
1466 !(XMLConstants
.XMLNS_ATTRIBUTE
.equals(prefix
) ||
1467 XMLConstants
.XMLNS_ATTRIBUTE
.equals(qualifiedName
)))
1469 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
1470 "xmlns namespace must be " +
1471 XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
, src
, 0);
1475 src
.setNodeName(qualifiedName
);
1476 src
.setNamespaceURI(namespaceURI
);
1477 src
.notifyUserDataHandlers(UserDataHandler
.NODE_RENAMED
, src
, src
);
1478 // TODO MutationNameEvents
1479 // DOMElementNameChanged or DOMAttributeNameChanged
1482 throw new DomDOMException(DOMException
.NOT_SUPPORTED_ERR
, null, n
, 0);
1485 // -- XPathEvaluator --
1487 public XPathExpression
createExpression(String expression
,
1488 XPathNSResolver resolver
)
1489 throws XPathException
, DOMException
1491 return new DomXPathExpression(this, expression
, resolver
);
1494 public XPathNSResolver
createNSResolver(Node nodeResolver
)
1496 return new DomXPathNSResolver(nodeResolver
);
1499 public Object
evaluate(String expression
,
1501 XPathNSResolver resolver
,
1504 throws XPathException
, DOMException
1506 XPathExpression xpe
=
1507 new DomXPathExpression(this, expression
, resolver
);
1508 return xpe
.evaluate(contextNode
, type
, result
);