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