Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / gnu / xml / dom / DomDocument.java
blob900d03ac3dcea866bf60d6b38c807641bfe8afac
1 /* DomDocument.java --
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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. */
38 package gnu.xml.dom;
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;
70 /**
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
83 extends DomNode
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;
95 String inputEncoding;
96 String encoding;
97 String version = "1.0";
98 boolean standalone;
99 String systemId;
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
113 public DomDocument()
115 this(new DomImpl());
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.
124 * @see DomImpl
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)
139 building = 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;
153 * <b>DOM L1</b>
154 * Returns the constant "#document".
156 final public String getNodeName()
158 return "#document";
162 * <b>DOM L1</b>
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;
174 return null;
178 * <b>DOM L1</b>
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;
190 return null;
194 * <b>DOM L1</b>
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)
215 return null;
217 DomDoctype doctype = (DomDoctype) getDoctype();
218 if (doctype != null && !doctype.hasIds())
220 doctype = null;
223 // yes, this is linear in size of document.
224 // it'd be easy enough to maintain a hashtable.
225 Node current = getDocumentElement();
226 Node temp;
228 if (current == null)
230 return null;
232 while (current != this)
234 // done?
235 if (current.getNodeType() == ELEMENT_NODE)
237 DomElement element = (DomElement) current;
238 if (doctype != null)
240 DTDElementTypeInfo info =
241 doctype.getElementTypeInfo(current.getNodeName());
242 if (info != null &&
243 id.equals(element.getAttribute(info.idAttrName)))
245 return element;
247 else if (element.userIdAttrs != null)
249 for (Iterator i = element.userIdAttrs.iterator();
250 i.hasNext(); )
252 Node idAttr = (Node) i.next();
253 if (id.equals(idAttr.getNodeValue()))
255 return element;
260 // xml:id
261 String xmlId = element.getAttribute("xml:id");
262 if (xmlId == null)
264 xmlId = element.getAttributeNS(XMLConstants.XML_NS_URI,
265 "id");
267 if (id.equals(xmlId))
269 return element;
273 // descend?
274 if (current.hasChildNodes())
276 current = current.getFirstChild();
277 continue;
280 // lateral?
281 temp = current.getNextSibling();
282 if (temp != null)
284 current = temp;
285 continue;
288 // back up ...
291 temp = current.getParentNode();
292 if (temp == null)
294 return null;
296 current = temp;
297 temp = current.getNextSibling();
299 while (temp == null);
300 current = temp;
302 return 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);
324 * <b>DOM L1</b>
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);
339 * <b>DOM L1</b>
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);
354 * <b>DOM L1</b>
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
380 * Name.
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)
392 if (name == null)
394 throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0);
396 int len = name.length();
397 if (len == 0)
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);
406 if (xml11)
408 // XML 1.1
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,
426 name, null, c);
429 else
431 // XML 1.0
432 int type = Character.getType(c);
433 switch (type)
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,
445 name, null, c);
447 break;
448 default:
449 if (c != ':' && c != '_' && (c < 0x02bb || c > 0x02c1) &&
450 c != 0x0559 && c != 0x06e5 && c != 0x06e6)
452 throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR,
453 name, null, c);
458 // Subsequent characters
459 for (int i = 1; i < len; i++)
461 c = name.charAt(i);
462 if (xml11)
464 // XML 1.1
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) &&
481 c != 0x00b7 &&
482 (c < 0x0300 || c > 0x036f) &&
483 (c < 0x203f || c > 0x2040))
485 throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, name,
486 null, c);
489 else
491 // XML 1.0
492 int type = Character.getType(c);
493 switch (type)
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,
510 name, null, c);
512 break;
513 default:
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,
519 name, null, c);
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.
530 // package private
531 static void checkNCName(String name, boolean xml11)
533 checkName(name, xml11);
534 int len = name.length();
535 int index = name.indexOf(':');
536 if (index != -1)
538 if (index == 0 || index == (len - 1) ||
539 name.lastIndexOf(':') != index)
541 throw new DomDOMException(DOMException.NAMESPACE_ERR,
542 name, null, 0);
547 // package private
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++)
558 char c = buf[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))
566 continue;
568 if (xml11)
570 if ((c >= 0x0001 && c <= 0x001f) ||
571 (c >= 0x007f && c <= 0x0084) ||
572 (c >= 0x0086 && c <= 0x009f))
574 continue;
577 throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR,
578 new String(buf, off, len), null, c);
583 * <b>DOM L1</b>
584 * Returns a newly created element with the specified name.
586 public Element createElement(String name)
588 Element element;
590 if (checkingCharacters)
592 checkName(name, "1.1".equals(version));
594 if (name.startsWith("xml:"))
596 element = createElementNS(null, name);
598 else
600 DomElement domElement = new DomElement(this, null, name);
601 domElement.localName = null;
602 element = domElement;
604 defaultAttributes(element, name);
605 return element;
609 * <b>DOM L2</b>
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))
622 namespaceURI = null;
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);
650 return element;
653 private void defaultAttributes(Element element, String name)
655 DomDoctype doctype = (DomDoctype) getDoctype();
656 if (doctype == null)
658 return;
661 // default any attributes that need it
662 DTDElementTypeInfo info = doctype.getElementTypeInfo(name);
663 if (info != null)
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;
671 if (value == null)
673 value = "";
675 node.setValue(value);
676 node.setSpecified(false);
677 element.setAttributeNode(node);
683 * <b>DOM L1</b>
684 * Returns a newly created document fragment.
686 public DocumentFragment createDocumentFragment()
688 return new DomDocumentFragment(this);
692 * <b>DOM L1</b>
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);
717 * <b>DOM L1</b>
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);
730 * <b>DOM L1</b>
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);
755 * <b>DOM L1</b>
756 * Returns a newly created processing instruction.
758 public ProcessingInstruction createProcessingInstruction(String target,
759 String data)
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",
769 this, 0);
771 checkChar(data, xml11);
773 return new DomProcessingInstruction(this, target, data);
777 * <b>DOM L1</b>
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);
795 else
797 DomAttr ret = new DomAttr(this, null, name);
798 ret.localName = null;
799 return ret;
804 * <b>DOM L2</b>
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))
817 namespaceURI = null;
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,
830 this, 0);
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,
845 this, 0);
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);
857 * <b>DOM L1</b>
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();
868 if (doctype != null)
870 DomEntity ent = (DomEntity) doctype.getEntities().getNamedItem(name);
871 if (ent != null)
873 for (DomNode ctx = ent.first; ctx != null; ctx = ctx.next)
875 ret.appendChild(ctx.cloneNode(true));
879 ret.makeReadonly();
880 return ret;
884 * <b>DOM L2</b>
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)
901 Node dst = null;
902 switch (src.getNodeType())
904 case TEXT_NODE:
905 dst = createTextNode(src.getNodeValue());
906 break;
907 case CDATA_SECTION_NODE:
908 dst = createCDATASection(src.getNodeValue());
909 break;
910 case COMMENT_NODE:
911 dst = createComment(src.getNodeValue());
912 break;
913 case PROCESSING_INSTRUCTION_NODE:
914 dst = createProcessingInstruction(src.getNodeName(),
915 src.getNodeValue());
916 break;
917 case NOTATION_NODE:
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());
924 break;
925 case ENTITY_NODE:
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());
933 if (deep)
935 for (Node ctx = src.getFirstChild(); ctx != null;
936 ctx = ctx.getNextSibling())
938 dst.appendChild(importNode(ctx, deep));
941 break;
942 case ENTITY_REFERENCE_NODE:
943 dst = createEntityReference(src.getNodeName());
944 break;
945 case DOCUMENT_FRAGMENT_NODE:
946 dst = new DomDocumentFragment(this);
947 if (deep)
949 for (Node ctx = src.getFirstChild(); ctx != null;
950 ctx = ctx.getNextSibling())
952 dst.appendChild(importNode(ctx, deep));
955 break;
956 case ATTRIBUTE_NODE:
957 String attr_nsuri = src.getNamespaceURI();
958 if (attr_nsuri != null)
960 dst = createAttributeNS(attr_nsuri, src.getNodeName());
962 else
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));
972 break;
973 case ELEMENT_NODE:
974 String elem_nsuri = src.getNamespaceURI();
975 if (elem_nsuri != null)
977 dst = createElementNS(elem_nsuri, src.getNodeName());
979 else
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);
989 Attr dflt;
991 // maybe update defaulted attributes
992 dflt = (Attr) dstAttrs.getNamedItem(a.getNodeName());
993 if (dflt != null)
995 String newval = a.getNodeValue();
996 if (!dflt.getNodeValue().equals(newval)
997 || a.getSpecified () == true)
999 dflt.setNodeValue (newval);
1001 continue;
1004 dstAttrs.setNamedItem((Attr) importNode(a, false));
1006 if (deep)
1008 for (Node ctx = src.getFirstChild(); ctx != null;
1009 ctx = ctx.getNextSibling())
1011 dst.appendChild(importNode(ctx, true));
1014 break;
1015 // can't import document or doctype nodes
1016 case DOCUMENT_NODE:
1017 case DOCUMENT_TYPE_NODE:
1018 // FALLTHROUGH
1019 // can't import unrecognized or nonstandard nodes
1020 default:
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,
1030 src, dst);
1032 return dst;
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!
1040 * @see DomIterator
1042 public NodeIterator createNodeIterator(Node root,
1043 int whatToShow,
1044 NodeFilter filter,
1045 boolean expandEntities)
1047 return new DomNodeIterator(root, whatToShow, filter, expandEntities,
1048 false);
1051 public TreeWalker createTreeWalker(Node root,
1052 int whatToShow,
1053 NodeFilter filter,
1054 boolean expandEntities)
1056 return new DomNodeIterator(root, whatToShow, filter, expandEntities,
1057 true);
1060 // DOM Level 3 methods
1063 * DOM L3
1065 public String getInputEncoding()
1067 return inputEncoding;
1070 public void setInputEncoding(String inputEncoding)
1072 this.inputEncoding = inputEncoding;
1076 * DOM L3
1078 public String getXmlEncoding()
1080 return encoding;
1083 public void setXmlEncoding(String encoding)
1085 this.encoding = encoding;
1088 public boolean getXmlStandalone()
1090 return standalone;
1093 public void setXmlStandalone(boolean xmlStandalone)
1095 standalone = xmlStandalone;
1098 public String getXmlVersion()
1100 return version;
1103 public void setXmlVersion(String xmlVersion)
1105 if (xmlVersion == null)
1107 xmlVersion = "1.0";
1109 if ("1.0".equals(xmlVersion) ||
1110 "1.1".equals(xmlVersion))
1112 version = xmlVersion;
1114 else
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();
1153 if (root != null)
1155 NamedNodeMap attrs = root.getAttributes();
1156 Node xmlBase = attrs.getNamedItemNS(XMLConstants.XML_NS_URI, "base");
1157 if (xmlBase != null)
1159 return xmlBase.getNodeValue();
1162 return systemId;
1166 public String getDocumentURI()
1168 return systemId;
1171 public void setDocumentURI(String documentURI)
1173 systemId = documentURI;
1176 public Node adoptNode(Node source)
1178 int sourceNodeType = source.getNodeType();
1179 switch (sourceNodeType)
1181 case DOCUMENT_NODE:
1182 case DOCUMENT_TYPE_NODE:
1183 throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
1184 case ENTITY_NODE:
1185 case NOTATION_NODE:
1186 throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR);
1188 if (source instanceof DomNode)
1190 // GNU native
1191 DomNode src = (DomNode) source;
1192 DomNode dst = src;
1193 if (dst.parent != null)
1195 dst = (DomNode) dst.cloneNode(true);
1197 dst.setOwner(this);
1198 src.notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, src, dst);
1199 return dst;
1201 else
1203 // Some other implementation
1204 Node dst = null;
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);
1217 break;
1219 case Node.CDATA_SECTION_NODE:
1221 CDATASection src = (CDATASection) source;
1222 dst = createCDATASection(src.getData());
1223 break;
1225 case Node.COMMENT_NODE:
1227 Comment src = (Comment) source;
1228 dst = createComment(src.getData());
1229 break;
1231 case Node.DOCUMENT_FRAGMENT_NODE:
1233 DocumentFragment src = (DocumentFragment) source;
1234 dst = createDocumentFragment();
1235 adoptChildren(src, dst);
1236 break;
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);
1249 break;
1251 case Node.ENTITY_REFERENCE_NODE:
1253 EntityReference src = (EntityReference) source;
1254 dst = createEntityReference(src.getNodeName());
1255 adoptChildren(src, dst);
1256 break;
1258 case Node.PROCESSING_INSTRUCTION_NODE:
1260 ProcessingInstruction src = (ProcessingInstruction) source;
1261 dst = createProcessingInstruction(src.getTarget(),
1262 src.getData());
1263 break;
1265 case Node.TEXT_NODE:
1267 Text src = (Text) source;
1268 dst = createTextNode(src.getData());
1269 break;
1272 return dst;
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));
1283 node = next;
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));
1300 else
1302 dstAttrs.setNamedItemNS(adoptNode(node));
1307 public DOMConfiguration getDomConfig()
1309 if (config == null)
1311 config = new DomDocumentConfiguration();
1313 return config;
1316 public boolean isEqualNode(Node arg)
1318 if (!super.isEqualNode(arg))
1319 return false;
1320 Document d = (Document) arg;
1321 String dversion = d.getXmlVersion();
1322 if (dversion == null || !dversion.equals(version))
1323 return false;
1324 boolean dstandalone = d.getXmlStandalone();
1325 if (dstandalone != standalone)
1326 return false;
1327 String dencoding = d.getXmlEncoding();
1328 if (dencoding == null || dencoding.equalsIgnoreCase("UTF-8"))
1330 if (encoding != null && !encoding.equalsIgnoreCase("UTF-8"))
1331 return false;
1333 else
1335 if (!dencoding.equals(encoding))
1336 return false;
1338 return true;
1341 public void normalizeDocument()
1343 boolean save = building;
1344 building = true;
1345 normalizeNode(this);
1346 building = save;
1349 void normalizeNode(DomNode node)
1351 node.normalize();
1352 if (config != null)
1354 switch (node.nodeType)
1356 case CDATA_SECTION_NODE:
1357 if (!config.cdataSections)
1359 // replace CDATA section with text node
1360 Text text = createTextNode(node.getNodeValue());
1361 node.parent.insertBefore(text, node);
1362 node.parent.removeChild(node);
1363 // merge adjacent text nodes
1364 String data = text.getWholeText();
1365 node = (DomNode) text.replaceWholeText(data);
1367 else if (config.splitCdataSections)
1369 String value = node.getNodeValue();
1370 int i = value.indexOf("]]>");
1371 while (i != -1)
1373 Node node2 = createCDATASection(value.substring(0, i));
1374 node.parent.insertBefore(node2, node);
1375 value = value.substring(i + 3);
1376 node.setNodeValue(value);
1377 i = value.indexOf("]]>");
1380 break;
1381 case COMMENT_NODE:
1382 if (!config.comments)
1384 node.parent.removeChild(node);
1386 break;
1387 case TEXT_NODE:
1388 if (!config.elementContentWhitespace &&
1389 ((Text) node).isElementContentWhitespace())
1391 node.parent.removeChild(node);
1393 break;
1394 case ENTITY_REFERENCE_NODE:
1395 if (!config.entities)
1397 for (DomNode ctx = node.first; ctx != null; )
1399 DomNode ctxNext = ctx.next;
1400 node.parent.insertBefore(ctx, node);
1401 ctx = ctxNext;
1403 node.parent.removeChild(node);
1405 break;
1406 case ELEMENT_NODE:
1407 if (!config.namespaceDeclarations)
1409 DomNamedNodeMap attrs =
1410 (DomNamedNodeMap) node.getAttributes();
1411 boolean aro = attrs.readonly;
1412 attrs.readonly = false; // Ensure we can delete if necessary
1413 int len = attrs.getLength();
1414 for (int i = 0; i < len; i++)
1416 Node attr = attrs.item(i);
1417 String namespace = attr.getNamespaceURI();
1418 if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespace))
1420 attrs.removeNamedItemNS(namespace,
1421 attr.getLocalName());
1422 i--;
1423 len--;
1426 attrs.readonly = aro;
1428 break;
1431 for (DomNode ctx = node.first; ctx != null; )
1433 DomNode ctxNext = ctx.next;
1434 normalizeNode(ctx);
1435 ctx = ctxNext;
1439 public Node renameNode(Node n, String namespaceURI, String qualifiedName)
1440 throws DOMException
1442 if (n instanceof DomNsNode)
1444 DomNsNode src = (DomNsNode) n;
1445 if (src == null)
1447 throw new DomDOMException(DOMException.NOT_FOUND_ERR);
1449 if (src.owner != this)
1451 throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR,
1452 null, src, 0);
1454 boolean xml11 = "1.1".equals(version);
1455 checkName(qualifiedName, xml11);
1456 int ci = qualifiedName.indexOf(':');
1457 if ("".equals(namespaceURI))
1459 namespaceURI = null;
1461 if (namespaceURI != null)
1463 checkNCName(qualifiedName, xml11);
1464 String prefix = (ci == -1) ? "" :
1465 qualifiedName.substring(0, ci);
1466 if (XMLConstants.XML_NS_PREFIX.equals(prefix) &&
1467 !XMLConstants.XML_NS_URI.equals(namespaceURI))
1469 throw new DomDOMException(DOMException.NAMESPACE_ERR,
1470 "xml namespace must be " +
1471 XMLConstants.XML_NS_URI, src, 0);
1473 else if (src.nodeType == ATTRIBUTE_NODE &&
1474 (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) ||
1475 XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName)) &&
1476 !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI))
1478 throw new DomDOMException(DOMException.NAMESPACE_ERR,
1479 "xmlns namespace must be " +
1480 XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0);
1482 if (XMLConstants.XML_NS_URI.equals(namespaceURI) &&
1483 !XMLConstants.XML_NS_PREFIX.equals(prefix))
1485 throw new DomDOMException(DOMException.NAMESPACE_ERR,
1486 "xml namespace must be " +
1487 XMLConstants.XML_NS_URI, src, 0);
1489 else if (src.nodeType == ATTRIBUTE_NODE &&
1490 XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI) &&
1491 !(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) ||
1492 XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName)))
1494 throw new DomDOMException(DOMException.NAMESPACE_ERR,
1495 "xmlns namespace must be " +
1496 XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0);
1500 src.setNodeName(qualifiedName);
1501 src.setNamespaceURI(namespaceURI);
1502 src.notifyUserDataHandlers(UserDataHandler.NODE_RENAMED, src, src);
1503 // TODO MutationNameEvents
1504 // DOMElementNameChanged or DOMAttributeNameChanged
1505 return src;
1507 throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, n, 0);
1510 // -- XPathEvaluator --
1512 public XPathExpression createExpression(String expression,
1513 XPathNSResolver resolver)
1514 throws XPathException, DOMException
1516 return new DomXPathExpression(this, expression, resolver);
1519 public XPathNSResolver createNSResolver(Node nodeResolver)
1521 return new DomXPathNSResolver(nodeResolver);
1524 public Object evaluate(String expression,
1525 Node contextNode,
1526 XPathNSResolver resolver,
1527 short type,
1528 Object result)
1529 throws XPathException, DOMException
1531 XPathExpression xpe =
1532 new DomXPathExpression(this, expression, resolver);
1533 return xpe.evaluate(contextNode, type, result);