1   
2   
3   
4   
5   
6   
7   
8   package org.dom4j.tree;
9   
10  import java.io.IOException;
11  import java.io.StringWriter;
12  import java.io.Writer;
13  import java.util.ArrayList;
14  import java.util.Collections;
15  import java.util.Iterator;
16  import java.util.List;
17  import java.util.Map;
18  
19  import org.dom4j.Attribute;
20  import org.dom4j.CDATA;
21  import org.dom4j.CharacterData;
22  import org.dom4j.Comment;
23  import org.dom4j.Document;
24  import org.dom4j.DocumentFactory;
25  import org.dom4j.Element;
26  import org.dom4j.Entity;
27  import org.dom4j.IllegalAddException;
28  import org.dom4j.Namespace;
29  import org.dom4j.Node;
30  import org.dom4j.ProcessingInstruction;
31  import org.dom4j.QName;
32  import org.dom4j.Text;
33  import org.dom4j.Visitor;
34  import org.dom4j.io.OutputFormat;
35  import org.dom4j.io.XMLWriter;
36  
37  import org.xml.sax.Attributes;
38  
39  /***
40   * <p>
41   * <code>AbstractElement</code> is an abstract base class for tree
42   * implementors to use for implementation inheritence.
43   * </p>
44   * 
45   * @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
46   * @version $Revision: 1.80 $
47   */
48  public abstract class AbstractElement extends AbstractBranch implements
49          org.dom4j.Element {
50      /*** The <code>DocumentFactory</code> instance used by default */
51      private static final DocumentFactory DOCUMENT_FACTORY = DocumentFactory
52              .getInstance();
53  
54      protected static final List EMPTY_LIST = Collections.EMPTY_LIST;
55  
56      protected static final Iterator EMPTY_ITERATOR = EMPTY_LIST.iterator();
57  
58      protected static final boolean VERBOSE_TOSTRING = false;
59  
60      protected static final boolean USE_STRINGVALUE_SEPARATOR = false;
61  
62      public AbstractElement() {
63      }
64  
65      public short getNodeType() {
66          return ELEMENT_NODE;
67      }
68  
69      public boolean isRootElement() {
70          Document document = getDocument();
71  
72          if (document != null) {
73              Element root = document.getRootElement();
74  
75              if (root == this) {
76                  return true;
77              }
78          }
79  
80          return false;
81      }
82  
83      public void setName(String name) {
84          setQName(getDocumentFactory().createQName(name));
85      }
86  
87      public void setNamespace(Namespace namespace) {
88          setQName(getDocumentFactory().createQName(getName(), namespace));
89      }
90  
91      /***
92       * Returns the XPath expression to match this Elements name which is
93       * getQualifiedName() if there is a namespace prefix defined or if no
94       * namespace is present then it is getName() or if a namespace is defined
95       * with no prefix then the expression is [name()='X'] where X = getName().
96       * 
97       * @return DOCUMENT ME!
98       */
99      public String getXPathNameStep() {
100         String uri = getNamespaceURI();
101 
102         if ((uri == null) || (uri.length() == 0)) {
103             return getName();
104         }
105 
106         String prefix = getNamespacePrefix();
107 
108         if ((prefix == null) || (prefix.length() == 0)) {
109             return "*[name()='" + getName() + "']";
110         }
111 
112         return getQualifiedName();
113     }
114 
115     public String getPath(Element context) {
116         if (this == context) {
117             return ".";
118         }
119 
120         Element parent = getParent();
121 
122         if (parent == null) {
123             return "/" + getXPathNameStep();
124         } else if (parent == context) {
125             return getXPathNameStep();
126         }
127 
128         return parent.getPath(context) + "/" + getXPathNameStep();
129     }
130 
131     public String getUniquePath(Element context) {
132         Element parent = getParent();
133 
134         if (parent == null) {
135             return "/" + getXPathNameStep();
136         }
137 
138         StringBuffer buffer = new StringBuffer();
139 
140         if (parent != context) {
141             buffer.append(parent.getUniquePath(context));
142 
143             buffer.append("/");
144         }
145 
146         buffer.append(getXPathNameStep());
147 
148         List mySiblings = parent.elements(getQName());
149 
150         if (mySiblings.size() > 1) {
151             int idx = mySiblings.indexOf(this);
152 
153             if (idx >= 0) {
154                 buffer.append("[");
155 
156                 buffer.append(Integer.toString(++idx));
157 
158                 buffer.append("]");
159             }
160         }
161 
162         return buffer.toString();
163     }
164 
165     public String asXML() {
166         try {
167             StringWriter out = new StringWriter();
168             XMLWriter writer = new XMLWriter(out, new OutputFormat());
169 
170             writer.write(this);
171             writer.flush();
172 
173             return out.toString();
174         } catch (IOException e) {
175             throw new RuntimeException("IOException while generating "
176                     + "textual representation: " + e.getMessage());
177         }
178     }
179 
180     public void write(Writer out) throws IOException {
181         XMLWriter writer = new XMLWriter(out, new OutputFormat());
182         writer.write(this);
183     }
184 
185     /***
186      * <p>
187      * <code>accept</code> method is the <code>Visitor Pattern</code>
188      * method.
189      * </p>
190      * 
191      * @param visitor
192      *            <code>Visitor</code> is the visitor.
193      */
194     public void accept(Visitor visitor) {
195         visitor.visit(this);
196 
197         
198         for (int i = 0, size = attributeCount(); i < size; i++) {
199             Attribute attribute = attribute(i);
200 
201             visitor.visit(attribute);
202         }
203 
204         
205         for (int i = 0, size = nodeCount(); i < size; i++) {
206             Node node = node(i);
207 
208             node.accept(visitor);
209         }
210     }
211 
212     public String toString() {
213         String uri = getNamespaceURI();
214 
215         if ((uri != null) && (uri.length() > 0)) {
216             if (VERBOSE_TOSTRING) {
217                 return super.toString() + " [Element: <" + getQualifiedName()
218                         + " uri: " + uri + " attributes: " + attributeList()
219                         + " content: " + contentList() + " />]";
220             } else {
221                 return super.toString() + " [Element: <" + getQualifiedName()
222                         + " uri: " + uri + " attributes: " + attributeList()
223                         + "/>]";
224             }
225         } else {
226             if (VERBOSE_TOSTRING) {
227                 return super.toString() + " [Element: <" + getQualifiedName()
228                         + " attributes: " + attributeList() + " content: "
229                         + contentList() + " />]";
230             } else {
231                 return super.toString() + " [Element: <" + getQualifiedName()
232                         + " attributes: " + attributeList() + "/>]";
233             }
234         }
235     }
236 
237     
238     
239     public Namespace getNamespace() {
240         return getQName().getNamespace();
241     }
242 
243     public String getName() {
244         return getQName().getName();
245     }
246 
247     public String getNamespacePrefix() {
248         return getQName().getNamespacePrefix();
249     }
250 
251     public String getNamespaceURI() {
252         return getQName().getNamespaceURI();
253     }
254 
255     public String getQualifiedName() {
256         return getQName().getQualifiedName();
257     }
258 
259     public Object getData() {
260         return getText();
261     }
262 
263     public void setData(Object data) {
264         
265     }
266 
267     
268     
269     public Node node(int index) {
270         if (index >= 0) {
271             List list = contentList();
272 
273             if (index >= list.size()) {
274                 return null;
275             }
276 
277             Object node = list.get(index);
278 
279             if (node != null) {
280                 if (node instanceof Node) {
281                     return (Node) node;
282                 } else {
283                     return getDocumentFactory().createText(node.toString());
284                 }
285             }
286         }
287 
288         return null;
289     }
290 
291     public int indexOf(Node node) {
292         return contentList().indexOf(node);
293     }
294 
295     public int nodeCount() {
296         return contentList().size();
297     }
298 
299     public Iterator nodeIterator() {
300         return contentList().iterator();
301     }
302 
303     
304     
305     public Element element(String name) {
306         List list = contentList();
307 
308         int size = list.size();
309 
310         for (int i = 0; i < size; i++) {
311             Object object = list.get(i);
312 
313             if (object instanceof Element) {
314                 Element element = (Element) object;
315 
316                 if (name.equals(element.getName())) {
317                     return element;
318                 }
319             }
320         }
321 
322         return null;
323     }
324 
325     public Element element(QName qName) {
326         List list = contentList();
327 
328         int size = list.size();
329 
330         for (int i = 0; i < size; i++) {
331             Object object = list.get(i);
332 
333             if (object instanceof Element) {
334                 Element element = (Element) object;
335 
336                 if (qName.equals(element.getQName())) {
337                     return element;
338                 }
339             }
340         }
341 
342         return null;
343     }
344 
345     public Element element(String name, Namespace namespace) {
346         return element(getDocumentFactory().createQName(name, namespace));
347     }
348 
349     public List elements() {
350         List list = contentList();
351 
352         BackedList answer = createResultList();
353 
354         int size = list.size();
355 
356         for (int i = 0; i < size; i++) {
357             Object object = list.get(i);
358 
359             if (object instanceof Element) {
360                 answer.addLocal(object);
361             }
362         }
363 
364         return answer;
365     }
366 
367     public List elements(String name) {
368         List list = contentList();
369 
370         BackedList answer = createResultList();
371 
372         int size = list.size();
373 
374         for (int i = 0; i < size; i++) {
375             Object object = list.get(i);
376 
377             if (object instanceof Element) {
378                 Element element = (Element) object;
379 
380                 if (name.equals(element.getName())) {
381                     answer.addLocal(element);
382                 }
383             }
384         }
385 
386         return answer;
387     }
388 
389     public List elements(QName qName) {
390         List list = contentList();
391 
392         BackedList answer = createResultList();
393 
394         int size = list.size();
395 
396         for (int i = 0; i < size; i++) {
397             Object object = list.get(i);
398 
399             if (object instanceof Element) {
400                 Element element = (Element) object;
401 
402                 if (qName.equals(element.getQName())) {
403                     answer.addLocal(element);
404                 }
405             }
406         }
407 
408         return answer;
409     }
410 
411     public List elements(String name, Namespace namespace) {
412         return elements(getDocumentFactory().createQName(name, namespace));
413     }
414 
415     public Iterator elementIterator() {
416         List list = elements();
417 
418         return list.iterator();
419     }
420 
421     public Iterator elementIterator(String name) {
422         List list = elements(name);
423 
424         return list.iterator();
425     }
426 
427     public Iterator elementIterator(QName qName) {
428         List list = elements(qName);
429 
430         return list.iterator();
431     }
432 
433     public Iterator elementIterator(String name, Namespace ns) {
434         return elementIterator(getDocumentFactory().createQName(name, ns));
435     }
436 
437     
438     
439     public List attributes() {
440         return new ContentListFacade(this, attributeList());
441     }
442 
443     public Iterator attributeIterator() {
444         return attributeList().iterator();
445     }
446 
447     public Attribute attribute(int index) {
448         return (Attribute) attributeList().get(index);
449     }
450 
451     public int attributeCount() {
452         return attributeList().size();
453     }
454 
455     public Attribute attribute(String name) {
456         List list = attributeList();
457 
458         int size = list.size();
459 
460         for (int i = 0; i < size; i++) {
461             Attribute attribute = (Attribute) list.get(i);
462 
463             if (name.equals(attribute.getName())) {
464                 return attribute;
465             }
466         }
467 
468         return null;
469     }
470 
471     public Attribute attribute(QName qName) {
472         List list = attributeList();
473 
474         int size = list.size();
475 
476         for (int i = 0; i < size; i++) {
477             Attribute attribute = (Attribute) list.get(i);
478 
479             if (qName.equals(attribute.getQName())) {
480                 return attribute;
481             }
482         }
483 
484         return null;
485     }
486 
487     public Attribute attribute(String name, Namespace namespace) {
488         return attribute(getDocumentFactory().createQName(name, namespace));
489     }
490 
491     /***
492      * This method provides a more optimal way of setting all the attributes on
493      * an Element particularly for use in {@link org.dom4j.io.SAXReader}.
494      * 
495      * @param attributes
496      *            DOCUMENT ME!
497      * @param namespaceStack
498      *            DOCUMENT ME!
499      * @param noNamespaceAttributes
500      *            DOCUMENT ME!
501      */
502     public void setAttributes(Attributes attributes,
503             NamespaceStack namespaceStack, boolean noNamespaceAttributes) {
504         
505         int size = attributes.getLength();
506 
507         if (size > 0) {
508             DocumentFactory factory = getDocumentFactory();
509 
510             if (size == 1) {
511                 
512                 String name = attributes.getQName(0);
513 
514                 if (noNamespaceAttributes || !name.startsWith("xmlns")) {
515                     String attributeURI = attributes.getURI(0);
516 
517                     String attributeLocalName = attributes.getLocalName(0);
518 
519                     String attributeValue = attributes.getValue(0);
520 
521                     QName attributeQName = namespaceStack.getAttributeQName(
522                             attributeURI, attributeLocalName, name);
523 
524                     add(factory.createAttribute(this, attributeQName,
525                             attributeValue));
526                 }
527             } else {
528                 List list = attributeList(size);
529 
530                 list.clear();
531 
532                 for (int i = 0; i < size; i++) {
533                     
534                     
535                     String attributeName = attributes.getQName(i);
536 
537                     if (noNamespaceAttributes
538                             || !attributeName.startsWith("xmlns")) {
539                         String attributeURI = attributes.getURI(i);
540 
541                         String attributeLocalName = attributes.getLocalName(i);
542 
543                         String attributeValue = attributes.getValue(i);
544 
545                         QName attributeQName = namespaceStack
546                                 .getAttributeQName(attributeURI,
547                                         attributeLocalName, attributeName);
548 
549                         Attribute attribute = factory.createAttribute(this,
550                                 attributeQName, attributeValue);
551 
552                         list.add(attribute);
553 
554                         childAdded(attribute);
555                     }
556                 }
557             }
558         }
559     }
560 
561     public String attributeValue(String name) {
562         Attribute attrib = attribute(name);
563 
564         if (attrib == null) {
565             return null;
566         } else {
567             return attrib.getValue();
568         }
569     }
570 
571     public String attributeValue(QName qName) {
572         Attribute attrib = attribute(qName);
573 
574         if (attrib == null) {
575             return null;
576         } else {
577             return attrib.getValue();
578         }
579     }
580 
581     public String attributeValue(String name, String defaultValue) {
582         String answer = attributeValue(name);
583 
584         return (answer != null) ? answer : defaultValue;
585     }
586 
587     public String attributeValue(QName qName, String defaultValue) {
588         String answer = attributeValue(qName);
589 
590         return (answer != null) ? answer : defaultValue;
591     }
592 
593     /***
594      * DOCUMENT ME!
595      * 
596      * @param name
597      *            DOCUMENT ME!
598      * @param value
599      *            DOCUMENT ME!
600      * 
601      * @deprecated As of version 0.5. Please use {@link
602      *             #addAttribute(String,String)} instead. WILL BE REMOVED IN
603      *             dom4j-1.6 !!
604      */
605     public void setAttributeValue(String name, String value) {
606         addAttribute(name, value);
607     }
608 
609     /***
610      * DOCUMENT ME!
611      * 
612      * @param qName
613      *            DOCUMENT ME!
614      * @param value
615      *            DOCUMENT ME!
616      * 
617      * @deprecated As of version 0.5. Please use {@link
618      *             #addAttribute(String,String)} instead. WILL BE REMOVED IN
619      *             dom4j-1.6 !!
620      */
621     public void setAttributeValue(QName qName, String value) {
622         addAttribute(qName, value);
623     }
624 
625     public void add(Attribute attribute) {
626         if (attribute.getParent() != null) {
627             String message = "The Attribute already has an existing parent \""
628                     + attribute.getParent().getQualifiedName() + "\"";
629 
630             throw new IllegalAddException(this, attribute, message);
631         }
632 
633         if (attribute.getValue() == null) {
634             
635             
636             
637             Attribute oldAttribute = attribute(attribute.getQName());
638 
639             if (oldAttribute != null) {
640                 remove(oldAttribute);
641             }
642         } else {
643             attributeList().add(attribute);
644 
645             childAdded(attribute);
646         }
647     }
648 
649     public boolean remove(Attribute attribute) {
650         List list = attributeList();
651 
652         boolean answer = list.remove(attribute);
653 
654         if (answer) {
655             childRemoved(attribute);
656         } else {
657             
658             Attribute copy = attribute(attribute.getQName());
659 
660             if (copy != null) {
661                 list.remove(copy);
662 
663                 answer = true;
664             }
665         }
666 
667         return answer;
668     }
669 
670     
671     
672     public List processingInstructions() {
673         List list = contentList();
674 
675         BackedList answer = createResultList();
676 
677         int size = list.size();
678 
679         for (int i = 0; i < size; i++) {
680             Object object = list.get(i);
681 
682             if (object instanceof ProcessingInstruction) {
683                 answer.addLocal(object);
684             }
685         }
686 
687         return answer;
688     }
689 
690     public List processingInstructions(String target) {
691         List list = contentList();
692 
693         BackedList answer = createResultList();
694 
695         int size = list.size();
696 
697         for (int i = 0; i < size; i++) {
698             Object object = list.get(i);
699 
700             if (object instanceof ProcessingInstruction) {
701                 ProcessingInstruction pi = (ProcessingInstruction) object;
702 
703                 if (target.equals(pi.getName())) {
704                     answer.addLocal(pi);
705                 }
706             }
707         }
708 
709         return answer;
710     }
711 
712     public ProcessingInstruction processingInstruction(String target) {
713         List list = contentList();
714 
715         int size = list.size();
716 
717         for (int i = 0; i < size; i++) {
718             Object object = list.get(i);
719 
720             if (object instanceof ProcessingInstruction) {
721                 ProcessingInstruction pi = (ProcessingInstruction) object;
722 
723                 if (target.equals(pi.getName())) {
724                     return pi;
725                 }
726             }
727         }
728 
729         return null;
730     }
731 
732     public boolean removeProcessingInstruction(String target) {
733         List list = contentList();
734 
735         for (Iterator iter = list.iterator(); iter.hasNext();) {
736             Object object = iter.next();
737 
738             if (object instanceof ProcessingInstruction) {
739                 ProcessingInstruction pi = (ProcessingInstruction) object;
740 
741                 if (target.equals(pi.getName())) {
742                     iter.remove();
743 
744                     return true;
745                 }
746             }
747         }
748 
749         return false;
750     }
751 
752     
753     
754     public Node getXPathResult(int index) {
755         Node answer = node(index);
756 
757         if ((answer != null) && !answer.supportsParent()) {
758             return answer.asXPathResult(this);
759         }
760 
761         return answer;
762     }
763 
764     public Element addAttribute(String name, String value) {
765         
766         Attribute attribute = attribute(name);
767 
768         if (value != null) {
769             if (attribute == null) {
770                 add(getDocumentFactory().createAttribute(this, name, value));
771             } else if (attribute.isReadOnly()) {
772                 remove(attribute);
773 
774                 add(getDocumentFactory().createAttribute(this, name, value));
775             } else {
776                 attribute.setValue(value);
777             }
778         } else if (attribute != null) {
779             remove(attribute);
780         }
781 
782         return this;
783     }
784 
785     public Element addAttribute(QName qName, String value) {
786         
787         Attribute attribute = attribute(qName);
788 
789         if (value != null) {
790             if (attribute == null) {
791                 add(getDocumentFactory().createAttribute(this, qName, value));
792             } else if (attribute.isReadOnly()) {
793                 remove(attribute);
794 
795                 add(getDocumentFactory().createAttribute(this, qName, value));
796             } else {
797                 attribute.setValue(value);
798             }
799         } else if (attribute != null) {
800             remove(attribute);
801         }
802 
803         return this;
804     }
805 
806     public Element addCDATA(String cdata) {
807         CDATA node = getDocumentFactory().createCDATA(cdata);
808 
809         addNewNode(node);
810 
811         return this;
812     }
813 
814     public Element addComment(String comment) {
815         Comment node = getDocumentFactory().createComment(comment);
816 
817         addNewNode(node);
818 
819         return this;
820     }
821 
822     public Element addElement(String name) {
823         DocumentFactory factory = getDocumentFactory();
824 
825         int index = name.indexOf(":");
826 
827         String prefix = "";
828 
829         String localName = name;
830 
831         Namespace namespace = null;
832 
833         if (index > 0) {
834             prefix = name.substring(0, index);
835 
836             localName = name.substring(index + 1);
837 
838             namespace = getNamespaceForPrefix(prefix);
839 
840             if (namespace == null) {
841                 throw new IllegalAddException("No such namespace prefix: "
842                         + prefix + " is in scope on: " + this
843                         + " so cannot add element: " + name);
844             }
845         } else {
846             namespace = getNamespaceForPrefix("");
847         }
848 
849         Element node;
850 
851         if (namespace != null) {
852             QName qname = factory.createQName(localName, namespace);
853 
854             node = factory.createElement(qname);
855         } else {
856             node = factory.createElement(name);
857         }
858 
859         addNewNode(node);
860 
861         return node;
862     }
863 
864     public Element addEntity(String name, String text) {
865         Entity node = getDocumentFactory().createEntity(name, text);
866 
867         addNewNode(node);
868 
869         return this;
870     }
871 
872     public Element addNamespace(String prefix, String uri) {
873         Namespace node = getDocumentFactory().createNamespace(prefix, uri);
874 
875         addNewNode(node);
876 
877         return this;
878     }
879 
880     public Element addProcessingInstruction(String target, String data) {
881         ProcessingInstruction node = getDocumentFactory()
882                 .createProcessingInstruction(target, data);
883 
884         addNewNode(node);
885 
886         return this;
887     }
888 
889     public Element addProcessingInstruction(String target, Map data) {
890         ProcessingInstruction node = getDocumentFactory()
891                 .createProcessingInstruction(target, data);
892 
893         addNewNode(node);
894 
895         return this;
896     }
897 
898     public Element addText(String text) {
899         Text node = getDocumentFactory().createText(text);
900 
901         addNewNode(node);
902 
903         return this;
904     }
905 
906     
907     public void add(Node node) {
908         switch (node.getNodeType()) {
909             case ELEMENT_NODE:
910                 add((Element) node);
911 
912                 break;
913 
914             case ATTRIBUTE_NODE:
915                 add((Attribute) node);
916 
917                 break;
918 
919             case TEXT_NODE:
920                 add((Text) node);
921 
922                 break;
923 
924             case CDATA_SECTION_NODE:
925                 add((CDATA) node);
926 
927                 break;
928 
929             case ENTITY_REFERENCE_NODE:
930                 add((Entity) node);
931 
932                 break;
933 
934             case PROCESSING_INSTRUCTION_NODE:
935                 add((ProcessingInstruction) node);
936 
937                 break;
938 
939             case COMMENT_NODE:
940                 add((Comment) node);
941 
942                 break;
943 
944             
945 
946 
947 
948             case NAMESPACE_NODE:
949                 add((Namespace) node);
950 
951                 break;
952 
953             default:
954                 invalidNodeTypeAddException(node);
955         }
956     }
957 
958     public boolean remove(Node node) {
959         switch (node.getNodeType()) {
960             case ELEMENT_NODE:
961                 return remove((Element) node);
962 
963             case ATTRIBUTE_NODE:
964                 return remove((Attribute) node);
965 
966             case TEXT_NODE:
967                 return remove((Text) node);
968 
969             case CDATA_SECTION_NODE:
970                 return remove((CDATA) node);
971 
972             case ENTITY_REFERENCE_NODE:
973                 return remove((Entity) node);
974 
975             case PROCESSING_INSTRUCTION_NODE:
976                 return remove((ProcessingInstruction) node);
977 
978             case COMMENT_NODE:
979                 return remove((Comment) node);
980 
981             
982 
983 
984             case NAMESPACE_NODE:
985                 return remove((Namespace) node);
986 
987             default:
988                 return false;
989         }
990     }
991 
992     
993     public void add(CDATA cdata) {
994         addNode(cdata);
995     }
996 
997     public void add(Comment comment) {
998         addNode(comment);
999     }
1000 
1001     public void add(Element element) {
1002         addNode(element);
1003     }
1004 
1005     public void add(Entity entity) {
1006         addNode(entity);
1007     }
1008 
1009     public void add(Namespace namespace) {
1010         addNode(namespace);
1011     }
1012 
1013     public void add(ProcessingInstruction pi) {
1014         addNode(pi);
1015     }
1016 
1017     public void add(Text text) {
1018         addNode(text);
1019     }
1020 
1021     public boolean remove(CDATA cdata) {
1022         return removeNode(cdata);
1023     }
1024 
1025     public boolean remove(Comment comment) {
1026         return removeNode(comment);
1027     }
1028 
1029     public boolean remove(Element element) {
1030         return removeNode(element);
1031     }
1032 
1033     public boolean remove(Entity entity) {
1034         return removeNode(entity);
1035     }
1036 
1037     public boolean remove(Namespace namespace) {
1038         return removeNode(namespace);
1039     }
1040 
1041     public boolean remove(ProcessingInstruction pi) {
1042         return removeNode(pi);
1043     }
1044 
1045     public boolean remove(Text text) {
1046         return removeNode(text);
1047     }
1048 
1049     
1050     
1051     public boolean hasMixedContent() {
1052         List content = contentList();
1053 
1054         if ((content == null) || content.isEmpty() || (content.size() < 2)) {
1055             return false;
1056         }
1057 
1058         Class prevClass = null;
1059 
1060         for (Iterator iter = content.iterator(); iter.hasNext();) {
1061             Object object = iter.next();
1062 
1063             Class newClass = object.getClass();
1064 
1065             if (newClass != prevClass) {
1066                 if (prevClass != null) {
1067                     return true;
1068                 }
1069 
1070                 prevClass = newClass;
1071             }
1072         }
1073 
1074         return false;
1075     }
1076 
1077     public boolean isTextOnly() {
1078         List content = contentList();
1079 
1080         if ((content == null) || content.isEmpty()) {
1081             return true;
1082         }
1083 
1084         for (Iterator iter = content.iterator(); iter.hasNext();) {
1085             Object object = iter.next();
1086 
1087             if (!(object instanceof CharacterData)
1088                     && !(object instanceof String)) {
1089                 return false;
1090             }
1091         }
1092 
1093         return true;
1094     }
1095 
1096     public void setText(String text) {
1097         
1098         List allContent = contentList();
1099 
1100         if (allContent != null) {
1101             Iterator it = allContent.iterator();
1102 
1103             while (it.hasNext()) {
1104                 Node node = (Node) it.next();
1105 
1106                 switch (node.getNodeType()) {
1107                     case CDATA_SECTION_NODE:
1108 
1109                     
1110                     case ENTITY_REFERENCE_NODE:
1111                     case TEXT_NODE:
1112                         it.remove();
1113 
1114                     default:
1115                         break;
1116                 }
1117             }
1118         }
1119 
1120         addText(text);
1121     }
1122 
1123     public String getStringValue() {
1124         List list = contentList();
1125 
1126         int size = list.size();
1127 
1128         if (size > 0) {
1129             if (size == 1) {
1130                 
1131                 return getContentAsStringValue(list.get(0));
1132             } else {
1133                 StringBuffer buffer = new StringBuffer();
1134 
1135                 for (int i = 0; i < size; i++) {
1136                     Object node = list.get(i);
1137 
1138                     String string = getContentAsStringValue(node);
1139 
1140                     if (string.length() > 0) {
1141                         if (USE_STRINGVALUE_SEPARATOR) {
1142                             if (buffer.length() > 0) {
1143                                 buffer.append(' ');
1144                             }
1145                         }
1146 
1147                         buffer.append(string);
1148                     }
1149                 }
1150 
1151                 return buffer.toString();
1152             }
1153         }
1154 
1155         return "";
1156     }
1157 
1158     /***
1159      * Puts all <code>Text</code> nodes in the full depth of the sub-tree
1160      * underneath this <code>Node</code>, including attribute nodes, into a
1161      * "normal" form where only structure (e.g., elements, comments, processing
1162      * instructions, CDATA sections, and entity references) separates
1163      * <code>Text</code> nodes, i.e., there are neither adjacent
1164      * <code>Text</code> nodes nor empty <code>Text</code> nodes. This can
1165      * be used to ensure that the DOM view of a document is the same as if it
1166      * were saved and re-loaded, and is useful when operations (such as XPointer
1167      * lookups) that depend on a particular document tree structure are to be
1168      * used.In cases where the document contains <code>CDATASections</code>,
1169      * the normalize operation alone may not be sufficient, since XPointers do
1170      * not differentiate between <code>Text</code> nodes and
1171      * <code>CDATASection</code> nodes.
1172      * 
1173      * @since DOM Level 2
1174      */
1175     public void normalize() {
1176         List content = contentList();
1177 
1178         Text previousText = null;
1179 
1180         int i = 0;
1181 
1182         while (i < content.size()) {
1183             Node node = (Node) content.get(i);
1184 
1185             if (node instanceof Text) {
1186                 Text text = (Text) node;
1187 
1188                 if (previousText != null) {
1189                     previousText.appendText(text.getText());
1190 
1191                     remove(text);
1192                 } else {
1193                     String value = text.getText();
1194 
1195                     
1196                     
1197                     if ((value == null) || (value.length() <= 0)) {
1198                         remove(text);
1199                     } else {
1200                         previousText = text;
1201 
1202                         i++;
1203                     }
1204                 }
1205             } else {
1206                 if (node instanceof Element) {
1207                     Element element = (Element) node;
1208 
1209                     element.normalize();
1210                 }
1211 
1212                 previousText = null;
1213 
1214                 i++;
1215             }
1216         }
1217     }
1218 
1219     public String elementText(String name) {
1220         Element element = element(name);
1221 
1222         return (element != null) ? element.getText() : null;
1223     }
1224 
1225     public String elementText(QName qName) {
1226         Element element = element(qName);
1227 
1228         return (element != null) ? element.getText() : null;
1229     }
1230 
1231     public String elementTextTrim(String name) {
1232         Element element = element(name);
1233 
1234         return (element != null) ? element.getTextTrim() : null;
1235     }
1236 
1237     public String elementTextTrim(QName qName) {
1238         Element element = element(qName);
1239 
1240         return (element != null) ? element.getTextTrim() : null;
1241     }
1242 
1243     
1244     
1245     public void appendAttributes(Element element) {
1246         for (int i = 0, size = element.attributeCount(); i < size; i++) {
1247             Attribute attribute = element.attribute(i);
1248 
1249             if (attribute.supportsParent()) {
1250                 addAttribute(attribute.getQName(), attribute.getValue());
1251             } else {
1252                 add(attribute);
1253             }
1254         }
1255     }
1256 
1257     /***
1258      * <p>
1259      * This returns a deep clone of this element. The new element is detached
1260      * from its parent, and getParent() on the clone will return null.
1261      * </p>
1262      * 
1263      * @return the clone of this element
1264      */
1265 
1266     
1267 
1268 
1269 
1270     public Element createCopy() {
1271         Element clone = createElement(getQName());
1272 
1273         clone.appendAttributes(this);
1274 
1275         clone.appendContent(this);
1276 
1277         return clone;
1278     }
1279 
1280     public Element createCopy(String name) {
1281         Element clone = createElement(name);
1282 
1283         clone.appendAttributes(this);
1284 
1285         clone.appendContent(this);
1286 
1287         return clone;
1288     }
1289 
1290     public Element createCopy(QName qName) {
1291         Element clone = createElement(qName);
1292 
1293         clone.appendAttributes(this);
1294 
1295         clone.appendContent(this);
1296 
1297         return clone;
1298     }
1299 
1300     public QName getQName(String qualifiedName) {
1301         String prefix = "";
1302 
1303         String localName = qualifiedName;
1304 
1305         int index = qualifiedName.indexOf(":");
1306 
1307         if (index > 0) {
1308             prefix = qualifiedName.substring(0, index);
1309 
1310             localName = qualifiedName.substring(index + 1);
1311         }
1312 
1313         Namespace namespace = getNamespaceForPrefix(prefix);
1314 
1315         if (namespace != null) {
1316             return getDocumentFactory().createQName(localName, namespace);
1317         } else {
1318             return getDocumentFactory().createQName(localName);
1319         }
1320     }
1321 
1322     public Namespace getNamespaceForPrefix(String prefix) {
1323         if (prefix == null) {
1324             prefix = "";
1325         }
1326 
1327         if (prefix.equals(getNamespacePrefix())) {
1328             return getNamespace();
1329         } else if (prefix.equals("xml")) {
1330             return Namespace.XML_NAMESPACE;
1331         } else {
1332             List list = contentList();
1333 
1334             int size = list.size();
1335 
1336             for (int i = 0; i < size; i++) {
1337                 Object object = list.get(i);
1338 
1339                 if (object instanceof Namespace) {
1340                     Namespace namespace = (Namespace) object;
1341 
1342                     if (prefix.equals(namespace.getPrefix())) {
1343                         return namespace;
1344                     }
1345                 }
1346             }
1347         }
1348 
1349         Element parent = getParent();
1350 
1351         if (parent != null) {
1352             Namespace answer = parent.getNamespaceForPrefix(prefix);
1353 
1354             if (answer != null) {
1355                 return answer;
1356             }
1357         }
1358 
1359         if ((prefix == null) || (prefix.length() <= 0)) {
1360             return Namespace.NO_NAMESPACE;
1361         }
1362 
1363         return null;
1364     }
1365 
1366     public Namespace getNamespaceForURI(String uri) {
1367         if ((uri == null) || (uri.length() <= 0)) {
1368             return Namespace.NO_NAMESPACE;
1369         } else if (uri.equals(getNamespaceURI())) {
1370             return getNamespace();
1371         } else {
1372             List list = contentList();
1373 
1374             int size = list.size();
1375 
1376             for (int i = 0; i < size; i++) {
1377                 Object object = list.get(i);
1378 
1379                 if (object instanceof Namespace) {
1380                     Namespace namespace = (Namespace) object;
1381 
1382                     if (uri.equals(namespace.getURI())) {
1383                         return namespace;
1384                     }
1385                 }
1386             }
1387 
1388             return null;
1389         }
1390     }
1391 
1392     public List getNamespacesForURI(String uri) {
1393         BackedList answer = createResultList();
1394 
1395         
1396         
1397         
1398         
1399         
1400         List list = contentList();
1401 
1402         int size = list.size();
1403 
1404         for (int i = 0; i < size; i++) {
1405             Object object = list.get(i);
1406 
1407             if ((object instanceof Namespace)
1408                     && ((Namespace) object).getURI().equals(uri)) {
1409                 answer.addLocal(object);
1410             }
1411         }
1412 
1413         return answer;
1414     }
1415 
1416     public List declaredNamespaces() {
1417         BackedList answer = createResultList();
1418 
1419         
1420         
1421         
1422         
1423         
1424         
1425         List list = contentList();
1426 
1427         int size = list.size();
1428 
1429         for (int i = 0; i < size; i++) {
1430             Object object = list.get(i);
1431 
1432             if (object instanceof Namespace) {
1433                 answer.addLocal(object);
1434             }
1435         }
1436 
1437         return answer;
1438     }
1439 
1440     public List additionalNamespaces() {
1441         List list = contentList();
1442 
1443         int size = list.size();
1444 
1445         BackedList answer = createResultList();
1446 
1447         for (int i = 0; i < size; i++) {
1448             Object object = list.get(i);
1449 
1450             if (object instanceof Namespace) {
1451                 Namespace namespace = (Namespace) object;
1452 
1453                 if (!namespace.equals(getNamespace())) {
1454                     answer.addLocal(namespace);
1455                 }
1456             }
1457         }
1458 
1459         return answer;
1460     }
1461 
1462     public List additionalNamespaces(String defaultNamespaceURI) {
1463         List list = contentList();
1464 
1465         BackedList answer = createResultList();
1466 
1467         int size = list.size();
1468 
1469         for (int i = 0; i < size; i++) {
1470             Object object = list.get(i);
1471 
1472             if (object instanceof Namespace) {
1473                 Namespace namespace = (Namespace) object;
1474 
1475                 if (!defaultNamespaceURI.equals(namespace.getURI())) {
1476                     answer.addLocal(namespace);
1477                 }
1478             }
1479         }
1480 
1481         return answer;
1482     }
1483 
1484     
1485     
1486 
1487     /***
1488      * Ensures that the list of attributes has the given size
1489      * 
1490      * @param minCapacity
1491      *            DOCUMENT ME!
1492      */
1493     public void ensureAttributesCapacity(int minCapacity) {
1494         if (minCapacity > 1) {
1495             List list = attributeList();
1496 
1497             if (list instanceof ArrayList) {
1498                 ArrayList arrayList = (ArrayList) list;
1499 
1500                 arrayList.ensureCapacity(minCapacity);
1501             }
1502         }
1503     }
1504 
1505     
1506     
1507     protected Element createElement(String name) {
1508         return getDocumentFactory().createElement(name);
1509     }
1510 
1511     protected Element createElement(QName qName) {
1512         return getDocumentFactory().createElement(qName);
1513     }
1514 
1515     protected void addNode(Node node) {
1516         if (node.getParent() != null) {
1517             
1518             String message = "The Node already has an existing parent of \""
1519                     + node.getParent().getQualifiedName() + "\"";
1520 
1521             throw new IllegalAddException(this, node, message);
1522         }
1523 
1524         addNewNode(node);
1525     }
1526 
1527     protected void addNode(int index, Node node) {
1528         if (node.getParent() != null) {
1529             
1530             String message = "The Node already has an existing parent of \""
1531                     + node.getParent().getQualifiedName() + "\"";
1532 
1533             throw new IllegalAddException(this, node, message);
1534         }
1535 
1536         addNewNode(index, node);
1537     }
1538 
1539     /***
1540      * Like addNode() but does not require a parent check
1541      * 
1542      * @param node
1543      *            DOCUMENT ME!
1544      */
1545     protected void addNewNode(Node node) {
1546         contentList().add(node);
1547 
1548         childAdded(node);
1549     }
1550 
1551     protected void addNewNode(int index, Node node) {
1552         contentList().add(index, node);
1553 
1554         childAdded(node);
1555     }
1556 
1557     protected boolean removeNode(Node node) {
1558         boolean answer = contentList().remove(node);
1559 
1560         if (answer) {
1561             childRemoved(node);
1562         }
1563 
1564         return answer;
1565     }
1566 
1567     /***
1568      * Called when a new child node is added to create any parent relationships
1569      * 
1570      * @param node
1571      *            DOCUMENT ME!
1572      */
1573     protected void childAdded(Node node) {
1574         if (node != null) {
1575             node.setParent(this);
1576         }
1577     }
1578 
1579     protected void childRemoved(Node node) {
1580         if (node != null) {
1581             node.setParent(null);
1582 
1583             node.setDocument(null);
1584         }
1585     }
1586 
1587     /***
1588      * DOCUMENT ME!
1589      * 
1590      * @return the internal List used to store attributes or creates one if one
1591      *         is not available
1592      */
1593     protected abstract List attributeList();
1594 
1595     /***
1596      * DOCUMENT ME!
1597      * 
1598      * @param attributeCount
1599      *            DOCUMENT ME!
1600      * 
1601      * @return the internal List used to store attributes or creates one with
1602      *         the specified size if one is not available
1603      */
1604     protected abstract List attributeList(int attributeCount);
1605 
1606     protected DocumentFactory getDocumentFactory() {
1607         QName qName = getQName();
1608 
1609         
1610         if (qName != null) {
1611             DocumentFactory factory = qName.getDocumentFactory();
1612 
1613             if (factory != null) {
1614                 return factory;
1615             }
1616         }
1617 
1618         return DOCUMENT_FACTORY;
1619     }
1620 
1621     /***
1622      * A Factory Method pattern which creates a List implementation used to
1623      * store attributes
1624      * 
1625      * @return DOCUMENT ME!
1626      */
1627     protected List createAttributeList() {
1628         return createAttributeList(DEFAULT_CONTENT_LIST_SIZE);
1629     }
1630 
1631     /***
1632      * A Factory Method pattern which creates a List implementation used to
1633      * store attributes
1634      * 
1635      * @param size
1636      *            DOCUMENT ME!
1637      * 
1638      * @return DOCUMENT ME!
1639      */
1640     protected List createAttributeList(int size) {
1641         return new ArrayList(size);
1642     }
1643 
1644     protected Iterator createSingleIterator(Object result) {
1645         return new SingleIterator(result);
1646     }
1647 }
1648 
1649 
1650 
1651 
1652 
1653 
1654 
1655 
1656 
1657 
1658 
1659 
1660 
1661 
1662 
1663 
1664 
1665 
1666 
1667 
1668 
1669 
1670 
1671 
1672 
1673 
1674 
1675 
1676 
1677 
1678 
1679 
1680 
1681 
1682 
1683 
1684