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., 59 Temple Place, Suite 330, 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 DomDoctype doctype
= (DomDoctype
) getDoctype();
215 if (doctype
== null || !doctype
.hasIds()
216 || id
== null || id
.length() == 0)
221 // yes, this is linear in size of document.
222 // it'd be easy enough to maintain a hashtable.
223 Node current
= getDocumentElement();
230 while (current
!= this)
233 if (current
.getNodeType() == ELEMENT_NODE
)
235 DomElement element
= (DomElement
) current
;
236 DTDElementTypeInfo info
=
237 doctype
.getElementTypeInfo(current
.getNodeName());
239 id
.equals(element
.getAttribute(info
.idAttrName
)))
243 else if (element
.userIdAttrs
!= null)
245 for (Iterator i
= element
.userIdAttrs
.iterator();
248 Node idAttr
= (Node
) i
.next();
249 if (id
.equals(idAttr
.getNodeValue()))
258 if (current
.hasChildNodes())
260 current
= current
.getFirstChild();
265 temp
= current
.getNextSibling();
275 temp
= current
.getParentNode();
281 temp
= current
.getNextSibling();
283 while (temp
== null);
289 private void checkNewChild(Node newChild
)
291 if (newChild
.getNodeType() == ELEMENT_NODE
292 && getDocumentElement() != null)
294 throw new DomDOMException(DOMException
.HIERARCHY_REQUEST_ERR
,
295 "document element already present: " +
296 getDocumentElement(), newChild
, 0);
298 if (newChild
.getNodeType() == DOCUMENT_TYPE_NODE
299 && getDoctype() != null)
301 throw new DomDOMException(DOMException
.HIERARCHY_REQUEST_ERR
,
302 "document type already present: " +
303 getDoctype(), newChild
, 0);
309 * Appends the specified node to this node's list of children,
310 * enforcing the constraints that there be only one root element
311 * and one document type child.
313 public Node
appendChild(Node newChild
)
315 if (checkingWellformedness
)
317 checkNewChild(newChild
);
319 return super.appendChild(newChild
);
324 * Inserts the specified node in this node's list of children,
325 * enforcing the constraints that there be only one root element
326 * and one document type child.
328 public Node
insertBefore(Node newChild
, Node refChild
)
330 if (checkingWellformedness
)
332 checkNewChild(newChild
);
334 return super.insertBefore(newChild
, refChild
);
339 * Replaces the specified node in this node's list of children,
340 * enforcing the constraints that there be only one root element
341 * and one document type child.
343 public Node
replaceChild(Node newChild
, Node refChild
)
345 if (checkingWellformedness
&&
346 ((newChild
.getNodeType() == ELEMENT_NODE
&&
347 refChild
.getNodeType() != ELEMENT_NODE
) ||
348 (newChild
.getNodeType() == DOCUMENT_TYPE_NODE
&&
349 refChild
.getNodeType() != DOCUMENT_TYPE_NODE
)))
351 checkNewChild(newChild
);
353 return super.replaceChild(newChild
, refChild
);
356 // NOTE: DOM can't really tell when the name of an entity,
357 // notation, or PI must follow the namespace rules (excluding
358 // colons) instead of the XML rules (which allow them without
359 // much restriction). That's an API issue. verifyXmlName
360 // aims to enforce the XML rules, not the namespace rules.
363 * Throws a DOM exception if the specified name is not a legal XML 1.0
365 * @deprecated This method is deprecated and may be removed in future
366 * versions of GNU JAXP
368 public static void verifyXmlName(String name
)
370 // XXX why is this public?
371 checkName(name
, false);
374 static void checkName(String name
, boolean xml11
)
378 throw new DomDOMException(DOMException
.NAMESPACE_ERR
, name
, null, 0);
380 int len
= name
.length();
383 throw new DomDOMException(DOMException
.NAMESPACE_ERR
, name
, null, 0);
386 // dog: rewritten to use the rules for XML 1.0 and 1.1
388 // Name start character
389 char c
= name
.charAt(0);
393 if ((c
< 0x0041 || c
> 0x005a) &&
394 (c
< 0x0061 || c
> 0x007a) &&
395 c
!= ':' && c
!= '_' &&
396 (c
< 0x00c0 || c
> 0x00d6) &&
397 (c
< 0x00d8 || c
> 0x00f6) &&
398 (c
< 0x00f8 || c
> 0x02ff) &&
399 (c
< 0x0370 || c
> 0x037d) &&
400 (c
< 0x037f || c
> 0x1fff) &&
401 (c
< 0x200c || c
> 0x200d) &&
402 (c
< 0x2070 || c
> 0x218f) &&
403 (c
< 0x2c00 || c
> 0x2fef) &&
404 (c
< 0x3001 || c
> 0xd7ff) &&
405 (c
< 0xf900 || c
> 0xfdcf) &&
406 (c
< 0xfdf0 || c
> 0xfffd) &&
407 (c
< 0x10000 || c
> 0xeffff))
409 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
416 int type
= Character
.getType(c
);
419 case Character
.LOWERCASE_LETTER
: // Ll
420 case Character
.UPPERCASE_LETTER
: // Lu
421 case Character
.OTHER_LETTER
: // Lo
422 case Character
.TITLECASE_LETTER
: // Lt
423 case Character
.LETTER_NUMBER
: // Nl
424 if ((c
> 0xf900 && c
< 0xfffe) ||
425 (c
>= 0x20dd && c
<= 0x20e0))
427 // Compatibility area and Unicode 2.0 exclusions
428 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
433 if (c
!= ':' && c
!= '_' && (c
< 0x02bb || c
> 0x02c1) &&
434 c
!= 0x0559 && c
!= 0x06e5 && c
!= 0x06e6)
436 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
442 // Subsequent characters
443 for (int i
= 1; i
< len
; i
++)
449 if ((c
< 0x0041 || c
> 0x005a) &&
450 (c
< 0x0061 || c
> 0x007a) &&
451 (c
< 0x0030 || c
> 0x0039) &&
452 c
!= ':' && c
!= '_' && c
!= '-' && c
!= '.' &&
453 (c
< 0x00c0 || c
> 0x00d6) &&
454 (c
< 0x00d8 || c
> 0x00f6) &&
455 (c
< 0x00f8 || c
> 0x02ff) &&
456 (c
< 0x0370 || c
> 0x037d) &&
457 (c
< 0x037f || c
> 0x1fff) &&
458 (c
< 0x200c || c
> 0x200d) &&
459 (c
< 0x2070 || c
> 0x218f) &&
460 (c
< 0x2c00 || c
> 0x2fef) &&
461 (c
< 0x3001 || c
> 0xd7ff) &&
462 (c
< 0xf900 || c
> 0xfdcf) &&
463 (c
< 0xfdf0 || c
> 0xfffd) &&
464 (c
< 0x10000 || c
> 0xeffff) &&
466 (c
< 0x0300 || c
> 0x036f) &&
467 (c
< 0x203f || c
> 0x2040))
469 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
, name
,
476 int type
= Character
.getType(c
);
479 case Character
.LOWERCASE_LETTER
: // Ll
480 case Character
.UPPERCASE_LETTER
: // Lu
481 case Character
.DECIMAL_DIGIT_NUMBER
: // Nd
482 case Character
.OTHER_LETTER
: // Lo
483 case Character
.TITLECASE_LETTER
: // Lt
484 case Character
.LETTER_NUMBER
: // Nl
485 case Character
.COMBINING_SPACING_MARK
: // Mc
486 case Character
.ENCLOSING_MARK
: // Me
487 case Character
.NON_SPACING_MARK
: // Mn
488 case Character
.MODIFIER_LETTER
: // Lm
489 if ((c
> 0xf900 && c
< 0xfffe) ||
490 (c
>= 0x20dd && c
<= 0x20e0))
492 // Compatibility area and Unicode 2.0 exclusions
493 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
498 if (c
!= '-' && c
!= '.' && c
!= ':' && c
!= '_' &&
499 c
!= 0x0387 && (c
< 0x02bb || c
> 0x02c1) &&
500 c
!= 0x0559 && c
!= 0x06e5 && c
!= 0x06e6 && c
!= 0x00b7)
502 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
509 // FIXME characters with a font or compatibility decomposition (i.e.
510 // those with a "compatibility formatting tag" in field 5 of the
511 // database -- marked by field 5 beginning with a "<") are not allowed.
515 static void checkNCName(String name
, boolean xml11
)
517 checkName(name
, xml11
);
518 int len
= name
.length();
519 int index
= name
.indexOf(':');
522 if (index
== 0 || index
== (len
- 1) ||
523 name
.lastIndexOf(':') != index
)
525 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
532 static void checkChar(String value
, boolean xml11
)
534 char[] chars
= value
.toCharArray();
535 checkChar(chars
, 0, chars
.length
, xml11
);
538 static void checkChar(char[] buf
, int off
, int len
, boolean xml11
)
540 for (int i
= 0; i
< len
; i
++)
544 // assume surrogate pairing checks out OK, for simplicity
545 if ((c
>= 0x0020 && c
<= 0xd7ff) ||
546 (c
== 0x000a || c
== 0x000d || c
== 0x0009) ||
547 (c
>= 0xe000 && c
<= 0xfffd) ||
548 (c
>= 0x10000 && c
<= 0x10ffff))
554 if ((c
>= 0x0001 && c
<= 0x001f) ||
555 (c
>= 0x007f && c
<= 0x0084) ||
556 (c
>= 0x0086 && c
<= 0x009f))
561 throw new DomDOMException(DOMException
.INVALID_CHARACTER_ERR
,
562 new String(buf
, off
, len
), null, c
);
568 * Returns a newly created element with the specified name.
570 public Element
createElement(String name
)
574 if (checkingCharacters
)
576 checkName(name
, "1.1".equals(version
));
578 if (name
.startsWith("xml:"))
580 element
= createElementNS(null, name
);
584 element
= new DomElement(this, null, name
);
586 defaultAttributes(element
, name
);
592 * Returns a newly created element with the specified name
593 * and namespace information.
595 public Element
createElementNS(String namespaceURI
, String name
)
597 if (checkingCharacters
)
599 checkNCName(name
, "1.1".equals(version
));
602 if ("".equals(namespaceURI
))
606 if (name
.startsWith("xml:"))
608 if (namespaceURI
!= null
609 && !XMLConstants
.XML_NS_URI
.equals(namespaceURI
))
611 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
612 "xml namespace is always " +
613 XMLConstants
.XML_NS_URI
, this, 0);
615 namespaceURI
= XMLConstants
.XML_NS_URI
;
617 else if (XMLConstants
.XMLNS_ATTRIBUTE
.equals(name
) ||
618 name
.startsWith("xmlns:"))
620 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
621 "xmlns is reserved", this, 0);
623 else if (namespaceURI
== null && name
.indexOf(':') != -1)
625 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
626 "prefixed name '" + name
+
627 "' needs a URI", this, 0);
630 Element element
= new DomElement(this, namespaceURI
, name
);
631 defaultAttributes(element
, name
);
635 private void defaultAttributes(Element element
, String name
)
637 DomDoctype doctype
= (DomDoctype
) getDoctype();
643 // default any attributes that need it
644 DTDElementTypeInfo info
= doctype
.getElementTypeInfo(name
);
647 for (Iterator i
= info
.attributes(); i
!= null && i
.hasNext(); )
649 DTDAttributeTypeInfo attr
= (DTDAttributeTypeInfo
) i
.next();
650 DomAttr node
= (DomAttr
) createAttribute(attr
.name
);
652 String value
= attr
.value
;
657 node
.setValue(value
);
658 node
.setSpecified(false);
659 element
.setAttributeNode(node
);
666 * Returns a newly created document fragment.
668 public DocumentFragment
createDocumentFragment()
670 return new DomDocumentFragment(this);
675 * Returns a newly created text node with the specified value.
677 public Text
createTextNode(String value
)
679 if (checkingCharacters
)
681 checkChar(value
, "1.1".equals(version
));
683 return new DomText(this, value
);
687 * Returns a newly created text node with the specified value.
689 public Text
createTextNode(char[] buf
, int off
, int len
)
691 if (checkingCharacters
)
693 checkChar(buf
, off
, len
, "1.1".equals(version
));
695 return new DomText(this, buf
, off
, len
);
700 * Returns a newly created comment node with the specified value.
702 public Comment
createComment(String value
)
704 if (checkingCharacters
)
706 checkChar(value
, "1.1".equals(version
));
708 return new DomComment(this, value
);
713 * Returns a newly created CDATA section node with the specified value.
715 public CDATASection
createCDATASection(String value
)
717 if (checkingCharacters
)
719 checkChar(value
, "1.1".equals(version
));
721 return new DomCDATASection(this, value
);
725 * Returns a newly created CDATA section node with the specified value.
727 public CDATASection
createCDATASection(char[] buf
, int off
, int len
)
729 if (checkingCharacters
)
731 checkChar(buf
, off
, len
, "1.1".equals(version
));
733 return new DomCDATASection(this, buf
, off
, len
);
738 * Returns a newly created processing instruction.
740 public ProcessingInstruction
createProcessingInstruction(String target
,
743 if (checkingCharacters
)
745 boolean xml11
= "1.1".equals(version
);
746 checkName(target
, xml11
);
747 if ("xml".equalsIgnoreCase(target
))
749 throw new DomDOMException(DOMException
.SYNTAX_ERR
,
750 "illegal PI target name",
753 checkChar(data
, xml11
);
755 return new DomProcessingInstruction(this, target
, data
);
760 * Returns a newly created attribute with the specified name.
762 public Attr
createAttribute(String name
)
764 if (checkingCharacters
)
766 checkName(name
, "1.1".equals(version
));
768 if (name
.startsWith("xml:"))
770 return createAttributeNS(XMLConstants
.XML_NS_URI
, name
);
772 else if (XMLConstants
.XMLNS_ATTRIBUTE
.equals(name
) ||
773 name
.startsWith("xmlns:"))
775 return createAttributeNS(XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
, name
);
779 return new DomAttr(this, null, name
);
785 * Returns a newly created attribute with the specified name
786 * and namespace information.
788 public Attr
createAttributeNS(String namespaceURI
, String name
)
790 if (checkingCharacters
)
792 checkNCName(name
, "1.1".equals(version
));
795 if ("".equals(namespaceURI
))
799 if (name
.startsWith ("xml:"))
801 if (namespaceURI
== null)
803 namespaceURI
= XMLConstants
.XML_NS_URI
;
805 else if (!XMLConstants
.XML_NS_URI
.equals(namespaceURI
))
807 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
808 "xml namespace is always " +
809 XMLConstants
.XML_NS_URI
,
813 else if (XMLConstants
.XMLNS_ATTRIBUTE
.equals(name
) ||
814 name
.startsWith("xmlns:"))
816 if (namespaceURI
== null)
818 namespaceURI
= XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
;
820 else if (!XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
.equals(namespaceURI
))
822 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
823 "xmlns namespace must be " +
824 XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
,
828 else if (namespaceURI
== null && name
.indexOf(':') != -1)
830 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
831 "prefixed name needs a URI: " + name
, this, 0);
833 return new DomAttr(this, namespaceURI
, name
);
838 * Returns a newly created reference to the specified entity.
839 * The caller should populate this with the appropriate children
840 * and then mark it as readonly.
842 * @see DomNode#makeReadonly
844 public EntityReference
createEntityReference(String name
)
846 DomEntityReference ret
= new DomEntityReference(this, name
);
847 DocumentType doctype
= getDoctype();
850 DomEntity ent
= (DomEntity
) doctype
.getEntities().getNamedItem(name
);
853 for (DomNode ctx
= ent
.first
; ctx
!= null; ctx
= ctx
.next
)
855 ret
.appendChild(ctx
.cloneNode(true));
865 * Makes a copy of the specified node, with all nodes "owned" by
866 * this document and with children optionally copied. This type
867 * of standard utility has become, well, a standard utility.
869 * <p> Note that EntityReference nodes created through this method (either
870 * directly, or recursively) never have children, and that there is no
871 * portable way to associate them with such children.
873 * <p> Note also that there is no requirement that the specified node
874 * be associated with a different document. This differs from the
875 * <em>cloneNode</em> operation in that the node itself is not given
876 * an opportunity to participate, so that any information managed
877 * by node subclasses will be lost.
879 public Node
importNode(Node src
, boolean deep
)
882 switch (src
.getNodeType())
885 dst
= createTextNode(src
.getNodeValue());
887 case CDATA_SECTION_NODE
:
888 dst
= createCDATASection(src
.getNodeValue());
891 dst
= createComment(src
.getNodeValue());
893 case PROCESSING_INSTRUCTION_NODE
:
894 dst
= createProcessingInstruction(src
.getNodeName(),
898 // NOTE: There's no standard way to create
899 // these, or add them to a doctype. Useless.
900 Notation notation
= (Notation
) src
;
901 dst
= new DomNotation(this, notation
.getNodeName(),
902 notation
.getPublicId(),
903 notation
.getSystemId());
906 // NOTE: There's no standard way to create
907 // these, or add them to a doctype. Useless.
908 Entity entity
= (Entity
) src
;
909 dst
= new DomEntity(this, entity
.getNodeName(),
910 entity
.getPublicId(),
911 entity
.getSystemId(),
912 entity
.getNotationName());
915 for (Node ctx
= src
.getFirstChild(); ctx
!= null;
916 ctx
= ctx
.getNextSibling())
918 dst
.appendChild(importNode(ctx
, deep
));
922 case ENTITY_REFERENCE_NODE
:
923 dst
= createEntityReference(src
.getNodeName());
925 case DOCUMENT_FRAGMENT_NODE
:
926 dst
= new DomDocumentFragment(this);
929 for (Node ctx
= src
.getFirstChild(); ctx
!= null;
930 ctx
= ctx
.getNextSibling())
932 dst
.appendChild(importNode(ctx
, deep
));
937 String attr_nsuri
= src
.getNamespaceURI();
938 if (attr_nsuri
!= null)
940 dst
= createAttributeNS(attr_nsuri
, src
.getNodeName());
944 dst
= createAttribute(src
.getNodeName());
946 // this is _always_ done regardless of "deep" setting
947 for (Node ctx
= src
.getFirstChild(); ctx
!= null;
948 ctx
= ctx
.getNextSibling())
950 dst
.appendChild(importNode(ctx
, false));
954 String elem_nsuri
= src
.getNamespaceURI();
955 if (elem_nsuri
!= null)
957 dst
= createElementNS(elem_nsuri
, src
.getNodeName());
961 dst
= createElement(src
.getNodeName());
963 NamedNodeMap srcAttrs
= src
.getAttributes();
964 NamedNodeMap dstAttrs
= dst
.getAttributes();
965 int len
= srcAttrs
.getLength();
966 for (int i
= 0; i
< len
; i
++)
968 Attr a
= (Attr
) srcAttrs
.item(i
);
971 // maybe update defaulted attributes
972 dflt
= (Attr
) dstAttrs
.getNamedItem(a
.getNodeName());
975 String newval
= a
.getNodeValue();
976 if (!dflt
.getNodeValue().equals(newval
)
977 || a
.getSpecified () == true)
979 dflt
.setNodeValue (newval
);
984 dstAttrs
.setNamedItem((Attr
) importNode(a
, false));
988 for (Node ctx
= src
.getFirstChild(); ctx
!= null;
989 ctx
= ctx
.getNextSibling())
991 dst
.appendChild(importNode(ctx
, true));
995 // can't import document or doctype nodes
997 case DOCUMENT_TYPE_NODE
:
999 // can't import unrecognized or nonstandard nodes
1001 throw new DomDOMException(DOMException
.NOT_SUPPORTED_ERR
, null, src
, 0);
1004 // FIXME cleanup a bit -- for deep copies, copy those
1005 // children in one place, here (code sharing is healthy)
1007 if (src
instanceof DomNode
)
1009 ((DomNode
) src
).notifyUserDataHandlers(UserDataHandler
.NODE_IMPORTED
,
1016 * <b>DOM L2 (Traversal)</b>
1017 * Returns a newly created node iterator. Don't forget to detach
1018 * this iterator when you're done using it!
1022 public NodeIterator
createNodeIterator(Node root
,
1025 boolean expandEntities
)
1027 return new DomNodeIterator(root
, whatToShow
, filter
, expandEntities
,
1031 public TreeWalker
createTreeWalker(Node root
,
1034 boolean expandEntities
)
1036 return new DomNodeIterator(root
, whatToShow
, filter
, expandEntities
,
1040 // DOM Level 3 methods
1045 public String
getInputEncoding()
1047 return inputEncoding
;
1050 public void setInputEncoding(String inputEncoding
)
1052 this.inputEncoding
= inputEncoding
;
1058 public String
getXmlEncoding()
1063 public void setXmlEncoding(String encoding
)
1065 this.encoding
= encoding
;
1068 public boolean getXmlStandalone()
1073 public void setXmlStandalone(boolean xmlStandalone
)
1075 standalone
= xmlStandalone
;
1078 public String
getXmlVersion()
1083 public void setXmlVersion(String xmlVersion
)
1085 if (xmlVersion
== null)
1089 if ("1.0".equals(xmlVersion
) ||
1090 "1.1".equals(xmlVersion
))
1092 version
= xmlVersion
;
1096 throw new DomDOMException(DOMException
.NOT_SUPPORTED_ERR
);
1100 public boolean getStrictErrorChecking()
1102 return checkingCharacters
;
1105 public void setStrictErrorChecking(boolean strictErrorChecking
)
1107 checkingCharacters
= strictErrorChecking
;
1110 public String
lookupPrefix(String namespaceURI
)
1112 Node root
= getDocumentElement();
1113 return (root
== null) ?
null : root
.lookupPrefix(namespaceURI
);
1116 public boolean isDefaultNamespace(String namespaceURI
)
1118 Node root
= getDocumentElement();
1119 return (root
== null) ?
false : root
.isDefaultNamespace(namespaceURI
);
1122 public String
lookupNamespaceURI(String prefix
)
1124 Node root
= getDocumentElement();
1125 return (root
== null) ?
null : root
.lookupNamespaceURI(prefix
);
1128 public String
getBaseURI()
1130 return getDocumentURI();
1132 Node root = getDocumentElement();
1135 NamedNodeMap attrs = root.getAttributes();
1136 Node xmlBase = attrs.getNamedItemNS(XMLConstants.XML_NS_URI, "base");
1137 if (xmlBase != null)
1139 return xmlBase.getNodeValue();
1146 public String
getDocumentURI()
1151 public void setDocumentURI(String documentURI
)
1153 systemId
= documentURI
;
1156 public Node
adoptNode(Node source
)
1158 switch (source
.getNodeType())
1161 case DOCUMENT_TYPE_NODE
:
1162 throw new DomDOMException(DOMException
.NOT_SUPPORTED_ERR
);
1165 throw new DomDOMException(DOMException
.NO_MODIFICATION_ALLOWED_ERR
);
1167 if (source
instanceof DomNode
)
1169 DomNode src
= (DomNode
) source
;
1171 if (dst
.parent
!= null)
1173 dst
= (DomNode
) dst
.cloneNode(true);
1176 src
.notifyUserDataHandlers(UserDataHandler
.NODE_ADOPTED
, src
, dst
);
1182 public DOMConfiguration
getDomConfig()
1186 config
= new DomDocumentConfiguration();
1191 public void normalizeDocument()
1193 boolean save
= building
;
1195 normalizeNode(this);
1199 void normalizeNode(DomNode node
)
1204 switch (node
.nodeType
)
1206 case CDATA_SECTION_NODE
:
1207 if (!config
.cdataSections
)
1209 // replace CDATA section with text node
1210 Text text
= createTextNode(node
.getNodeValue());
1211 node
.parent
.insertBefore(text
, node
);
1212 node
.parent
.removeChild(node
);
1213 // merge adjacent text nodes
1214 String data
= text
.getWholeText();
1215 node
= (DomNode
) text
.replaceWholeText(data
);
1217 else if (config
.splitCdataSections
)
1219 String value
= node
.getNodeValue();
1220 int i
= value
.indexOf("]]>");
1223 Node node2
= createCDATASection(value
.substring(0, i
));
1224 node
.parent
.insertBefore(node2
, node
);
1225 value
= value
.substring(i
+ 3);
1226 node
.setNodeValue(value
);
1227 i
= value
.indexOf("]]>");
1232 if (!config
.comments
)
1234 node
.parent
.removeChild(node
);
1238 if (!config
.elementContentWhitespace
&&
1239 ((Text
) node
).isElementContentWhitespace())
1241 node
.parent
.removeChild(node
);
1244 case ENTITY_REFERENCE_NODE
:
1245 if (!config
.entities
)
1247 for (DomNode ctx
= node
.first
; ctx
!= null; )
1249 DomNode ctxNext
= ctx
.next
;
1250 node
.parent
.insertBefore(ctx
, node
);
1253 node
.parent
.removeChild(node
);
1257 if (!config
.namespaceDeclarations
)
1259 DomNamedNodeMap attrs
=
1260 (DomNamedNodeMap
) node
.getAttributes();
1261 boolean aro
= attrs
.readonly
;
1262 attrs
.readonly
= false; // Ensure we can delete if necessary
1263 int len
= attrs
.getLength();
1264 for (int i
= 0; i
< len
; i
++)
1266 Node attr
= attrs
.item(i
);
1267 String namespace
= attr
.getNamespaceURI();
1268 if (XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
.equals(namespace
))
1270 attrs
.removeNamedItemNS(namespace
,
1271 attr
.getLocalName());
1276 attrs
.readonly
= aro
;
1281 for (DomNode ctx
= node
.first
; ctx
!= null; )
1283 DomNode ctxNext
= ctx
.next
;
1289 public Node
renameNode(Node n
, String namespaceURI
, String qualifiedName
)
1292 if (n
instanceof DomNsNode
)
1294 DomNsNode src
= (DomNsNode
) n
;
1297 throw new DomDOMException(DOMException
.NOT_FOUND_ERR
);
1299 if (src
.owner
!= this)
1301 throw new DomDOMException(DOMException
.WRONG_DOCUMENT_ERR
,
1304 boolean xml11
= "1.1".equals(version
);
1305 checkName(qualifiedName
, xml11
);
1306 int ci
= qualifiedName
.indexOf(':');
1307 if ("".equals(namespaceURI
))
1309 namespaceURI
= null;
1311 if (namespaceURI
!= null)
1313 checkNCName(qualifiedName
, xml11
);
1314 String prefix
= (ci
== -1) ?
"" :
1315 qualifiedName
.substring(0, ci
);
1316 if (XMLConstants
.XML_NS_PREFIX
.equals(prefix
) &&
1317 !XMLConstants
.XML_NS_URI
.equals(namespaceURI
))
1319 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
1320 "xml namespace must be " +
1321 XMLConstants
.XML_NS_URI
, src
, 0);
1323 else if (src
.nodeType
== ATTRIBUTE_NODE
&&
1324 (XMLConstants
.XMLNS_ATTRIBUTE
.equals(prefix
) ||
1325 XMLConstants
.XMLNS_ATTRIBUTE
.equals(qualifiedName
)) &&
1326 !XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
.equals(namespaceURI
))
1328 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
1329 "xmlns namespace must be " +
1330 XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
, src
, 0);
1332 if (XMLConstants
.XML_NS_URI
.equals(namespaceURI
) &&
1333 !XMLConstants
.XML_NS_PREFIX
.equals(prefix
))
1335 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
1336 "xml namespace must be " +
1337 XMLConstants
.XML_NS_URI
, src
, 0);
1339 else if (src
.nodeType
== ATTRIBUTE_NODE
&&
1340 XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
.equals(namespaceURI
) &&
1341 !(XMLConstants
.XMLNS_ATTRIBUTE
.equals(prefix
) ||
1342 XMLConstants
.XMLNS_ATTRIBUTE
.equals(qualifiedName
)))
1344 throw new DomDOMException(DOMException
.NAMESPACE_ERR
,
1345 "xmlns namespace must be " +
1346 XMLConstants
.XMLNS_ATTRIBUTE_NS_URI
, src
, 0);
1350 src
.setNodeName(qualifiedName
);
1351 src
.setNamespaceURI(namespaceURI
);
1352 src
.notifyUserDataHandlers(UserDataHandler
.NODE_RENAMED
, src
, src
);
1353 // TODO MutationNameEvents
1354 // DOMElementNameChanged or DOMAttributeNameChanged
1357 throw new DomDOMException(DOMException
.NOT_SUPPORTED_ERR
, null, n
, 0);
1360 // -- XPathEvaluator --
1362 public XPathExpression
createExpression(String expression
,
1363 XPathNSResolver resolver
)
1364 throws XPathException
, DOMException
1366 return new DomXPathExpression(this, expression
, resolver
);
1369 public XPathNSResolver
createNSResolver(Node nodeResolver
)
1371 return new DomXPathNSResolver(nodeResolver
);
1374 public Object
evaluate(String expression
,
1376 XPathNSResolver resolver
,
1379 throws XPathException
, DOMException
1381 XPathExpression xpe
=
1382 new DomXPathExpression(this, expression
, resolver
);
1383 return xpe
.evaluate(contextNode
, type
, result
);