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