KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nu > xom > Element


1 /* Copyright 2002-2005 Elliotte Rusty Harold
2    
3    This library is free software; you can redistribute it and/or modify
4    it under the terms of version 2.1 of the GNU Lesser General Public
5    License as published by the Free Software Foundation.
6    
7    This library is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10    GNU Lesser General Public License for more details.
11    
12    You should have received a copy of the GNU Lesser General Public
13    License along with this library; if not, write to the
14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
15    Boston, MA 02111-1307 USA
16    
17    You can contact Elliotte Rusty Harold by sending e-mail to
18    elharo@metalab.unc.edu. Please include the word "XOM" in the
19    subject line. The XOM home page is located at http://www.xom.nu/
20 */

21
22 package nu.xom;
23
24 import java.util.ArrayList JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.NoSuchElementException JavaDoc;
28 import java.util.Set JavaDoc;
29 import java.util.SortedSet JavaDoc;
30 import java.util.TreeSet JavaDoc;
31
32 /**
33  * <p>
34  * This class represents an XML element. Each
35  * element has the following properties:
36  * </p>
37  *
38  * <ul>
39  * <li>Local name</li>
40  * <li>Prefix (which may be null or the empty string) </li>
41  * <li>Namespace URI (which may be null or the empty string) </li>
42  * <li>A list of attributes</li>
43  * <li>A list of namespace declarations for this element
44  * (not including those inherited from its parent)</li>
45  * <li>A list of child nodes</li>
46  * </ul>
47  *
48  * @author Elliotte Rusty Harold
49  * @version 1.0
50  *
51  */

