1 /* DomDocument.java --
2    Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
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.
10 
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.
15 
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.
20 
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.
25 
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. */
37 
38 package gnu.xml.dom;
39 
40 import java.util.Iterator;
41 import javax.xml.XMLConstants;
42 
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;
69 
70 /**
71  * <p> "Document" and "DocumentTraversal" implementation.
72  *
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.)
78  *
79  * @author David Brownell
80  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
81  */
82 public class DomDocument
83   extends DomNode
84   implements Document, DocumentTraversal, XPathEvaluator
85 {
86 
87   private final DOMImplementation implementation;
88   private boolean checkingCharacters = true;
89   boolean checkingWellformedness = true;
90   private boolean defaultAttributes = true;
91 
92   boolean building; // if true, skip mutation events in the tree
93 
94   DomDocumentConfiguration config;
95 
96   String inputEncoding;
97   String encoding;
98   String version = "1.0";
99   boolean standalone;
100   String systemId;
101 
102   /**
103    * Constructs a Document node, associating it with an instance
104    * of the DomImpl class.
105    *
106    * <p> Note that this constructor disables character checking.
107    * It is normally used when connecting a DOM to an XML parser,
108    * and duplicating such checks is undesirable.  When used for
109    * purposes other than connecting to a parser, you should
110    * re-enable that checking.
111    *
112    * @see #setCheckingCharacters
113    */
DomDocument()114   public DomDocument()
115   {
116     this(new DomImpl());
117   }
118 
119   /**
120    * Constructs a Document node, associating it with the specified
121    * implementation.  This should only be used in conjunction with
122    * a specialized implementation; it will normally be called by
123    * that implementation.
124    *
125    * @see DomImpl
126    * @see #setCheckingCharacters
127    */
DomDocument(DOMImplementation impl)128   protected DomDocument(DOMImplementation impl)
129   {
130     super(DOCUMENT_NODE, null);
131     implementation = impl;
132   }
133 
134   /**
135    * Sets the <code>building</code> flag.
136    * Mutation events in the document are not reported.
137    */
setBuilding(boolean flag)138   public void setBuilding(boolean flag)
139   {
140     building = flag;
141   }
142 
143   /**
144    * Sets whether to check for document well-formedness.
145    * If true, an exception will be raised if a second doctype or root
146    * element node is added to the document.
147    */
setCheckWellformedness(boolean flag)148   public void setCheckWellformedness(boolean flag)
149   {
150     checkingWellformedness = flag;
151   }
152 
153   /**
154    * Sets whether to check for document characters.
155    */
setCheckingCharacters(boolean flag)156   public void setCheckingCharacters(boolean flag)
157   {
158     checkingCharacters = flag;
159   }
160 
161   /**
162    * Sets whether to default attributes for new elements.
163    */
setDefaultAttributes(boolean flag)164   public void setDefaultAttributes(boolean flag)
165   {
166     defaultAttributes = flag;
167   }
168 
169   /**
170    * <b>DOM L1</b>
171    * Returns the constant "#document".
172    */
getNodeName()173   final public String getNodeName()
174   {
175     return "#document";
176   }
177 
178   /**
179    * <b>DOM L1</b>
180    * Returns the document's root element, or null.
181    */
getDocumentElement()182   final public Element getDocumentElement()
183   {
184     for (DomNode ctx = first; ctx != null; ctx = ctx.next)
185       {
186         if (ctx.nodeType == ELEMENT_NODE)
187           {
188             return (Element) ctx;
189           }
190       }
191     return null;
192   }
193 
194   /**
195    * <b>DOM L1</b>
196    * Returns the document's DocumentType, or null.
197    */
getDoctype()198   final public DocumentType getDoctype()
199   {
200     for (DomNode ctx = first; ctx != null; ctx = ctx.next)
201       {
202       if (ctx.nodeType == DOCUMENT_TYPE_NODE)
203           {
204             return (DocumentType) ctx;
205           }
206       }
207     return null;
208   }
209 
210   /**
211    * <b>DOM L1</b>
212    * Returns the document's DOMImplementation.
213    */
getImplementation()214   final public DOMImplementation getImplementation()
215   {
216     return implementation;
217   }
218 
219   /**
220    * <b>DOM L1 (relocated in DOM L2)</b>
221    * Returns the element with the specified "ID" attribute, or null.
222    *
223    * <p>Returns null unless {@link Consumer} was used to populate internal
224    * DTD declaration information, using package-private APIs.  If that
225    * internal DTD information is available, the document may be searched for
226    * the element with that ID.
227    */
getElementById(String id)228   public Element getElementById(String id)
229   {
230     if (id == null || id.length() == 0)
231       {
232         return null;
233       }
234     DomDoctype doctype = (DomDoctype) getDoctype();
235     if (doctype != null && !doctype.hasIds())
236       {
237         doctype = null;
238       }
239 
240     // yes, this is linear in size of document.
241     // it'd be easy enough to maintain a hashtable.
242     Node current = getDocumentElement();
243     Node temp;
244 
245     if (current == null)
246       {
247         return null;
248       }
249     while (current != this)
250       {
251         // done?
252         if (current.getNodeType() == ELEMENT_NODE)
253           {
254             DomElement element = (DomElement) current;
255             if (element.userIdAttrs != null)
256               {
257                 for (Iterator i = element.userIdAttrs.iterator();
258                      i.hasNext(); )
259                   {
260                     Node idAttr = (Node) i.next();
261                     if (id.equals(idAttr.getNodeValue()))
262                       {
263                         return element;
264                       }
265                   }
266               }
267             if (doctype != null)
268               {
269                 DTDElementTypeInfo info =
270                   doctype.getElementTypeInfo(current.getNodeName());
271                 if (info != null &&
272                     id.equals(element.getAttribute(info.idAttrName)))
273                   {
274                     return element;
275                   }
276               }
277             // xml:id
278             String xmlId = element.getAttribute("xml:id");
279             if (xmlId == null)
280               {
281                 xmlId = element.getAttributeNS(XMLConstants.XML_NS_URI,
282                                                "id");
283               }
284             if (id.equals(xmlId))
285               {
286                 return element;
287               }
288           }
289 
290         // descend?
291         if (current.hasChildNodes())
292           {
293             current = current.getFirstChild();
294             continue;
295           }
296 
297         // lateral?
298         temp = current.getNextSibling();
299         if (temp != null)
300           {
301             current = temp;
302             continue;
303           }
304 
305         // back up ...
306         do
307           {
308             temp = current.getParentNode();
309             if (temp == null)
310               {
311                 return null;
312               }
313             current = temp;
314             temp = current.getNextSibling();
315           }
316         while (temp == null);
317         current = temp;
318       }
319     return null;
320   }
321 
checkNewChild(Node newChild)322   private void checkNewChild(Node newChild)
323   {
324     if (newChild.getNodeType() == ELEMENT_NODE
325         && getDocumentElement() != null)
326       {
327         throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR,
328                                   "document element already present: " +
329                                   getDocumentElement(), newChild, 0);
330       }
331     if (newChild.getNodeType() == DOCUMENT_TYPE_NODE
332         && getDoctype() != null)
333       {
334         throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR,
335                                   "document type already present: " +
336                                   getDoctype(), newChild, 0);
337       }
338   }
339 
340   /**
341    * <b>DOM L1</b>
342    * Appends the specified node to this node's list of children,
343    * enforcing the constraints that there be only one root element
344    * and one document type child.
345    */
appendChild(Node newChild)346   public Node appendChild(Node newChild)
347   {
348     if (checkingWellformedness)
349       {
350         checkNewChild(newChild);
351       }
352     return super.appendChild(newChild);
353   }
354 
355   /**
356    * <b>DOM L1</b>
357    * Inserts the specified node in this node's list of children,
358    * enforcing the constraints that there be only one root element
359    * and one document type child.
360    */
insertBefore(Node newChild, Node refChild)361   public Node insertBefore(Node newChild, Node refChild)
362   {
363     if (checkingWellformedness)
364       {
365         checkNewChild(newChild);
366       }
367     return super.insertBefore(newChild, refChild);
368   }
369 
370   /**
371    * <b>DOM L1</b>
372    * Replaces the specified node in this node's list of children,
373    * enforcing the constraints that there be only one root element
374    * and one document type child.
375    */
replaceChild(Node newChild, Node refChild)376   public Node replaceChild(Node newChild, Node refChild)
377   {
378     if (checkingWellformedness &&
379         ((newChild.getNodeType() == ELEMENT_NODE &&
380           refChild.getNodeType() != ELEMENT_NODE) ||
381          (newChild.getNodeType() == DOCUMENT_TYPE_NODE &&
382           refChild.getNodeType() != DOCUMENT_TYPE_NODE)))
383       {
384         checkNewChild(newChild);
385       }
386     return super.replaceChild(newChild, refChild);
387   }
388 
389   // NOTE:  DOM can't really tell when the name of an entity,
390   // notation, or PI must follow the namespace rules (excluding
391   // colons) instead of the XML rules (which allow them without
392   // much restriction).  That's an API issue.  verifyXmlName
393   // aims to enforce the XML rules, not the namespace rules.
394 
395   /**
396    * Throws a DOM exception if the specified name is not a legal XML 1.0
397    * Name.
398    * @deprecated This method is deprecated and may be removed in future
399    * versions of GNU JAXP
400    */
verifyXmlName(String name)401   public static void verifyXmlName(String name)
402   {
403     // XXX why is this public?
404     checkName(name, false);
405   }
406 
checkName(String name, boolean xml11)407   static void checkName(String name, boolean xml11)
408   {
409     if (name == null)
410       {
411         throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0);
412       }
413     int len = name.length();
414     if (len == 0)
415       {
416         throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0);
417       }
418 
419     // dog: rewritten to use the rules for XML 1.0 and 1.1
420 
421     // Name start character
422     char c = name.charAt(0);
423     if (xml11)
424       {
425         // XML 1.1
426         if ((c < 0x0041 || c > 0x005a) &&
427             (c < 0x0061 || c > 0x007a) &&
428             c != ':' && c != '_' &&
429             (c < 0x00c0 || c > 0x00d6) &&
430             (c < 0x00d8 || c > 0x00f6) &&
431             (c < 0x00f8 || c > 0x02ff) &&
432             (c < 0x0370 || c > 0x037d) &&
433             (c < 0x037f || c > 0x1fff) &&
434             (c < 0x200c || c > 0x200d) &&
435             (c < 0x2070 || c > 0x218f) &&
436             (c < 0x2c00 || c > 0x2fef) &&
437             (c < 0x3001 || c > 0xd7ff) &&
438             (c < 0xf900 || c > 0xfdcf) &&
439             (c < 0xfdf0 || c > 0xfffd) &&
440             (c < 0x10000 || c > 0xeffff))
441           {
442             throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR,
443                                       name, null, c);
444           }
445       }
446     else
447       {
448         // XML 1.0
449         int type = Character.getType(c);
450         switch (type)
451           {
452           case Character.LOWERCASE_LETTER: // Ll
453           case Character.UPPERCASE_LETTER: // Lu
454           case Character.OTHER_LETTER: // Lo
455           case Character.TITLECASE_LETTER: // Lt
456           case Character.LETTER_NUMBER: // Nl
457             if ((c > 0xf900 && c < 0xfffe) ||
458                 (c >= 0x20dd && c <= 0x20e0))
459               {
460                 // Compatibility area and Unicode 2.0 exclusions
461                 throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR,
462                                           name, null, c);
463               }
464             break;
465           default:
466             if (c != ':' && c != '_' && (c < 0x02bb || c > 0x02c1) &&
467                 c != 0x0559 && c != 0x06e5 && c != 0x06e6)
468               {
469                 throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR,
470                                           name, null, c);
471               }
472           }
473       }
474 
475     // Subsequent characters
476     for (int i = 1; i < len; i++)
477       {
478         c = name.charAt(i);
479         if (xml11)
480           {
481             // XML 1.1
482             if ((c < 0x0041 || c > 0x005a) &&
483                 (c < 0x0061 || c > 0x007a) &&
484                 (c < 0x0030 || c > 0x0039) &&
485                 c != ':' && c != '_' && c != '-' && c != '.' &&
486                 (c < 0x00c0 || c > 0x00d6) &&
487                 (c < 0x00d8 || c > 0x00f6) &&
488                 (c < 0x00f8 || c > 0x02ff) &&
489                 (c < 0x0370 || c > 0x037d) &&
490                 (c < 0x037f || c > 0x1fff) &&
491                 (c < 0x200c || c > 0x200d) &&
492                 (c < 0x2070 || c > 0x218f) &&
493                 (c < 0x2c00 || c > 0x2fef) &&
494                 (c < 0x3001 || c > 0xd7ff) &&
495                 (c < 0xf900 || c > 0xfdcf) &&
496                 (c < 0xfdf0 || c > 0xfffd) &&
497                 (c < 0x10000 || c > 0xeffff) &&
498                 c != 0x00b7 &&
499                 (c < 0x0300 || c > 0x036f) &&
500                 (c < 0x203f || c > 0x2040))
501               {
502                 throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, name,
503                                           null, c);
504               }
505           }
506         else
507           {
508             // XML 1.0
509             int type = Character.getType(c);
510             switch (type)
511               {
512               case Character.LOWERCASE_LETTER: // Ll
513               case Character.UPPERCASE_LETTER: // Lu
514               case Character.DECIMAL_DIGIT_NUMBER: // Nd
515               case Character.OTHER_LETTER: // Lo
516               case Character.TITLECASE_LETTER: // Lt
517               case Character.LETTER_NUMBER: // Nl
518               case Character.COMBINING_SPACING_MARK: // Mc
519               case Character.ENCLOSING_MARK: // Me
520               case Character.NON_SPACING_MARK: // Mn
521               case Character.MODIFIER_LETTER: // Lm
522                 if ((c > 0xf900 && c < 0xfffe) ||
523                     (c >= 0x20dd && c <= 0x20e0))
524                   {
525                     // Compatibility area and Unicode 2.0 exclusions
526                     throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR,
527                                               name, null, c);
528                   }
529                 break;
530               default:
531                 if (c != '-' && c != '.' && c != ':' && c != '_' &&
532                     c != 0x0387 && (c < 0x02bb || c > 0x02c1) &&
533                     c != 0x0559 && c != 0x06e5 && c != 0x06e6 && c != 0x00b7)
534                   {
535                     throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR,
536                                               name, null, c);
537                   }
538               }
539           }
540       }
541 
542     // FIXME characters with a font or compatibility decomposition (i.e.
543     // those with a "compatibility formatting tag" in field 5 of the
544     // database -- marked by field 5 beginning with a "<") are not allowed.
545   }
546 
547   // package private
checkNCName(String name, boolean xml11)548   static void checkNCName(String name, boolean xml11)
549   {
550     checkName(name, xml11);
551     int len = name.length();
552     int index = name.indexOf(':');
553     if (index != -1)
554       {
555         if (index == 0 || index == (len - 1) || name.lastIndexOf(':') != index)
556           {
557             throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0);
558           }
559       }
560   }
561 
562   // package private
checkChar(String value, boolean xml11)563   static void checkChar(String value, boolean xml11)
564   {
565     char[] chars = value.toCharArray();
566     checkChar(chars, 0, chars.length, xml11);
567   }
568 
checkChar(char[] buf, int off, int len, boolean xml11)569   static void checkChar(char[] buf, int off, int len, boolean xml11)
570   {
571     for (int i = 0; i < len; i++)
572       {
573         char c = buf[i];
574 
575         // assume surrogate pairing checks out OK, for simplicity
576         if ((c >= 0x0020 && c <= 0xd7ff) ||
577             (c == 0x000a || c == 0x000d || c == 0x0009) ||
578             (c >= 0xe000 && c <= 0xfffd) ||
579             (c >= 0x10000 && c <= 0x10ffff))
580           {
581             continue;
582           }
583         if (xml11)
584           {
585             if ((c >= 0x0001 && c <= 0x001f) ||
586                 (c >= 0x007f && c <= 0x0084) ||
587                 (c >= 0x0086 && c <= 0x009f))
588               {
589                 continue;
590               }
591           }
592         throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR,
593                                   new String(buf, off, len), null, c);
594       }
595   }
596 
597   /**
598    * <b>DOM L1</b>
599    * Returns a newly created element with the specified name.
600    * The node name of the created element will be equal to {@code name}.
601    * The namespace, prefix and local name will all be {@code null}.
602    */
createElement(String name)603   public Element createElement(String name)
604   {
605     Element element;
606 
607     if (checkingCharacters)
608       {
609         checkName(name, "1.1".equals(version));
610       }
611     if (name.startsWith("xml:"))
612       {
613         element = createElementNS(null, name);
614       }
615     else
616       {
617         DomElement domElement = new DomElement(this, null, name, null, null);
618         element = domElement;
619       }
620     if (defaultAttributes)
621       setDefaultAttributes(element, name);
622     return element;
623   }
624 
625   /**
626    * <b>DOM L2</b>
627    * Returns a newly created element with the specified name
628    * and namespace information.
629    */
createElementNS(String namespaceURI, String name)630   public Element createElementNS(String namespaceURI, String name)
631   {
632     if (checkingCharacters)
633       {
634         checkNCName(name, "1.1".equals(version));
635       }
636 
637     if ("".equals(namespaceURI))
638       {
639         namespaceURI = null;
640       }
641     if (name.startsWith("xml:"))
642       {
643         if (namespaceURI != null
644             && !XMLConstants.XML_NS_URI.equals(namespaceURI))
645           {
646             throw new DomDOMException(DOMException.NAMESPACE_ERR,
647                                       "xml namespace is always " +
648                                       XMLConstants.XML_NS_URI, this, 0);
649           }
650         namespaceURI = XMLConstants.XML_NS_URI;
651       }
652     else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) ||
653              name.startsWith("xmlns:"))
654       {
655         throw new DomDOMException(DOMException.NAMESPACE_ERR,
656                                   "xmlns is reserved", this, 0);
657       }
658     else if (namespaceURI == null && name.indexOf(':') != -1)
659       {
660         throw new DomDOMException(DOMException.NAMESPACE_ERR,
661                                   "prefixed name '" + name +
662                                   "' needs a URI", this, 0);
663       }
664 
665     Element  element = new DomElement(this, namespaceURI, name);
666     if (defaultAttributes)
667       setDefaultAttributes(element, name);
668     return element;
669   }
670 
setDefaultAttributes(Element element, String name)671   private void setDefaultAttributes(Element element, String name)
672   {
673     DomDoctype doctype = (DomDoctype) getDoctype();
674     if (doctype == null)
675       {
676         return;
677       }
678 
679     // default any attributes that need it
680     DTDElementTypeInfo info = doctype.getElementTypeInfo(name);
681     if (info != null)
682       {
683         for (Iterator i = info.attributes(); i != null && i.hasNext(); )
684           {
685             DTDAttributeTypeInfo attr = (DTDAttributeTypeInfo) i.next();
686             String value = attr.value;
687             if ("#IMPLIED".equals(attr.mode) && value == null)
688               continue;
689             DomAttr node = (DomAttr) createAttribute(attr.name);
690 
691             if (value == null)
692               {
693                 value = "";
694               }
695             node.setValue(value);
696             node.setSpecified(false);
697             element.setAttributeNode(node);
698           }
699       }
700   }
701 
702   /**
703    * <b>DOM L1</b>
704    * Returns a newly created document fragment.
705    */
createDocumentFragment()706   public DocumentFragment createDocumentFragment()
707   {
708     return new DomDocumentFragment(this);
709   }
710 
711   /**
712    * <b>DOM L1</b>
713    * Returns a newly created text node with the specified value.
714    */
createTextNode(String value)715   public Text createTextNode(String value)
716   {
717     if (checkingCharacters)
718       {
719         checkChar(value, "1.1".equals(version));
720       }
721     return new DomText(this, value);
722   }
723 
724   /**
725    * Returns a newly created text node with the specified value.
726    */
createTextNode(char[] buf, int off, int len)727   public Text createTextNode(char[] buf, int off, int len)
728   {
729     if (checkingCharacters)
730       {
731         checkChar(buf, off, len, "1.1".equals(version));
732       }
733     return new DomText(this, buf, off, len);
734   }
735 
736   /**
737    * <b>DOM L1</b>
738    * Returns a newly created comment node with the specified value.
739    */
createComment(String value)740   public Comment createComment(String value)
741   {
742     if (checkingCharacters)
743       {
744         checkChar(value, "1.1".equals(version));
745       }
746     return new DomComment(this, value);
747   }
748 
749   /**
750    * <b>DOM L1</b>
751    * Returns a newly created CDATA section node with the specified value.
752    */
createCDATASection(String value)753   public CDATASection createCDATASection(String value)
754   {
755     if (checkingCharacters)
756       {
757         checkChar(value, "1.1".equals(version));
758       }
759     return new DomCDATASection(this, value);
760   }
761 
762   /**
763    * Returns a newly created CDATA section node with the specified value.
764    */
createCDATASection(char[] buf, int off, int len)765   public CDATASection createCDATASection(char[] buf, int off, int len)
766   {
767     if (checkingCharacters)
768       {
769         checkChar(buf, off, len, "1.1".equals(version));
770       }
771     return new DomCDATASection(this, buf, off, len);
772   }
773 
774   /**
775    * <b>DOM L1</b>
776    * Returns a newly created processing instruction.
777    */
createProcessingInstruction(String target, String data)778   public ProcessingInstruction createProcessingInstruction(String target,
779                                                            String data)
780   {
781     if (checkingCharacters)
782       {
783         boolean xml11 = "1.1".equals(version);
784         checkName(target, xml11);
785         if ("xml".equalsIgnoreCase(target))
786           {
787             throw new DomDOMException(DOMException.SYNTAX_ERR,
788                                       "illegal PI target name",
789                                       this, 0);
790           }
791         checkChar(data, xml11);
792       }
793     return new DomProcessingInstruction(this, target, data);
794   }
795 
796   /**
797    * <b>DOM L1</b>
798    * Returns a newly created attribute with the specified name.
799    */
createAttribute(String name)800   public Attr createAttribute(String name)
801   {
802     if (checkingCharacters)
803       {
804         checkName(name, "1.1".equals(version));
805       }
806     if (name.startsWith("xml:"))
807       {
808         return createAttributeNS(XMLConstants.XML_NS_URI, name);
809       }
810     else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) ||
811              name.startsWith("xmlns:"))
812       {
813         return createAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, name);
814       }
815     else
816       {
817         DomAttr ret = new DomAttr(this, null, name, null, null);
818         return ret;
819       }
820   }
821 
822   /**
823    * <b>DOM L2</b>
824    * Returns a newly created attribute with the specified name
825    * and namespace information.
826    */
createAttributeNS(String namespaceURI, String name)827   public Attr createAttributeNS(String namespaceURI, String name)
828   {
829     if (checkingCharacters)
830       {
831         checkNCName(name, "1.1".equals(version));
832       }
833 
834     if ("".equals(namespaceURI))
835       {
836         namespaceURI = null;
837       }
838     if (name.startsWith ("xml:"))
839       {
840         if (namespaceURI == null)
841           {
842             namespaceURI = XMLConstants.XML_NS_URI;
843           }
844         else if (!XMLConstants.XML_NS_URI.equals(namespaceURI))
845           {
846             throw new DomDOMException(DOMException.NAMESPACE_ERR,
847                                       "xml namespace is always " +
848                                       XMLConstants.XML_NS_URI,
849                                       this, 0);
850           }
851       }
852     else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) ||
853              name.startsWith("xmlns:"))
854       {
855         if (namespaceURI == null)
856           {
857             namespaceURI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
858           }
859         else if (!XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI))
860           {
861             throw new DomDOMException(DOMException.NAMESPACE_ERR,
862                                       "xmlns namespace must be " +
863                                       XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
864                                       this, 0);
865           }
866       }
867     else if (namespaceURI == null && name.indexOf(':') != -1)
868       {
869         throw new DomDOMException(DOMException.NAMESPACE_ERR,
870                         "prefixed name needs a URI: " + name, this, 0);
871       }
872     return new DomAttr(this, namespaceURI, name);
873   }
874 
875   /**
876    * <b>DOM L1</b>
877    * Returns a newly created reference to the specified entity.
878    * The caller should populate this with the appropriate children
879    * and then mark it as readonly.
880    *
881    * @see DomNode#makeReadonly
882    */
createEntityReference(String name)883   public EntityReference createEntityReference(String name)
884   {
885     DomEntityReference ret = new DomEntityReference(this, name);
886     DocumentType doctype = getDoctype();
887     if (doctype != null)
888       {
889         DomEntity ent = (DomEntity) doctype.getEntities().getNamedItem(name);
890         if (ent != null)
891           {
892             for (DomNode ctx = ent.first; ctx != null; ctx = ctx.next)
893               {
894                 ret.appendChild(ctx.cloneNode(true));
895               }
896           }
897       }
898     ret.makeReadonly();
899     return ret;
900   }
901 
902   /**
903    * <b>DOM L2</b>
904    * Makes a copy of the specified node, with all nodes "owned" by
905    * this document and with children optionally copied.  This type
906    * of standard utility has become, well, a standard utility.
907    *
908    * <p> Note that EntityReference nodes created through this method (either
909    * directly, or recursively) never have children, and that there is no
910    * portable way to associate them with such children.
911    *
912    * <p> Note also that there is no requirement that the specified node
913    * be associated with a different document.  This differs from the
914    * <em>cloneNode</em> operation in that the node itself is not given
915    * an opportunity to participate, so that any information managed
916    * by node subclasses will be lost.
917    */
importNode(Node src, boolean deep)918   public Node importNode(Node src, boolean deep)
919   {
920     Node dst = null;
921     switch (src.getNodeType())
922       {
923       case TEXT_NODE:
924         dst = createTextNode(src.getNodeValue());
925         break;
926       case CDATA_SECTION_NODE:
927         dst = createCDATASection(src.getNodeValue());
928         break;
929       case COMMENT_NODE:
930         dst = createComment(src.getNodeValue());
931         break;
932       case PROCESSING_INSTRUCTION_NODE:
933         dst = createProcessingInstruction(src.getNodeName(),
934                                           src.getNodeValue());
935         break;
936       case NOTATION_NODE:
937         // NOTE:  There's no standard way to create
938         // these, or add them to a doctype.  Useless.
939         Notation notation = (Notation) src;
940         dst = new DomNotation(this, notation.getNodeName(),
941                               notation.getPublicId(),
942                               notation.getSystemId());
943         break;
944       case ENTITY_NODE:
945         // NOTE:  There's no standard way to create
946         // these, or add them to a doctype.  Useless.
947         Entity entity = (Entity) src;
948         dst = new DomEntity(this, entity.getNodeName(),
949                             entity.getPublicId(),
950                             entity.getSystemId(),
951                             entity.getNotationName());
952         if (deep)
953           {
954             for (Node ctx = src.getFirstChild(); ctx != null;
955                  ctx = ctx.getNextSibling())
956               {
957                 dst.appendChild(importNode(ctx, deep));
958               }
959           }
960         break;
961       case ENTITY_REFERENCE_NODE:
962         dst = createEntityReference(src.getNodeName());
963         break;
964       case DOCUMENT_FRAGMENT_NODE:
965         dst = new DomDocumentFragment(this);
966         if (deep)
967           {
968             for (Node ctx = src.getFirstChild(); ctx != null;
969                  ctx = ctx.getNextSibling())
970               {
971                 dst.appendChild(importNode(ctx, deep));
972               }
973           }
974         break;
975       case ATTRIBUTE_NODE:
976         String attr_nsuri = src.getNamespaceURI();
977         if (attr_nsuri != null)
978           {
979             dst = createAttributeNS(attr_nsuri, src.getNodeName());
980           }
981         else
982           {
983             dst = createAttribute(src.getNodeName());
984           }
985         // this is _always_ done regardless of "deep" setting
986         for (Node ctx = src.getFirstChild(); ctx != null;
987              ctx = ctx.getNextSibling())
988           {
989             dst.appendChild(importNode(ctx, false));
990           }
991         break;
992       case ELEMENT_NODE:
993         String elem_nsuri = src.getNamespaceURI();
994         if (elem_nsuri != null)
995           {
996             dst = createElementNS(elem_nsuri, src.getNodeName());
997           }
998         else
999           {
1000             dst = createElement(src.getNodeName());
1001           }
1002         NamedNodeMap srcAttrs = src.getAttributes();
1003         NamedNodeMap dstAttrs = dst.getAttributes();
1004         int len = srcAttrs.getLength();
1005         for (int i = 0; i < len; i++)
1006           {
1007             Attr a = (Attr) srcAttrs.item(i);
1008             Attr dflt;
1009 
1010             // maybe update defaulted attributes
1011             dflt = (Attr) dstAttrs.getNamedItem(a.getNodeName());
1012             if (dflt != null)
1013               {
1014                 String newval = a.getNodeValue();
1015                 if (!dflt.getNodeValue().equals(newval)
1016                     || a.getSpecified () == true)
1017                   {
1018                     dflt.setNodeValue (newval);
1019                   }
1020                 continue;
1021               }
1022 
1023             dstAttrs.setNamedItem((Attr) importNode(a, false));
1024           }
1025         if (deep)
1026           {
1027             for (Node ctx = src.getFirstChild(); ctx != null;
1028                  ctx = ctx.getNextSibling())
1029               {
1030                 dst.appendChild(importNode(ctx, true));
1031               }
1032           }
1033         break;
1034         // can't import document or doctype nodes
1035       case DOCUMENT_NODE:
1036       case DOCUMENT_TYPE_NODE:
1037         // FALLTHROUGH
1038         // can't import unrecognized or nonstandard nodes
1039       default:
1040         throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, src, 0);
1041       }
1042 
1043     // FIXME cleanup a bit -- for deep copies, copy those
1044     // children in one place, here (code sharing is healthy)
1045 
1046     if (src instanceof DomNode)
1047       {
1048         ((DomNode) src).notifyUserDataHandlers(UserDataHandler.NODE_IMPORTED,
1049                                                src, dst);
1050       }
1051     return dst;
1052   }
1053 
1054   /**
1055    * <b>DOM L2 (Traversal)</b>
1056    * Returns a newly created node iterator.  Don't forget to detach
1057    * this iterator when you're done using it!
1058    *
1059    * @see DomIterator
1060    */
createNodeIterator(Node root, int whatToShow, NodeFilter filter, boolean expandEntities)1061   public NodeIterator createNodeIterator(Node root,
1062                                          int whatToShow,
1063                                          NodeFilter filter,
1064                                          boolean expandEntities)
1065   {
1066     return new DomNodeIterator(root, whatToShow, filter, expandEntities,
1067                                false);
1068   }
1069 
createTreeWalker(Node root, int whatToShow, NodeFilter filter, boolean expandEntities)1070   public TreeWalker createTreeWalker(Node root,
1071                                      int whatToShow,
1072                                      NodeFilter filter,
1073                                      boolean expandEntities)
1074   {
1075     return new DomNodeIterator(root, whatToShow, filter, expandEntities,
1076                                true);
1077   }
1078 
1079   // DOM Level 3 methods
1080 
1081   /**
1082    * DOM L3
1083    */
getInputEncoding()1084   public String getInputEncoding()
1085   {
1086     return inputEncoding;
1087   }
1088 
setInputEncoding(String inputEncoding)1089   public void setInputEncoding(String inputEncoding)
1090   {
1091     this.inputEncoding = inputEncoding;
1092   }
1093 
1094   /**
1095    * DOM L3
1096    */
getXmlEncoding()1097   public String getXmlEncoding()
1098   {
1099     return encoding;
1100   }
1101 
setXmlEncoding(String encoding)1102   public void setXmlEncoding(String encoding)
1103   {
1104     this.encoding = encoding;
1105   }
1106 
getXmlStandalone()1107   public boolean getXmlStandalone()
1108   {
1109     return standalone;
1110   }
1111 
setXmlStandalone(boolean xmlStandalone)1112   public void setXmlStandalone(boolean xmlStandalone)
1113   {
1114     standalone = xmlStandalone;
1115   }
1116 
getXmlVersion()1117   public String getXmlVersion()
1118   {
1119     return version;
1120   }
1121 
setXmlVersion(String xmlVersion)1122   public void setXmlVersion(String xmlVersion)
1123   {
1124     if (xmlVersion == null)
1125       {
1126         xmlVersion = "1.0";
1127       }
1128     if ("1.0".equals(xmlVersion) ||
1129         "1.1".equals(xmlVersion))
1130       {
1131         version = xmlVersion;
1132       }
1133     else
1134       {
1135         throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
1136       }
1137   }
1138 
getStrictErrorChecking()1139   public boolean getStrictErrorChecking()
1140   {
1141     return checkingCharacters;
1142   }
1143 
setStrictErrorChecking(boolean strictErrorChecking)1144   public void setStrictErrorChecking(boolean strictErrorChecking)
1145   {
1146     checkingCharacters = strictErrorChecking;
1147   }
1148 
lookupPrefix(String namespaceURI)1149   public String lookupPrefix(String namespaceURI)
1150   {
1151     Node root = getDocumentElement();
1152     return (root == null) ? null : root.lookupPrefix(namespaceURI);
1153   }
1154 
isDefaultNamespace(String namespaceURI)1155   public boolean isDefaultNamespace(String namespaceURI)
1156   {
1157     Node root = getDocumentElement();
1158     return (root == null) ? false : root.isDefaultNamespace(namespaceURI);
1159   }
1160 
lookupNamespaceURI(String prefix)1161   public String lookupNamespaceURI(String prefix)
1162   {
1163     Node root = getDocumentElement();
1164     return (root == null) ? null : root.lookupNamespaceURI(prefix);
1165   }
1166 
getBaseURI()1167   public String getBaseURI()
1168   {
1169     return getDocumentURI();
1170     /*
1171     Node root = getDocumentElement();
1172     if (root != null)
1173       {
1174         NamedNodeMap attrs = root.getAttributes();
1175         Node xmlBase = attrs.getNamedItemNS(XMLConstants.XML_NS_URI, "base");
1176         if (xmlBase != null)
1177           {
1178             return xmlBase.getNodeValue();
1179           }
1180       }
1181     return systemId;
1182     */
1183   }
1184 
getDocumentURI()1185   public String getDocumentURI()
1186   {
1187     return systemId;
1188   }
1189 
setDocumentURI(String documentURI)1190   public void setDocumentURI(String documentURI)
1191   {
1192     systemId = documentURI;
1193   }
1194 
adoptNode(Node source)1195   public Node adoptNode(Node source)
1196   {
1197     int sourceNodeType = source.getNodeType();
1198     switch (sourceNodeType)
1199       {
1200       case DOCUMENT_NODE:
1201       case DOCUMENT_TYPE_NODE:
1202         throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR);
1203       case ENTITY_NODE:
1204       case NOTATION_NODE:
1205         throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR);
1206       }
1207     if (source instanceof DomNode)
1208       {
1209         // GNU native
1210         DomNode src = (DomNode) source;
1211         DomNode dst = src;
1212         if (dst.parent != null)
1213           {
1214             dst = (DomNode) dst.cloneNode(true);
1215           }
1216         dst.setOwner(this);
1217         src.notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, src, dst);
1218         return dst;
1219       }
1220     else
1221       {
1222         // Some other implementation
1223         Node dst = null;
1224         switch (sourceNodeType)
1225           {
1226           case Node.ATTRIBUTE_NODE:
1227               {
1228                 Attr src = (Attr) source;
1229                 String nodeName = src.getNodeName();
1230                 String localName = src.getLocalName();
1231                 String namespaceUri = src.getNamespaceURI();
1232                 dst = (localName == null) ?
1233                   createAttribute(nodeName) :
1234                   createAttributeNS(namespaceUri, nodeName);
1235                 adoptChildren(src, dst);
1236                 break;
1237               }
1238           case Node.CDATA_SECTION_NODE:
1239               {
1240                 CDATASection src = (CDATASection) source;
1241                 dst = createCDATASection(src.getData());
1242                 break;
1243               }
1244           case Node.COMMENT_NODE:
1245               {
1246                 Comment src = (Comment) source;
1247                 dst = createComment(src.getData());
1248                 break;
1249               }
1250           case Node.DOCUMENT_FRAGMENT_NODE:
1251               {
1252                 DocumentFragment src = (DocumentFragment) source;
1253                 dst = createDocumentFragment();
1254                 adoptChildren(src, dst);
1255                 break;
1256               }
1257           case Node.ELEMENT_NODE:
1258               {
1259                 Element src = (Element) source;
1260                 String nodeName = src.getNodeName();
1261                 String localName = src.getLocalName();
1262                 String namespaceUri = src.getNamespaceURI();
1263                 dst = (localName == null) ?
1264                   createElement(nodeName) :
1265                   createElementNS(namespaceUri, nodeName);
1266                 adoptAttributes(src, dst);
1267                 adoptChildren(src, dst);
1268                 break;
1269               }
1270           case Node.ENTITY_REFERENCE_NODE:
1271               {
1272                 EntityReference src = (EntityReference) source;
1273                 dst = createEntityReference(src.getNodeName());
1274                 adoptChildren(src, dst);
1275                 break;
1276               }
1277           case Node.PROCESSING_INSTRUCTION_NODE:
1278               {
1279                 ProcessingInstruction src = (ProcessingInstruction) source;
1280                 dst = createProcessingInstruction(src.getTarget(),
1281                                                   src.getData());
1282                 break;
1283               }
1284           case Node.TEXT_NODE:
1285               {
1286                 Text src = (Text) source;
1287                 dst = createTextNode(src.getData());
1288                 break;
1289               }
1290           }
1291         return dst;
1292       }
1293   }
1294 
adoptChildren(Node src, Node dst)1295   void adoptChildren(Node src, Node dst)
1296   {
1297     Node node = src.getFirstChild();
1298     while (node != null)
1299       {
1300         Node next = node.getNextSibling();
1301         dst.appendChild(adoptNode(node));
1302         node = next;
1303       }
1304   }
1305 
adoptAttributes(Node src, Node dst)1306   void adoptAttributes(Node src, Node dst)
1307   {
1308     NamedNodeMap srcAttrs = src.getAttributes();
1309     NamedNodeMap dstAttrs = dst.getAttributes();
1310     int len = srcAttrs.getLength();
1311     for (int i = 0; i < len; i++)
1312       {
1313         Node node = srcAttrs.item(i);
1314         String localName = node.getLocalName();
1315         if (localName == null)
1316           {
1317             dstAttrs.setNamedItem(adoptNode(node));
1318           }
1319         else
1320           {
1321             dstAttrs.setNamedItemNS(adoptNode(node));
1322           }
1323       }
1324   }
1325 
getDomConfig()1326   public DOMConfiguration getDomConfig()
1327   {
1328     if (config == null)
1329       {
1330         config = new DomDocumentConfiguration();
1331       }
1332     return config;
1333   }
1334 
isEqualNode(Node arg)1335   public boolean isEqualNode(Node arg)
1336   {
1337     if (!super.isEqualNode(arg))
1338       return false;
1339     Document d = (Document) arg;
1340     String dversion = d.getXmlVersion();
1341     if (dversion == null || !dversion.equals(version))
1342       return false;
1343     boolean dstandalone = d.getXmlStandalone();
1344     if (dstandalone != standalone)
1345       return false;
1346     String dencoding = d.getXmlEncoding();
1347     if (dencoding == null || dencoding.equalsIgnoreCase("UTF-8"))
1348       {
1349         if (encoding != null && !encoding.equalsIgnoreCase("UTF-8"))
1350           return false;
1351       }
1352     else
1353       {
1354         if (!dencoding.equals(encoding))
1355           return false;
1356       }
1357     return true;
1358   }
1359 
normalizeDocument()1360   public void normalizeDocument()
1361   {
1362     boolean save = building;
1363     building = true;
1364     normalizeNode(this);
1365     building = save;
1366   }
1367 
normalizeNode(DomNode node)1368   void normalizeNode(DomNode node)
1369   {
1370     node.normalize();
1371     if (config != null)
1372       {
1373         switch (node.nodeType)
1374           {
1375           case CDATA_SECTION_NODE:
1376             if (!config.cdataSections)
1377               {
1378                 // replace CDATA section with text node
1379                 Text text = createTextNode(node.getNodeValue());
1380                 node.parent.insertBefore(text, node);
1381                 node.parent.removeChild(node);
1382                 // merge adjacent text nodes
1383                 String data = text.getWholeText();
1384                 node = (DomNode) text.replaceWholeText(data);
1385               }
1386             else if (config.splitCdataSections)
1387               {
1388                 String value = node.getNodeValue();
1389                 int i = value.indexOf("]]>");
1390                 while (i != -1)
1391                   {
1392                     Node node2 = createCDATASection(value.substring(0, i));
1393                     node.parent.insertBefore(node2, node);
1394                     value = value.substring(i + 3);
1395                     node.setNodeValue(value);
1396                     i = value.indexOf("]]>");
1397                   }
1398               }
1399             break;
1400           case COMMENT_NODE:
1401             if (!config.comments)
1402               {
1403                 node.parent.removeChild(node);
1404               }
1405             break;
1406           case TEXT_NODE:
1407             if (!config.elementContentWhitespace &&
1408                 ((Text) node).isElementContentWhitespace())
1409               {
1410                 node.parent.removeChild(node);
1411               }
1412             break;
1413           case ENTITY_REFERENCE_NODE:
1414             if (!config.entities)
1415               {
1416                 for (DomNode ctx = node.first; ctx != null; )
1417                   {
1418                     DomNode ctxNext = ctx.next;
1419                     node.parent.insertBefore(ctx, node);
1420                     ctx = ctxNext;
1421                   }
1422                 node.parent.removeChild(node);
1423               }
1424             break;
1425           case ELEMENT_NODE:
1426             if (!config.namespaceDeclarations)
1427               {
1428                 DomNamedNodeMap attrs =
1429                   (DomNamedNodeMap) node.getAttributes();
1430                 boolean aro = attrs.readonly;
1431                 attrs.readonly = false; // Ensure we can delete if necessary
1432                 int len = attrs.getLength();
1433                 for (int i = 0; i < len; i++)
1434                   {
1435                     Node attr = attrs.item(i);
1436                     String namespace = attr.getNamespaceURI();
1437                     if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespace))
1438                       {
1439                         attrs.removeNamedItemNS(namespace,
1440                                                 attr.getLocalName());
1441                         i--;
1442                         len--;
1443                       }
1444                   }
1445                 attrs.readonly = aro;
1446               }
1447             break;
1448           }
1449       }
1450     for (DomNode ctx = node.first; ctx != null; )
1451       {
1452         DomNode ctxNext = ctx.next;
1453         normalizeNode(ctx);
1454         ctx = ctxNext;
1455       }
1456   }
1457 
renameNode(Node n, String namespaceURI, String qualifiedName)1458   public Node renameNode(Node n, String namespaceURI, String qualifiedName)
1459     throws DOMException
1460   {
1461     if (n instanceof DomNsNode)
1462       {
1463         DomNsNode src = (DomNsNode) n;
1464         if (src == null)
1465           {
1466             throw new DomDOMException(DOMException.NOT_FOUND_ERR);
1467           }
1468         if (src.owner != this)
1469           {
1470             throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR,
1471                                       null, src, 0);
1472           }
1473         boolean xml11 = "1.1".equals(version);
1474         checkName(qualifiedName, xml11);
1475         int ci = qualifiedName.indexOf(':');
1476         if ("".equals(namespaceURI))
1477           {
1478             namespaceURI = null;
1479           }
1480         if (namespaceURI != null)
1481           {
1482             checkNCName(qualifiedName, xml11);
1483             String prefix = (ci == -1) ? "" :
1484               qualifiedName.substring(0, ci);
1485             if (XMLConstants.XML_NS_PREFIX.equals(prefix) &&
1486                 !XMLConstants.XML_NS_URI.equals(namespaceURI))
1487               {
1488                 throw new DomDOMException(DOMException.NAMESPACE_ERR,
1489                                 "xml namespace must be " +
1490                                 XMLConstants.XML_NS_URI, src, 0);
1491               }
1492             else if (src.nodeType == ATTRIBUTE_NODE &&
1493                      (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) ||
1494                       XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName)) &&
1495                      !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI))
1496               {
1497                 throw new DomDOMException(DOMException.NAMESPACE_ERR,
1498                                 "xmlns namespace must be " +
1499                                 XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0);
1500               }
1501             if (XMLConstants.XML_NS_URI.equals(namespaceURI) &&
1502                 !XMLConstants.XML_NS_PREFIX.equals(prefix))
1503               {
1504                 throw new DomDOMException(DOMException.NAMESPACE_ERR,
1505                                 "xml namespace must be " +
1506                                 XMLConstants.XML_NS_URI, src, 0);
1507               }
1508             else if (src.nodeType == ATTRIBUTE_NODE &&
1509                      XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI) &&
1510                      !(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) ||
1511                        XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName)))
1512               {
1513                 throw new DomDOMException(DOMException.NAMESPACE_ERR,
1514                                 "xmlns namespace must be " +
1515                                 XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0);
1516               }
1517 
1518           }
1519         src.setNodeName(qualifiedName);
1520         src.setNamespaceURI(namespaceURI);
1521         src.notifyUserDataHandlers(UserDataHandler.NODE_RENAMED, src, src);
1522         // TODO MutationNameEvents
1523         // DOMElementNameChanged or DOMAttributeNameChanged
1524         return src;
1525       }
1526     throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, n, 0);
1527   }
1528 
1529   // -- XPathEvaluator --
1530 
createExpression(String expression, XPathNSResolver resolver)1531   public XPathExpression createExpression(String expression,
1532                                           XPathNSResolver resolver)
1533     throws XPathException, DOMException
1534   {
1535     return new DomXPathExpression(this, expression, resolver);
1536   }
1537 
createNSResolver(Node nodeResolver)1538   public XPathNSResolver createNSResolver(Node nodeResolver)
1539   {
1540     return new DomXPathNSResolver(nodeResolver);
1541   }
1542 
evaluate(String expression, Node contextNode, XPathNSResolver resolver, short type, Object result)1543   public Object evaluate(String expression,
1544                          Node contextNode,
1545                          XPathNSResolver resolver,
1546                          short type,
1547                          Object result)
1548     throws XPathException, DOMException
1549   {
1550     XPathExpression xpe =
1551       new DomXPathExpression(this, expression, resolver);
1552     return xpe.evaluate(contextNode, type, result);
1553   }
1554 
1555 }
1556