52 public class Element extends ParentNode {
53
54     private String JavaDoc localName;
55     private String JavaDoc prefix;
56     private String JavaDoc URI;
57
58     private ArrayList JavaDoc attributes = null;
59     private Namespaces namespaces = null;
60
61     /**
62      * <p>
63      * Creates a new element in no namespace.
64      * </p>
65      *
66      * @param name the name of the element
67      *
68      * @throws IllegalNameException if <code>name</code>
69      * is not a legal XML 1.0 non-colonized name
70      */

71     public Element(String JavaDoc name) {
72         this(name, "");
73     }
74
75     
76     /**
77      * <p>
78      * Creates a new element in a namespace.
79      * </p>
80      *
81      * @param name the qualified name of the element
82      * @param uri the namespace URI of the element
83      *
84      * @throws IllegalNameException if <code>name</code>
85      * is not a legal XML 1.0 non-colonized name
86      * @throws NamespaceConflictException if <code>name</code>'s prefix
87      * cannot be used with <code>uri</code>
88      * @throws MalformedURIException if <code>uri</code>
89      * is not an RFC 2396 absolute URI reference
90      */

91     public Element(String JavaDoc name, String JavaDoc uri) {
92         
93         // The shadowing is important here.
94
// I don't want to set the prefix field just yet.
95
String JavaDoc prefix = "";
96         String JavaDoc localName = name;
97         int colon = name.indexOf(':');
98         if (colon > 0) {
99             prefix = name.substring(0, colon);
100             localName = name.substring(colon + 1);
101         }
102         
103         // The order of these next two calls
104
// matters a great deal.
105
_setNamespacePrefix(prefix);
106         _setNamespaceURI(uri);
107         try {
108             _setLocalName(localName);
109         }
110         catch (IllegalNameException ex) {
111             ex.setData(name);
112             throw ex;
113         }
114         
115     }
116
117     
118     private Element() {}
119
120     
121     static Element build(String JavaDoc name, String JavaDoc uri) {
122         
123         Element result = new Element();
124         String JavaDoc prefix = "";
125         String JavaDoc localName = name;
126         int colon = name.indexOf(':');
127         if (colon >= 0) {
128             prefix = name.substring(0, colon);
129             localName = name.substring(colon + 1);
130         }
131         result.prefix = prefix;
132         result.localName = localName;
133         // We do need to verify the URI here because parsers are
134
// allowing relative URIs which XOM forbids, for reasons
135
// of canonical XML if nothing else. But we only have to verify
136
// that it's an absolute base URI. I don't have to verify
137
// no conflicts.
138
if (! "".equals(uri)) Verifier.checkAbsoluteURIReference(uri);
139         result.URI = uri;
140         return result;
141         
142     }
143
144
145     /**
146      * <p>
147      * Creates a deep copy of an element.
148      * The copy is disconnected from the tree, and does not
149      * have a parent.
150      * </p>
151      *
152      * @param element the element to copy
153      *
154      */

155     public Element(Element element) {
156         
157         this.prefix = element.prefix;
158         this.localName = element.localName;
159         this.URI = element.URI;
160         
161         // Attach additional namespaces
162
if (element.namespaces != null) {
163             this.namespaces = element.namespaces.copy();
164         }
165         
166         // Attach clones of attributes
167
if (element.attributes != null) {
168             this.attributes = element.copyAttributes();
169         }
170         
171         this.actualBaseURI = element.findActualBaseURI();
172         
173         copyChildren(element, this);
174         
175     }
176     
177
178     private ArrayList JavaDoc copyAttributes() {
179
180         int size = attributes.size();
181         ArrayList JavaDoc copy = new ArrayList JavaDoc(size);
182         for (int i = 0; i < size; i++) {
183             copy.add(((Attribute) attributes.get(i)).copy());
184         }
185         return copy;
186         
187     }
188     
189     
190     private static Element copyTag(final Element source) {
191         
192         Element result = source.shallowCopy();
193         
194         // Attach additional namespaces
195
if (source.namespaces != null) {
196             result.namespaces = source.namespaces.copy();
197         }
198         
199         // Attach clones of attributes
200
if (source.attributes != null) {
201             result.attributes = source.copyAttributes();
202         }
203         
204         result.actualBaseURI = source.findActualBaseURI();
205         
206         return result;
207         
208     }
209
210
211     private static void copyChildren(final Element sourceElement,
212       Element resultElement) {
213         
214         if (sourceElement.getChildCount() == 0) return;
215         ParentNode resultParent = resultElement;
216         Node sourceCurrent = sourceElement;
217         int index = 0;
218         int[] indexes = new int[10];
219         int top = 0;
220         indexes[0] = 0;
221         
222         // true if processing the element for the 2nd time;
223
// i.e. the element's end-tag
224
boolean endTag = false;
225         
226         while (true) {
227             if (!endTag && sourceCurrent.getChildCount() > 0) {
228                sourceCurrent = sourceCurrent.getChild(0);
229                index = 0;
230                top++;
231                indexes = grow(indexes, top);
232                indexes[top] = 0;
233             }
234             else {
235                 endTag = false;
236                 ParentNode sourceParent = sourceCurrent.getParent();
237                 if (sourceParent.getChildCount() - 1 == index) {
238                     sourceCurrent = sourceParent;
239                     top--;
240                     if (sourceCurrent == sourceElement) break;
241                     // switch parent up
242
resultParent = (Element) resultParent.getParent();
243                     index = indexes[top];
244                     endTag = true;
245                     continue;
246                 }
247                 else {
248                     index++;
249                     indexes[top] = index;
250                     sourceCurrent = sourceParent.getChild(index);
251                 }
252             }
253             
254             if (sourceCurrent.isElement()) {
255                 Element child = copyTag((Element) sourceCurrent);
256                 resultParent.appendChild(child);
257                 if (sourceCurrent.getChildCount() > 0) {
258                     resultParent = child;
259                 }
260             }
261             else {
262                 Node child = sourceCurrent.copy();
263                 resultParent.appendChild(child);
264             }
265             
266         }
267         
268     }
269
270
271     private static int[] grow(int[] indexes, int top) {
272         
273         if (top < indexes.length) return indexes;
274         int[] result = new int[indexes.length*2];
275         System.arraycopy(indexes, 0, result, 0, indexes.length);
276         return result;
277         
278     }
279
280
281     /**
282      * <p>
283      * Returns a list of the child elements of
284      * this element with the specified name in no namespace.
285      * The elements returned are in document order.
286      * </p>
287      *
288      * @param name the name of the elements included in the list
289      *
290      * @return a comatose list containing the child elements of this
291      * element with the specified name
292      */

293     public final Elements getChildElements(String JavaDoc name) {
294         return getChildElements(name, "");
295     }
296
297     
298     /**
299      * <p>
300      * Returns a list of the immediate child elements of this
301      * element with the specified local name and namespace URI.
302      * Passing the empty string or null as the local name
303      * returns all elements in the specified namespace.
304      * Passing null or the empty string as the namespace URI
305      * returns elements with the specified name in no namespace.
306      * The elements returned are in document order.
307      * </p>
308      *
309      * @param localName the name of the elements included in the list
310      * @param namespaceURI the namespace URI of the elements included
311      * in the list
312      *
313      * @return a comatose list containing the child
314      * elements of this element with the specified
315      * name in the specified namespace
316      */

317     public final Elements getChildElements(String JavaDoc localName,
318      String JavaDoc namespaceURI) {
319         
320         if (namespaceURI == null) namespaceURI = "";
321         if (localName == null) localName = "";
322         
323         Elements elements = new Elements();
324         for (int i = 0; i < getChildCount(); i++) {
325             Node child = getChild(i);
326             if (child.isElement()) {
327                 Element element = (Element) child;
328                 if ((localName.equals(element.getLocalName())
329                   || localName.length() == 0)
330                   && namespaceURI.equals(element.getNamespaceURI())) {
331                     elements.add(element);
332                 }
333             }
334         }
335         return elements;
336         
337     }
338
339     
340     /**
341      * <p>
342      * Returns a list of all the child elements
343      * of this element in document order.
344      * </p>
345      *
346      * @return a comatose list containing all
347      * child elements of this element
348      */

349     public final Elements getChildElements() {
350         
351         Elements elements = new Elements();
352         for (int i = 0; i < getChildCount(); i++) {
353             Node child = getChild(i);
354             if (child.isElement()) {
355                 Element element = (Element) child;
356                 elements.add(element);
357             }
358         }
359         return elements;
360         
361     }
362
363     
364     /**
365      * <p>
366      * Returns the first child
367      * element with the specified name in no namespace.
368      * If there is no such element, it returns null.
369      * </p>
370      *
371      * @param name the name of the element to return
372      *
373      * @return the first child element with the specified local name
374      * in no namespace or null if there is no such element
375      */

376     public final Element getFirstChildElement(String JavaDoc name) {
377         return getFirstChildElement(name, "");
378     }
379
380     
381     /**
382      * <p>
383      * Returns the first child
384      * element with the specified local name and namespace URI.
385      * If there is no such element, it returns null.
386      * </p>
387      *
388      * @param localName the local name of the element to return
389      * @param namespaceURI the namespace URI of the element to return
390      *
391      * @return the first child with the specified local name in the
392      * specified namespace, or null if there is no such element
393      */

394     public final Element getFirstChildElement(String JavaDoc localName,
395      String JavaDoc namespaceURI) {
396         
397         for (int i = 0; i < getChildCount(); i++) {
398             Node child = getChild(i);
399             if (child.isElement()) {
400                 Element element = (Element) child;
401                 if (localName.equals(element.getLocalName())
402                   && namespaceURI.equals(element.getNamespaceURI())) {
403                     return element;
404                 }
405             }
406         }
407         return null;
408         
409     }
410
411
412     /**
413      * <p>
414      * Adds an attribute to this element, replacing any existing
415      * attribute with the same local name and namespace URI.
416      * </p>
417      *
418      * @param attribute the attribute to add
419      *
420      * @throws MultipleParentException if the attribute is already
421      * attached to an element
422      * @throws NamespaceConflictException if the attribute's prefix
423      * is mapped to a different namespace URI than the same prefix
424      * is mapped to by this element, another attribute of
425      * this element, or an additional namespace declaration
426      * of this element
427      */

428     public void addAttribute(Attribute attribute) {
429
430         if (attribute.getParent() != null) {
431             throw new MultipleParentException(
432               "Attribute already has a parent");
433         }
434         
435         // check for namespace conflicts
436
String JavaDoc attPrefix = attribute.getNamespacePrefix();
437         if (attPrefix.length() != 0 && !"xml".equals(attPrefix)) {
438             if (prefix.equals(attribute.getNamespacePrefix())
439               && !(getNamespaceURI()
440                .equals(attribute.getNamespaceURI()))) {
441                 throw new NamespaceConflictException("Prefix of "
442                   + attribute.getQualifiedName()
443                   + " conflicts with element prefix " + prefix);
444             }
445             // check for conflicts with additional namespaces
446
if (namespaces != null) {
447                 String JavaDoc existing
448                  = namespaces.getURI(attribute.getNamespacePrefix());
449                 if (existing != null
450                   && !existing.equals(attribute.getNamespaceURI())) {
451                     throw new NamespaceConflictException("Attribute prefix "
452                       + attPrefix
453                       + " conflicts with namespace declaration.");
454                 }
455             }
456             
457         }
458         
459         if (attributes == null) attributes = new ArrayList JavaDoc(1);
460         checkPrefixConflict(attribute);
461         
462         // Is there already an attribute with this local name
463
// and namespace? If so, remove it.
464
Attribute oldAttribute = getAttribute(attribute.getLocalName(),
465           attribute.getNamespaceURI());
466         if (oldAttribute != null) attributes.remove(oldAttribute);
467         
468         attributes.add(attribute);
469         attribute.setParent(this);
470         
471     }
472     
473     
474     void fastAddAttribute(Attribute attribute) {
475         if (attributes == null) attributes = new ArrayList JavaDoc(1);
476         attributes.add(attribute);
477         attribute.setParent(this);
478     }
479
480
481     /**
482      * <p>
483      * Removes an attribute from this element.
484      * </p>
485      *
486      * @param attribute the attribute to remove
487      *
488      * @return the attribute that was removed
489      *
490      * @throws NoSuchAttributeException if this element is not the
491      * parent of attribute
492      *
493      */

494     public Attribute removeAttribute(Attribute attribute) {
495         
496         if (attributes == null) {
497             throw new NoSuchAttributeException(
498               "Tried to remove attribute "
499               + attribute.getQualifiedName()
500               + " from non-parent element");
501         }
502         if (attribute == null) {
503             throw new NullPointerException JavaDoc(
504               "Tried to remove null attribute");
505         }
506         if (attributes.remove(attribute)) {
507             attribute.setParent(null);
508             return attribute;
509         }
510         else {
511             throw new NoSuchAttributeException(
512               "Tried to remove attribute "
513               + attribute.getQualifiedName()
514               + " from non-parent element");
515         }
516         
517     }
518
519
520     /**
521      * <p>
522      * Returns the attribute with the specified name in no namespace,
523      * or null if this element does not have an attribute
524      * with that name in no namespace.
525      * </p>
526      *
527      * @param name the name of the attribute
528      *
529      * @return the attribute of this element with the specified name
530      */

531     public final Attribute getAttribute(String JavaDoc name) {
532         return getAttribute(name, "");
533     }
534
535     
536     /**
537      * <p>
538      * Returns the attribute with the specified name and namespace URI,
539      * or null if this element does not have an attribute
540      * with that name in that namespace.
541      * </p>
542      *
543      * @param localName the local name of the attribute
544      * @param namespaceURI the namespace of the attribute
545      *
546      * @return the attribute of this element
547      * with the specified name and namespace
548      */

549     public final Attribute getAttribute(String JavaDoc localName,
550       String JavaDoc namespaceURI) {
551         
552         if (attributes == null) return null;
553         int size = attributes.size();
554         for (int i = 0; i < size; i++) {
555             Attribute a = (Attribute) attributes.get(i);
556             if (a.getLocalName().equals(localName)
557              && a.getNamespaceURI().equals(namespaceURI)) {
558                 return a;
559             }
560         }
561         
562         return null;
563         
564     }
565
566     
567     /**
568      * <p>
569      * Returns the value of the attribute with the specified
570      * name in no namespace,
571      * or null if this element does not have an attribute
572      * with that name.
573      * </p>
574      *
575      * @param name the name of the attribute
576      *
577      * @return the value of the attribute of this element
578      * with the specified name
579      */

580     public final String JavaDoc getAttributeValue(String JavaDoc name) {
581         return getAttributeValue(name, "");
582     }
583
584     
585     /**
586      *
587      * <p>
588      * Returns the number of attributes of this <code>Element</code>,
589      * not counting namespace declarations.
590      * This is always a non-negative number.
591      * </p>
592      *
593      * @return the number of attributes in the container
594      */

595     public final int getAttributeCount() {
596         if (attributes == null) return 0;
597         return attributes.size();
598     }
599     
600     
601     /**
602      *
603      * <p>
604      * Selects an attribute by index.
605      * The index is purely for convenience and has no particular
606      * meaning. In particular, it is <em>not</em> necessarily the
607      * position of this attribute in the original document from
608      * which this <code>Element</code> object was read.
609      * As with most lists in Java, attributes are numbered
610      * from 0 to one less than the length of the list.
611      * </p>
612      *
613      * <p>
614      * In general, you should not add attributes to or remove
615      * attributes from the list while iterating across it.
616      * Doing so will change the indexes of the other attributes in
617      * the list. it is, however, safe to remove an attribute from
618      * either end of the list (0 or <code>getAttributeCount()-1</code>)
619      * until there are no attributes left.
620      * </p>
621      *
622      * @param index the attribute to return
623      *
624      * @return the index<sup>th</sup> attribute of this element
625      *
626      * @throws IndexOutofBoundsException if the index is negative
627      * or greater than or equal to the number of attributes
628      * of this element
629      *
630      */

631     public final Attribute getAttribute(int index) {
632         
633         if (attributes == null) {
634             throw new IndexOutOfBoundsException JavaDoc(
635               "Element does not have any attributes"
636             );
637         }
638         return (Attribute) attributes.get(index);
639         
640     }
641
642
643     /**
644      * <p>
645      * Returns the value of the attribute with the
646      * specified name and namespace URI,
647      * or null if this element does not have such an attribute.
648      * </p>
649      *
650      * @param localName the name of the attribute
651      * @param namespaceURI the namespace of the attribute
652      *
653      * @return the value of the attribute of this element
654      * with the specified name and namespace
655      */

656     public final String JavaDoc getAttributeValue(String JavaDoc localName,
657                                           String JavaDoc namespaceURI) {
658         
659         Attribute attribute = getAttribute(localName, namespaceURI);
660         if (attribute == null) return null;
661         else return attribute.getValue();
662         
663     }
664     
665     
666     /**
667      * <p>
668      * Returns the local name of this element, not including the
669      * namespace prefix or colon.
670      * </p>
671      *
672      * @return the local name of this element
673      */

674     public final String JavaDoc getLocalName() {
675         return localName;
676     }
677
678     
679     /**
680      * <p>
681      * Returns the complete name of this element, including the
682      * namespace prefix if this element has one.
683      * </p>
684      *
685      * @return the qualified name of this element
686      */

687     public final String JavaDoc getQualifiedName() {
688         if (prefix.length() == 0) return localName;
689         else return prefix + ":" + localName;
690     }
691
692     
693     /**
694      * <p>
695      * Returns the prefix of this element, or the empty string
696      * if this element does not have a prefix.
697      * </p>
698      *
699      * @return the prefix of this element
700      */

701     public final String JavaDoc getNamespacePrefix() {
702         return prefix;
703     }
704
705     
706     /**
707      * <p>
708      * Returns the namespace URI of this element,
709      * or the empty string if this element is not
710      * in a namespace.
711      * </p>
712      *
713      * @return the namespace URI of this element
714      */

715     public final String JavaDoc getNamespaceURI() {
716         return URI;
717     }
718
719     
720     /**
721      * <p>
722      * Returns the namespace URI mapped to the specified
723      * prefix within this element. Returns null if this prefix
724      * is not associated with a URI.
725      * </p>
726      *
727      * @param prefix the namespace prefix whose URI is desired
728      *
729      * @return the namespace URI mapped to <code>prefix</code>
730      */

731     public final String JavaDoc getNamespaceURI(String JavaDoc prefix) {
732         
733         Element current = this;
734         String JavaDoc result = getLocalNamespaceURI(prefix);
735         while (result == null) {
736             ParentNode parent = current.getParent();
737             if (parent == null || parent.isDocument()) break;
738             current = (Element) parent;
739             result = current.getLocalNamespaceURI(prefix);
740         }
741         if (result == null && "".equals(prefix)) result = "";
742         return result;
743
744     }
745
746     
747     String JavaDoc getLocalNamespaceURI(String JavaDoc prefix) {
748         
749         if (prefix.equals(this.prefix)) return this.URI;
750         
751         if ("xml".equals(prefix)) {
752             return "http://www.w3.org/XML/1998/namespace";
753         }
754         // This next line uses the original Namespaces 1.0
755
// specification rules.
756
// Namespaces 1.0 + errata is different
757
if ("xmlns".equals(prefix)) return "";
758         // Look in the additional namespace declarations
759
if (namespaces != null) {
760             String JavaDoc result = namespaces.getURI(prefix);
761             if (result != null) return result;
762         }
763         // Look in the attributes
764
if (prefix.length() != 0 && attributes != null) {
765             for (int i = 0; i < attributes.size(); i++) {
766                 Attribute a = (Attribute) attributes.get(i);
767                 if (a.getNamespacePrefix().equals(prefix)) {
768                     return a.getNamespaceURI();
769                 }
770             }
771         }
772         
773         return null;
774         
775     }
776
777    
778     /**
779      * <p>
780      * Sets the local name of this element.
781      * </p>
782      *
783      * @param localName the new local name
784      *
785      * @throws IllegalNameException if <code>localName</code> is not
786      * a legal, non-colonized name
787      */

788     public void setLocalName(String JavaDoc localName) {
789         _setLocalName(localName);
790     }
791
792
793     private void _setLocalName(String JavaDoc localName) {
794         Verifier.checkNCName(localName);
795         this.localName = localName;
796     }
797
798
799     /**
800      * <p>
801      * Sets the namespace URI of this element.
802      * </p>
803      *
804      * @param uri the new namespace URI
805      *
806      * @throws MalformedURIException if <code>uri</code>
807      * is not an absolute RFC2396 URI reference
808      * @throws NamespaceException if this element has a prefix
809      * and <code>uri</code> is null or the empty string;
810      * or if the element's prefix is shared by an attribute
811      * or additional namespace
812      */

813     public void setNamespaceURI(String JavaDoc uri) {
814         _setNamespaceURI(uri);
815     }
816
817     
818     private void _setNamespaceURI(String JavaDoc uri) {
819         
820         if (uri == null) uri = "";
821         // Next line is needed to avoid unintentional
822
// exceptions below when checking for conflicts
823
if (uri.equals(this.URI)) return;
824         if (uri.length() == 0) { // faster than "".equals(uri)
825
if (prefix.length() != 0) {
826                 throw new NamespaceConflictException(
827                  "Prefixed elements must have namespace URIs."
828                 );
829             }
830         }
831         else Verifier.checkAbsoluteURIReference(uri);
832         // Make sure this doesn't conflict with any local
833
// attribute prefixes or additional namespace declarations
834
// Note that if the prefix equals the prefix, then the
835
// URI must equal the old URI, so the URI can't easily be
836
// changed. (you'd need to detach everything first;
837
// change the URIs, then put it all back together
838
if (namespaces != null) {
839         String JavaDoc result = namespaces.getURI(prefix);
840             if (result != null) {
841                 throw new NamespaceConflictException(
842                   "new URI conflicts with existing prefix"
843                 );
844             }
845         }
846         // Look in the attributes
847
if (uri.length() > 0 && attributes != null) {
848             for (int i = 0; i < attributes.size(); i++) {
849                 Attribute a = (Attribute) attributes.get(i);
850                 String JavaDoc attPrefix = a.getNamespacePrefix();
851                 if (attPrefix.length() == 0) continue;
852                 if (a.getNamespacePrefix().equals(prefix)) {
853                     throw new NamespaceConflictException(
854                       "new element URI " + uri
855                       + " conflicts with attribute "
856                       + a.getQualifiedName()
857                     );
858                 }
859             }
860         }
861
862         if ("http://www.w3.org/XML/1998/namespace".equals(uri)
863           && ! "xml".equals(prefix)) {
864             throw new NamespaceConflictException(
865               "Wrong prefix " + prefix +
866               " for the http://www.w3.org/XML/1998/namespace namespace URI"
867             );
868         }
869         else if ("xml".equals(prefix) &&
870           !"http://www.w3.org/XML/1998/namespace".equals(uri)) {
871             throw new NamespaceConflictException(
872               "Wrong namespace URI " + uri + " for the xml prefix"
873             );
874         }
875         
876         this.URI = uri;
877         
878     }
879
880
881     /**
882      * <p>
883      * Sets the namespace prefix of this element.
884      * You can pass null or the empty string to remove the prefix.
885      * </p>
886      *
887      * @param prefix the new namespace prefix
888      *
889      * @throws IllegalNameException if <code>prefix</code> is
890      * not a legal XML non-colonized name
891      * @throws NamespaceConflictException if <code>prefix</code> is
892      * already in use by an attribute or additional
893      * namespace with a different URI than the element
894      * itself
895      */

896     public void setNamespacePrefix(String JavaDoc prefix) {
897         _setNamespacePrefix(prefix);
898     }
899
900
901     private void _setNamespacePrefix(String JavaDoc prefix) {
902         
903         if (prefix == null) prefix = "";
904         if (prefix.length() != 0) Verifier.checkNCName(prefix);
905
906         // Check how this affects or conflicts with
907
// attribute namespaces and additional
908
// namespace declarations.
909
String JavaDoc uri = getLocalNamespaceURI(prefix);
910         if (uri != null) {
911             if (!uri.equals(this.URI) && !"xml".equals(prefix)) {
912                 throw new NamespaceConflictException(prefix
913                  + " conflicts with existing prefix");
914             }
915         }
916         else if ("".equals(this.URI) && !"".equals(prefix)) {
917             throw new NamespaceConflictException(
918               "Cannot assign prefix to element in no namespace");
919         }
920
921         this.prefix = prefix;
922         
923     }
924
925
926     /**
927      * <p>
928      * Inserts a child node at the specified position.
929      * Inserting at position 0 makes the child the first child
930      * of this node. Inserting at the position
931      * <code>getChildCount()</code>
932      * makes the child the last child of the node.
933      * </p>
934      *
935      * <p>
936      * All the other methods that add a node to the tree,
937      * invoke this method ultimately.
938      * </p>
939      *
940      * @param position where to insert the child
941      * @param child the node to insert
942      *
943      * @throws IllegalAddException if <code>child</code>
944      * is a <code>Document</code>
945      * @throws MultipleParentException if <code>child</code>
946      * already has a parent
947      * @throws NullPointerException if <code>child</code> is null
948      * @throws IndexOutOfBoundsException if the position is negative
949      * or greater than the number of children of this element.
950      */

951     void insertionAllowed(Node child, int position) {
952         
953         if (child == null) {
954             throw new NullPointerException JavaDoc(
955              "Tried to insert a null child in the tree");
956         }
957         else if (child.getParent() != null) {
958             throw new MultipleParentException(child.toString()
959               + " child already has a parent.");
960         }
961         else if (child.isElement()) {
962             checkCycle(child, this);
963             return;
964         }
965         else if (child.isText()
966           || child.isProcessingInstruction()
967           || child.isComment()) {
968             return;
969         }
970         else {
971             throw new IllegalAddException("Cannot add a "
972              + child.getClass().getName() + " to an Element.");
973         }
974
975     }
976     
977     
978     private static void checkCycle(Node child, ParentNode parent) {
979         
980         if (child == parent) {
981             throw new CycleException("Cannot add a node to itself");
982         }
983         if (child.getChildCount() == 0) return;
984         while ((parent = parent.getParent()) != null) {
985             if (parent == child) {
986                 throw new CycleException(
987                   "Cannot add an ancestor as a child");
988             }
989         }
990         return;
991         
992     }
993
994     
995     /**
996      * <p>
997      * Converts a string to a text node and inserts that
998      * node at the specified position.
999      * </p>
1000     *
1001     * @param position where to insert the child
1002     * @param text the string to convert to a text node and insert
1003     *
1004     * @throws NullPointerException if text is null
1005     * @throws IndexOutOfBoundsException if the position is negative
1006     * or greater than the number of children of the node
1007     */

1008    public void insertChild(String JavaDoc text, int position) {
1009        
1010       if (text == null) {
1011           throw new NullPointerException JavaDoc("Inserted null string");
1012       }
1013       super.fastInsertChild(new Text(text), position);
1014       
1015    }
1016
1017
1018    /**
1019     * <p>
1020     * Converts a string to a text node
1021     * and appends that node to the children of this node.
1022     * </p>
1023     *
1024     * @param text String to add to this node
1025     *
1026     * @throws IllegalAddException if this node cannot
1027     * have children of this type
1028     * @throws NullPointerException if <code>text</code> is null
1029     */

1030    public void appendChild(String JavaDoc text) {
1031        insertChild(new Text(text), getChildCount());
1032    }
1033
1034
1035    /**
1036     * <p>
1037     * Detaches all children from this node.
1038     * </p>
1039     *
1040     * <p>
1041     * Subclassers should note that the default implementation of this
1042     * method does <strong>not</strong> call <code>removeChild</code>
1043     * or <code>detach</code>. If you override
1044     * <code>removeChild</code>, you'll probably need to override this
1045     * method as well.
1046     * </p>
1047     *
1048     * @return a list of all the children removed in the order they
1049     * appeared in the element
1050     */

1051    public Nodes removeChildren() {
1052        
1053        int length = this.getChildCount();
1054        Nodes result = new Nodes();
1055        for (int i = 0; i < length; i++) {
1056            Node child = getChild(i);
1057            if (child.isElement()) fillInBaseURI((Element) child);
1058            child.setParent(null);
1059            result.append(child);
1060        }
1061        this.children = null;
1062        
1063        return result;
1064        
1065    }
1066
1067    
1068    /**
1069     * <p>
1070     * Declares a namespace prefix. This is only necessary when
1071     * prefixes are used in element content and attribute values,
1072     * as in XSLT and the W3C XML Schema Language. Do not use
1073     * this method to declare prefixes for element and attribute
1074     * names.
1075     * </p>
1076     *
1077     * <p>
1078     * If you do redeclare a prefix that is already used
1079     * by an element or attribute name, the additional
1080     * namespace is added if and only if the URI is the same.
1081     * Conflicting namespace declarations will throw an exception.
1082     * </p>
1083     *
1084     * @param prefix the prefix to declare
1085     * @param uri the absolute URI reference to map the prefix to
1086     *
1087     * @throws MalformedURIException if <code>URI</code>
1088     * is not an RFC2396 URI reference
1089     * @throws IllegalNameException if <code>prefix</code> is not
1090     * a legal XML non-colonized name
1091     * @throws NamespaceConflictException if the mapping conflicts
1092     * with an existing element, attribute,
1093     * or additional namespace declaration
1094     */

1095    public void addNamespaceDeclaration(String JavaDoc prefix, String JavaDoc uri) {
1096
1097        if (prefix == null) prefix = "";
1098        if (uri == null) uri = "";
1099        
1100        // check to see if this is the xmlns or xml prefix
1101
if (prefix.equals("xmlns")) {
1102            if (uri.equals("")) {
1103                // This is done automatically
1104
return;
1105            }
1106            throw new NamespaceConflictException(
1107             "The xmlns prefix cannot bound to any URI");
1108        }
1109        else if (prefix.equals("xml")) {
1110            if (uri.equals("http://www.w3.org/XML/1998/namespace")) {
1111                // This is done automatically
1112
return;
1113            }
1114            throw new NamespaceConflictException(
1115              "Wrong namespace URI for xml prefix: " + uri);
1116        }
1117        else if (uri.equals("http://www.w3.org/XML/1998/namespace")) {
1118            throw new NamespaceConflictException(
1119               "Wrong prefix for http://www.w3.org/XML/1998/namespace namespace: "
1120               + prefix);
1121        }
1122        
1123        if (prefix.length() != 0) {
1124            Verifier.checkNCName(prefix);
1125            Verifier.checkAbsoluteURIReference(uri);
1126        }
1127        else if (uri.length() != 0) {
1128            // Make sure we're not trying to undeclare
1129
// the default namespace; this is legal.
1130
Verifier.checkAbsoluteURIReference(uri);
1131        }
1132        
1133        String JavaDoc currentBinding = getLocalNamespaceURI(prefix);
1134        if (currentBinding != null && !currentBinding.equals(uri)) {
1135            throw new NamespaceConflictException(
1136              "Additional namespace " + uri
1137              + " conflicts with existing namespace binding."
1138            );
1139        }
1140        
1141        if (namespaces == null) namespaces = new Namespaces();
1142        namespaces.put(prefix, uri);
1143        
1144    }
1145
1146    
1147    /**
1148     * <p>
1149     * Removes the mapping of the specified prefix. This method only
1150     * removes additional namespaces added with
1151     * <code>addNamespaceDeclaration</code>.
1152     * It has no effect on namespaces of elements and attributes.
1153     * If the prefix is not used on this element, this method
1154     * does nothing.
1155     * </p>
1156     *
1157     * @param prefix the prefix whose declaration should be removed
1158     */

1159    public void removeNamespaceDeclaration(String JavaDoc prefix) {
1160
1161        if (namespaces != null) {
1162            namespaces.remove(prefix);
1163        }
1164        
1165    }
1166
1167    
1168    /**
1169     * <p>
1170     * Returns the number of namespace declarations on this
1171     * element. This counts the namespace of the element
1172     * itself (which may be the empty string), the namespace
1173     * of each attribute, and each namespace added
1174     * by <code>addNamespaceDeclaration</code>.
1175     * However, prefixes used multiple times are only counted
1176     * once; and the <code>xml</code> prefix used for
1177     * <code>xml:base</code>, <code>xml:lang</code>, and
1178     * <code>xml:space</code> is not counted even if one of these
1179     * attributes is present on the element.
1180     * </p>
1181     *
1182     * <p>
1183     * The return value is almost always positive. It can be zero
1184     * if and only if the element itself has the prefix
1185     * <code>xml</code>; e.g. <code>&lt;xml:space /></code>.
1186     * This is not endorsed by the XML specification. The prefix
1187     * <code>xml</code> is reserved for use by the W3C, which has only
1188     * used it for attributes to date. You really shouldn't do this.
1189     * Nonetheless, this is not malformed so XOM allows it.
1190     * </p>
1191     *
1192     * @return the number of namespaces declared by this element
1193     */

1194    public final int getNamespaceDeclarationCount() {
1195        
1196        // This seems to be a hot spot for DOM conversion.
1197
// I'm trying to avoid the overhead of creating and adding
1198
// to a HasSet for the simplest case of an element, none
1199
// of whose attributes are in namespaces, and which has no
1200
// additional namespace declarations. In this case, the
1201
// namespace count is exactly one, which is here indicated
1202
// by a null prefix set.
1203
Set JavaDoc allPrefixes = null;
1204        if (namespaces != null) {
1205            allPrefixes = new HashSet JavaDoc(namespaces.getPrefixes());
1206            allPrefixes.add(prefix);
1207        }
1208        if ("xml".equals(prefix)) allPrefixes = new HashSet JavaDoc();
1209        // add attribute prefixes
1210
int count = getAttributeCount();
1211        for (int i = 0; i < count; i++) {
1212            Attribute att = getAttribute(i);
1213            String JavaDoc attPrefix = att.getNamespacePrefix();
1214            if (attPrefix.length() != 0 && !"xml".equals(attPrefix)) {
1215                if (allPrefixes == null) {
1216                    allPrefixes = new HashSet JavaDoc();
1217                    allPrefixes.add(prefix);
1218                }
1219                allPrefixes.add(attPrefix);
1220            }
1221        }
1222        
1223        if (allPrefixes == null) return 1;
1224        return allPrefixes.size();
1225        
1226    }
1227
1228    
1229    /**
1230     * <p>
1231     * Returns the index<sup>th</sup> namespace prefix declared on
1232     * this element. The index is purely for convenience, and has no
1233     * meaning in itself. This includes the namespaces of the element
1234     * name and of all attributes' names (except for those with the
1235     * prefix <code>xml</code> such as <code>xml:space</code>) as well
1236     * as additional declarations made for attribute values and element
1237     * content. However, prefixes used multiple times (e.g. on several
1238     * attribute values) are only reported once. The default
1239     * namespace is reported with an empty string prefix if present.
1240     * Like most lists in Java, the first prefix is at index 0.
1241     * </p>
1242     *
1243     * <p>
1244     * If the namespaces on the element change for any reason
1245     * (adding or removing an attribute in a namespace, adding
1246     * or removing a namespace declaration, changing the prefix
1247     * of an element, etc.) then then this method may skip or
1248     * repeat prefixes. Don't change the prefixes of an element
1249     * while iterating across them.
1250     * </p>
1251     *
1252     * @param index the prefix to return
1253     *
1254     * @return the prefix
1255     *
1256     * @throws IndexOutOfBoundsException if <code>index</code> is
1257     * negative or greater than or equal to the number of
1258     * namespaces declared by this element.
1259     *
1260     */

1261    public final String JavaDoc getNamespacePrefix(int index) {
1262        
1263        SortedSet JavaDoc allPrefixes;
1264        if (namespaces != null) {
1265            allPrefixes = new TreeSet JavaDoc(namespaces.getPrefixes());
1266        }
1267        else allPrefixes = new TreeSet JavaDoc();
1268        
1269        if (!("xml".equals(prefix))) allPrefixes.add(prefix);
1270        
1271        // add attribute prefixes
1272
for (int i = 0; i < getAttributeCount(); i++) {
1273            Attribute att = getAttribute(i);
1274            String JavaDoc attPrefix = att.getNamespacePrefix();
1275            if (attPrefix.length() != 0 && !("xml".equals(attPrefix))) {
1276                allPrefixes.add(attPrefix);
1277            }
1278        }
1279        
1280        Iterator JavaDoc iterator = allPrefixes.iterator();
1281        try {
1282            for (int i = 0; i < index; i++) {
1283                iterator.next();
1284            }
1285            return (String JavaDoc) iterator.next();
1286        }
1287        catch (NoSuchElementException JavaDoc ex) {
1288            throw new IndexOutOfBoundsException JavaDoc(
1289              "No " + index + "th namespace");
1290        }
1291        
1292    }
1293
1294    
1295    /**
1296     *
1297     * <p>
1298     * Sets the URI from which this element was loaded,
1299     * and against which relative URLs in this element will be
1300     * resolved, unless an <code>xml:base</code> attribute overrides
1301     * this. Setting the base URI to null or the empty string removes
1302     * any existing base URI.
1303     * </p>
1304     *
1305     * @param URI the new base URI for this element
1306     *
1307     * @throws MalformedURIException if <code>URI</code> is
1308     * not a legal RFC 2396 absolute URI
1309     */

1310    public void setBaseURI(String JavaDoc URI) {
1311        setActualBaseURI(URI);
1312    }
1313    
1314    
1315    /**
1316     *
1317     * <p>
1318     * Returns the absolute base URI against which relative URIs in
1319     * this element should be resolved. <code>xml:base</code>
1320     * attributes <em>in the same entity</em> take precedence over the
1321     * actual base URI of the document where the element was found
1322     * or which was set by <code>setBaseURI</code>.
1323     * </p>
1324     *
1325     * <p>
1326     * This URI is made absolute before it is returned
1327     * by resolving the information in this element against the
1328     * information in its parent element and document entity.
1329     * However, it is not always possible to fully absolutize the
1330     * URI in all circumstances. In this case, this method returns the
1331     * empty string to indicate the base URI of the current entity.
1332     * </p>
1333     *
1334     * <p>
1335     * If the element's <code>xml:base</code> attribute contains a
1336     * value that is a syntactically illegal URI (e.g. %GF.html"),
1337     * then the base URI is application dependent. XOM's choice is
1338     * to behave as if the element did not have an <code>xml:base</code>
1339     * attribute.
1340     * </p>
1341     *
1342     * @return the base URI of this element
1343     */

1344     public String JavaDoc getBaseURI() {
1345
1346        String JavaDoc baseURI = "";
1347        String JavaDoc sourceEntity = this.getActualBaseURI();
1348        
1349        ParentNode current = this;
1350        
1351        while (true) {
1352            String JavaDoc currentEntity = current.getActualBaseURI();
1353            if (sourceEntity.length() != 0
1354              && ! sourceEntity.equals(currentEntity)) {
1355                baseURI = URIUtil.absolutize(sourceEntity, baseURI);
1356                break;
1357            }
1358            
1359            if (current.isDocument()) {
1360                baseURI = URIUtil.absolutize(currentEntity, baseURI);
1361                break;
1362            }
1363            Attribute baseAttribute = ((Element) current).getAttribute("base",
1364              "http://www.w3.org/XML/1998/namespace");
1365            if (baseAttribute != null) {
1366                String JavaDoc baseIRI = baseAttribute.getValue();
1367                // The base attribute contains an IRI, not a URI.
1368
// Thus the first thing we have to do is escape it
1369
// to convert illegal characters to hexadecimal escapes.
1370
String JavaDoc base = URIUtil.toURI(baseIRI);
1371                if ("".equals(base)) {
1372                    baseURI = getEntityURI();
1373                    break;
1374                }
1375                else if (legalURI(base)) {
1376                    if ("".equals(baseURI)) baseURI = base;
1377                    else if (URIUtil.isOpaque(base)) break;
1378                    else baseURI = URIUtil.absolutize(base, baseURI);
1379                    if (URIUtil.isAbsolute(base)) break;
1380                }
1381            }
1382            current = current.getParent();
1383            if (current == null) {
1384                baseURI = URIUtil.absolutize(currentEntity, baseURI);
1385                break;
1386            }
1387        }
1388        
1389        if (URIUtil.isAbsolute(baseURI)) return baseURI;
1390        return "";
1391            
1392    }
1393    
1394    
1395    private String JavaDoc getEntityURI() {
1396     
1397        ParentNode current = this;
1398        while (current != null) {
1399            if (current.actualBaseURI != null
1400              && current.actualBaseURI.length() != 0) {
1401                return current.actualBaseURI;
1402            }
1403            current = current.getParent();
1404        }
1405        return "";
1406        
1407    }
1408        
1409    
1410    private boolean legalURI(String JavaDoc base) {
1411        
1412        try {
1413            Verifier.checkURIReference(base);
1414            return true;
1415        }
1416        catch (MalformedURIException ex) {
1417            return false;
1418        }
1419        
1420    }
1421
1422
1423    /**
1424     * <p>
1425     * Returns a string containing the XML serialization of this
1426     * element. This includes the element and all its attributes
1427     * and descendants. However, it does not contain namespace
1428     * declarations for namespaces inherited from ancestor elements.
1429     * </p>
1430     *
1431     * @return the XML representation of this element
1432     *
1433     */

1434    public final String JavaDoc toXML() {
1435        
1436        StringBuffer JavaDoc result = new StringBuffer JavaDoc(1024);
1437        Node current = this;
1438        boolean endTag = false;
1439        int index = -1;
1440        int[] indexes = new int[10];
1441        int top = 0;
1442        indexes[0] = -1;
1443        
1444        while (true) {
1445            
1446            if (!endTag && current.getChildCount() > 0) {
1447               writeStartTag((Element) current, result);
1448               current = current.getChild(0);
1449               index = 0;
1450               top++;
1451               indexes = grow(indexes, top);
1452               indexes[top] = 0;
1453            }
1454            else {
1455              if (endTag) {
1456                 writeEndTag((Element) current, result);
1457                 if (current == this) break;
1458              }
1459              else if (current.isElement()) {
1460                 writeStartTag((Element) current, result);
1461                 if (current == this) break;
1462              }
1463              else {
1464                  result.append(current.toXML());
1465              }
1466              endTag = false;
1467              ParentNode parent = current.getParent();
1468              if (parent.getChildCount() - 1 == index) {
1469                current = parent;
1470                top--;
1471                if (current != this) {
1472                    parent = current.getParent();
1473                    index = indexes[top];
1474                }
1475                endTag = true;
1476              }
1477              else {
1478                 index++;
1479                 indexes[top] = index;
1480                 current = parent.getChild(index);
1481              }
1482              
1483            }
1484
1485        }
1486
1487        return result.toString();
1488        
1489    }
1490    
1491    
1492    private static void writeStartTag(Element element, StringBuffer JavaDoc result) {
1493        
1494        result.append("<");
1495        result.append(element.getQualifiedName());
1496
1497        ParentNode parentNode = element.getParent();
1498        for (int i = 0; i < element.getNamespaceDeclarationCount(); i++) {
1499            String JavaDoc additionalPrefix = element.getNamespacePrefix(i);
1500            String JavaDoc uri = element.getNamespaceURI(additionalPrefix);
1501            if (parentNode != null && parentNode.isElement()) {
1502               Element parentElement = (Element) parentNode;
1503               if (uri.equals(
1504                 parentElement.getNamespaceURI(additionalPrefix))) {
1505                   continue;
1506               }
1507            }
1508            else if (uri.length() == 0) {
1509                continue; // no need to say xmlns=""
1510
}
1511            
1512            result.append(" xmlns");
1513            if (additionalPrefix.length() > 0) {
1514                result.append(':');
1515                result.append(additionalPrefix);
1516            }
1517            result.append("=\"");
1518            result.append(uri);
1519            result.append('"');
1520        }
1521        
1522        // attributes
1523
if (element.attributes != null) {
1524            for (int i = 0; i < element.attributes.size(); i++) {
1525                Attribute attribute = (Attribute) element.attributes.get(i);
1526                result.append(' ');
1527                result.append(attribute.toXML());
1528            }
1529        }
1530
1531        if (element.getChildCount() > 0) {
1532            result.append('>');
1533        }
1534        else {
1535            result.append(" />");
1536        }
1537        
1538    }
1539
1540    
1541    private static void writeEndTag(
1542      Element element, StringBuffer JavaDoc result) {
1543        
1544        result.append("</");
1545        result.append(element.getQualifiedName());
1546        result.append(">");
1547        
1548    }
1549    
1550
1551    /**
1552     * <p>
1553     * Returns the value of the element as defined by XPath 1.0.
1554     * This is the complete PCDATA content of the element, without
1555     * any tags, comments, or processing instructions after all
1556     * entity and character references have been resolved.
1557     * </p>
1558     *
1559     * @return XPath string value of this element
1560     *
1561     */

1562    public final String JavaDoc getValue() {
1563
1564        // non-recursive algorithm avoids stack size limitations
1565
if (this.getChildCount() == 0) return "";
1566        StringBuffer JavaDoc result = new StringBuffer JavaDoc();
1567        Node current = this.getChild(0);
1568        int index = 0;
1569        int[] indexes = new int[10];
1570        int top = 0;
1571        indexes[0] = 0;
1572        
1573        boolean endTag = false;
1574        while (true) {
1575            if (!endTag && current.getChildCount() > 0) {
1576               current = current.getChild(0);
1577               index = 0;
1578               top++;
1579               indexes = grow(indexes, top);
1580               indexes[top] = 0; }
1581            else {
1582                endTag = false;
1583                if (current.isText()) result.append(current.getValue());
1584                ParentNode parent = current.getParent();
1585                if (parent.getChildCount() - 1 == index) {
1586                    current = parent;
1587                    top--;
1588                    if (current == this) break;
1589                    index = indexes[top];
1590                    endTag = true;
1591                }
1592                else {
1593                    index++;
1594                    indexes[top] = index;
1595                    current = parent.getChild(index);
1596                }
1597            }
1598        }
1599        
1600        return result.toString();
1601
1602    }
1603
1604    /**
1605     * <p>
1606     * Creates a deep copy of this element with no parent,
1607     * that can be added to this document or a different one.
1608     * </p>
1609     *
1610     * <p>
1611     * Subclassers should be wary. Implementing this method is trickier
1612     * than it might seem, especially if you wish to avoid potential
1613     * stack overflows in deep documents. In particular, you should not
1614     * rely on the obvious recursive algorithm. Most subclasses should
1615     * override the {@link nu.xom.Element#shallowCopy() shallowCopy}
1616     * method instead.
1617     * </p>
1618     *
1619     * @return a deep copy of this element with no parent
1620     */

1621    public Node copy() {
1622        Element result = copyTag(this);
1623        copyChildren(this, result);
1624        return result;
1625    }
1626    
1627    
1628    /**
1629     * <p>
1630     * Creates a very shallow copy of the element with the same name
1631     * and namespace URI, but no children, attributes, base URI, or
1632     * namespace declaration. This method is invoked as necessary
1633     * by the {@link nu.xom.Element#copy() copy} method
1634     * and the {@link nu.xom.Element#Element(nu.xom.Element)
1635     * copy constructor}.
1636     * </p>
1637     *
1638     * <p>
1639     * Subclasses should override this method so that it
1640     * returns an instance of the subclass so that types
1641     * are preserved when copying. This method should not add any
1642     * attributes, namespace declarations, or children to the
1643     * shallow copy. Any such items will be overwritten.
1644     * </p>
1645     *
1646     * @return an empty element with the same name and
1647     * namespace as this element
1648     */

1649    protected Element shallowCopy() {
1650        return new Element(getQualifiedName(), getNamespaceURI());
1651    }
1652
1653    
1654    /**
1655     * <p>
1656     * Returns a string representation of this element suitable
1657     * for debugging and diagnosis. This is <em>not</em>
1658     * the XML representation of the element.
1659     * </p>
1660     *
1661     * @return a non-XML string representation of this element
1662     */

1663    public final String JavaDoc toString() {
1664        return
1665          "[" + getClass().getName() + ": " + getQualifiedName() + "]";
1666    }
1667
1668    
1669    boolean isElement() {
1670        return true;
1671    }
1672    
1673    
1674    private void checkPrefixConflict(Attribute attribute) {
1675        
1676        String JavaDoc prefix = attribute.getNamespacePrefix();
1677        String JavaDoc namespaceURI = attribute.getNamespaceURI();
1678        
1679        // Look for conflicts
1680
int size = attributes.size();
1681        for (int i = 0; i < size; i++) {
1682            Attribute a = (Attribute) attributes.get(i);
1683            if (a.getNamespacePrefix().equals(prefix)) {
1684              if (a.getNamespaceURI().equals(namespaceURI)) return;
1685              throw new NamespaceConflictException(
1686                "Prefix of " + attribute.getQualifiedName()
1687                + " conflicts with " + a.getQualifiedName());
1688            }
1689        }
1690        
1691    }
1692
1693    
1694}
Popular Tags