1
2
3
4
5
6
7
8
9
10 package org.dom4j.tree;
11
12 import java.io.IOException;
13 import java.io.StringWriter;
14 import java.io.Writer;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20
21 import org.dom4j.Attribute;
22 import org.dom4j.CDATA;
23 import org.dom4j.CharacterData;
24 import org.dom4j.Comment;
25 import org.dom4j.Document;
26 import org.dom4j.DocumentFactory;
27 import org.dom4j.Element;
28 import org.dom4j.Entity;
29 import org.dom4j.IllegalAddException;
30 import org.dom4j.Namespace;
31 import org.dom4j.Node;
32 import org.dom4j.ProcessingInstruction;
33 import org.dom4j.QName;
34 import org.dom4j.Text;
35 import org.dom4j.Visitor;
36 import org.dom4j.io.XMLWriter;
37 import org.xml.sax.Attributes;
38
39 /*** <p><code>AbstractElement</code> is an abstract base class for
40 * tree implementors to use for implementation inheritence.</p>
41 *
42 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
43 * @version $Revision: 1.77 $
44 */
45
46 public abstract class AbstractElement
47 extends AbstractBranch
48 implements Element {
49
50 /*** The <code>DocumentFactory</code> instance used by default */
51
52 private static final DocumentFactory DOCUMENT_FACTORY =
53 DocumentFactory.getInstance();
54
55 protected static final List EMPTY_LIST = Collections.EMPTY_LIST;
56
57 protected static final Iterator EMPTY_ITERATOR = EMPTY_LIST.iterator();
58
59 protected static final boolean VERBOSE_TOSTRING = false;
60
61 protected static final boolean USE_STRINGVALUE_SEPARATOR = false;
62
63 public AbstractElement() {
64
65 }
66
67 public short getNodeType() {
68
69 return ELEMENT_NODE;
70
71 }
72
73 public boolean isRootElement() {
74
75 Document document = getDocument();
76
77 if (document != null) {
78
79 Element root = document.getRootElement();
80
81 if (root == this) {
82
83 return true;
84
85 }
86
87 }
88
89 return false;
90
91 }
92
93 public void setName(String name) {
94
95 setQName(getDocumentFactory().createQName(name));
96
97 }
98
99 public void setNamespace(Namespace namespace) {
100
101 setQName(getDocumentFactory().createQName(getName(), namespace));
102
103 }
104
105 /*** Returns the XPath expression to match this Elements name
106 * which is getQualifiedName() if there is a namespace prefix defined or
107 * if no namespace is present then it is getName() or if a namespace is defined
108 * with no prefix then the expression is *[name()='X'] where X = getName().
109 */
110
111 public String getXPathNameStep() {
112
113 String uri = getNamespaceURI();
114
115 if (uri == null || uri.length() == 0) {
116
117 return getName();
118
119 }
120
121 String prefix = getNamespacePrefix();
122
123 if (prefix == null || prefix.length() == 0) {
124
125 return "*[name()='" + getName() + "']";
126
127 }
128
129 return getQualifiedName();
130
131 }
132
133 public String getPath(Element context) {
134
135 if (this == context) {
136 return ".";
137 }
138
139 Element parent = getParent();
140
141 if (parent == null) {
142
143 return "/" + getXPathNameStep();
144
145 }
146
147 else if (parent == context) {
148
149 return getXPathNameStep();
150
151 }
152
153 return parent.getPath(context) + "/" + getXPathNameStep();
154
155 }
156
157 public String getUniquePath(Element context) {
158
159 Element parent = getParent();
160
161 if (parent == null) {
162
163 return "/" + getXPathNameStep();
164
165 }
166
167 StringBuffer buffer = new StringBuffer();
168
169 if (parent != context) {
170
171 buffer.append(parent.getUniquePath(context));
172
173 buffer.append("/");
174
175 }
176
177 buffer.append(getXPathNameStep());
178
179 List mySiblings = parent.elements(getQName());
180
181 if (mySiblings.size() > 1) {
182
183 int idx = mySiblings.indexOf(this);
184
185 if (idx >= 0) {
186
187 buffer.append("[");
188
189 buffer.append(Integer.toString(++idx));
190
191 buffer.append("]");
192
193 }
194
195 }
196
197 return buffer.toString();
198
199 }
200
201 public String asXML() {
202
203 try {
204
205 StringWriter out = new StringWriter();
206
207 XMLWriter writer = new XMLWriter(out, outputFormat);
208
209 writer.write(this);
210
211 return out.toString();
212
213 }
214
215 catch (IOException e) {
216
217 throw new RuntimeException(
218 "Wierd IOException while generating textual representation: " + e.getMessage());
219
220 }
221
222 }
223
224 public void write(Writer out) throws IOException {
225
226 XMLWriter writer = new XMLWriter(out, outputFormat);
227
228 writer.write(this);
229
230 }
231
232 /*** <p><code>accept</code> method is the <code>Visitor Pattern</code> method.
233 * </p>
234 *
235 * @param visitor <code>Visitor</code> is the visitor.
236 */
237
238 public void accept(Visitor visitor) {
239
240 visitor.visit(this);
241
242
243
244 for (int i = 0, size = attributeCount(); i < size; i++) {
245
246 Attribute attribute = attribute(i);
247
248 visitor.visit(attribute);
249
250 }
251
252
253
254 for (int i = 0, size = nodeCount(); i < size; i++) {
255
256 Node node = node(i);
257
258 node.accept(visitor);
259
260 }
261
262 }
263
264 public String toString() {
265
266 String uri = getNamespaceURI();
267
268 if (uri != null && uri.length() > 0) {
269
270 if (VERBOSE_TOSTRING) {
271
272 return super.toString()
273 + " [Element: <"
274 + getQualifiedName()
275 + " uri: "
276 + uri
277 + " attributes: "
278 + attributeList()
279 + " content: "
280 + contentList()
281 + " />]";
282
283 }
284
285 else {
286
287 return super.toString()
288 + " [Element: <"
289 + getQualifiedName()
290 + " uri: "
291 + uri
292 + " attributes: "
293 + attributeList()
294 + "/>]";
295
296 }
297
298 }
299
300 else {
301
302 if (VERBOSE_TOSTRING) {
303
304 return super.toString()
305 + " [Element: <"
306 + getQualifiedName()
307 + " attributes: "
308 + attributeList()
309 + " content: "
310 + contentList()
311 + " />]";
312
313 }
314
315 else {
316
317 return super.toString()
318 + " [Element: <"
319 + getQualifiedName()
320 + " attributes: "
321 + attributeList()
322 + "/>]";
323
324 }
325
326 }
327
328 }
329
330
331
332
333
334 public Namespace getNamespace() {
335
336 return getQName().getNamespace();
337
338 }
339
340 public String getName() {
341
342 return getQName().getName();
343
344 }
345
346 public String getNamespacePrefix() {
347
348 return getQName().getNamespacePrefix();
349
350 }
351
352 public String getNamespaceURI() {
353
354 return getQName().getNamespaceURI();
355
356 }
357
358 public String getQualifiedName() {
359
360 return getQName().getQualifiedName();
361
362 }
363
364 public Object getData() {
365
366 return getText();
367
368 }
369
370 public void setData(Object data) {
371
372
373
374 }
375
376
377
378
379
380 public Node node(int index) {
381
382 if (index >= 0) {
383
384 List list = contentList();
385
386 if (index >= list.size()) {
387
388 return null;
389
390 }
391
392 Object node = list.get(index);
393
394 if (node != null) {
395
396 if (node instanceof Node) {
397
398 return (Node) node;
399
400 }
401
402 else {
403
404 return getDocumentFactory().createText(node.toString());
405
406 }
407
408 }
409
410 }
411
412 return null;
413
414 }
415
416 public int indexOf(Node node) {
417
418 return contentList().indexOf(node);
419
420 }
421
422 public int nodeCount() {
423
424 return contentList().size();
425
426 }
427
428 public Iterator nodeIterator() {
429
430 return contentList().iterator();
431
432 }
433
434
435
436
437
438 public Element element(String name) {
439
440 List list = contentList();
441
442 int size = list.size();
443
444 for (int i = 0; i < size; i++) {
445
446 Object object = list.get(i);
447
448 if (object instanceof Element) {
449
450 Element element = (Element) object;
451
452 if (name.equals(element.getName())) {
453
454 return element;
455
456 }
457
458 }
459
460 }
461
462 return null;
463
464 }
465
466 public Element element(QName qName) {
467
468 List list = contentList();
469
470 int size = list.size();
471
472 for (int i = 0; i < size; i++) {
473
474 Object object = list.get(i);
475
476 if (object instanceof Element) {
477
478 Element element = (Element) object;
479
480 if (qName.equals(element.getQName())) {
481
482 return element;
483
484 }
485
486 }
487
488 }
489
490 return null;
491
492 }
493
494 public Element element(String name, Namespace namespace) {
495
496 return element(getDocumentFactory().createQName(name, namespace));
497
498 }
499
500 public List elements() {
501
502 List list = contentList();
503
504 BackedList answer = createResultList();
505
506 int size = list.size();
507
508 for (int i = 0; i < size; i++) {
509
510 Object object = list.get(i);
511
512 if (object instanceof Element) {
513
514 answer.addLocal(object);
515
516 }
517
518 }
519
520 return answer;
521
522 }
523
524 public List elements(String name) {
525
526 List list = contentList();
527
528 BackedList answer = createResultList();
529
530 int size = list.size();
531
532 for (int i = 0; i < size; i++) {
533
534 Object object = list.get(i);
535
536 if (object instanceof Element) {
537
538 Element element = (Element) object;
539
540 if (name.equals(element.getName())) {
541
542 answer.addLocal(element);
543
544 }
545
546 }
547
548 }
549
550 return answer;
551
552 }
553
554 public List elements(QName qName) {
555
556 List list = contentList();
557
558 BackedList answer = createResultList();
559
560 int size = list.size();
561
562 for (int i = 0; i < size; i++) {
563
564 Object object = list.get(i);
565
566 if (object instanceof Element) {
567
568 Element element = (Element) object;
569
570 if (qName.equals(element.getQName())) {
571
572 answer.addLocal(element);
573
574 }
575
576 }
577
578 }
579
580 return answer;
581
582 }
583
584 public List elements(String name, Namespace namespace) {
585
586 return elements(getDocumentFactory().createQName(name, namespace));
587
588 }
589
590 public Iterator elementIterator() {
591
592 List list = elements();
593
594 return list.iterator();
595
596 }
597
598 public Iterator elementIterator(String name) {
599
600 List list = elements(name);
601
602 return list.iterator();
603
604 }
605
606 public Iterator elementIterator(QName qName) {
607
608 List list = elements(qName);
609
610 return list.iterator();
611
612 }
613
614 public Iterator elementIterator(String name, Namespace namespace) {
615
616 return elementIterator(getDocumentFactory().createQName(name, namespace));
617
618 }
619
620
621
622
623
624 public List attributes() {
625
626 return new ContentListFacade(this, attributeList());
627
628 }
629
630 public Iterator attributeIterator() {
631
632 return attributeList().iterator();
633
634 }
635
636 public Attribute attribute(int index) {
637
638 return (Attribute) attributeList().get(index);
639
640 }
641
642 public int attributeCount() {
643
644 return attributeList().size();
645
646 }
647
648 public Attribute attribute(String name) {
649
650 List list = attributeList();
651
652 int size = list.size();
653
654 for (int i = 0; i < size; i++) {
655
656 Attribute attribute = (Attribute) list.get(i);
657
658 if (name.equals(attribute.getName())) {
659
660 return attribute;
661
662 }
663
664 }
665
666 return null;
667
668 }
669
670 public Attribute attribute(QName qName) {
671
672 List list = attributeList();
673
674 int size = list.size();
675
676 for (int i = 0; i < size; i++) {
677
678 Attribute attribute = (Attribute) list.get(i);
679
680 if (qName.equals(attribute.getQName())) {
681
682 return attribute;
683
684 }
685
686 }
687
688 return null;
689
690 }
691
692 public Attribute attribute(String name, Namespace namespace) {
693
694 return attribute(getDocumentFactory().createQName(name, namespace));
695
696 }
697
698 /*** This method provides a more optimal way of setting all the attributes
699 * on an Element particularly for use in {@link org.dom4j.io.SAXReader}.
700 */
701
702 public void setAttributes(
703 Attributes attributes,
704 NamespaceStack namespaceStack,
705 boolean noNamespaceAttributes) {
706
707
708
709 int size = attributes.getLength();
710
711 if (size > 0) {
712
713 DocumentFactory factory = getDocumentFactory();
714
715 if (size == 1) {
716
717
718
719 String attributeQualifiedName = attributes.getQName(0);
720
721 if (noNamespaceAttributes || !attributeQualifiedName.startsWith("xmlns")) {
722
723 String attributeURI = attributes.getURI(0);
724
725 String attributeLocalName = attributes.getLocalName(0);
726
727 String attributeValue = attributes.getValue(0);
728
729 QName attributeQName =
730 namespaceStack.getAttributeQName(
731 attributeURI,
732 attributeLocalName,
733 attributeQualifiedName);
734
735 add(factory.createAttribute(this, attributeQName, attributeValue));
736
737 }
738
739 }
740
741 else {
742
743 List list = attributeList(size);
744
745 list.clear();
746
747 for (int i = 0; i < size; i++) {
748
749
750
751
752
753 String attributeQualifiedName = attributes.getQName(i);
754
755 if (noNamespaceAttributes || !attributeQualifiedName.startsWith("xmlns")) {
756
757 String attributeURI = attributes.getURI(i);
758
759 String attributeLocalName = attributes.getLocalName(i);
760
761 String attributeValue = attributes.getValue(i);
762
763 QName attributeQName =
764 namespaceStack.getAttributeQName(
765 attributeURI,
766 attributeLocalName,
767 attributeQualifiedName);
768
769 Attribute attribute =
770 factory.createAttribute(this, attributeQName, attributeValue);
771
772 list.add(attribute);
773
774 childAdded(attribute);
775
776 }
777
778 }
779
780 }
781
782 }
783
784 }
785
786 public String attributeValue(String name) {
787
788 Attribute attrib = attribute(name);
789
790 if (attrib == null) {
791
792 return null;
793
794 }
795
796 else {
797
798 return attrib.getValue();
799
800 }
801
802 }
803
804 public String attributeValue(QName qName) {
805
806 Attribute attrib = attribute(qName);
807
808 if (attrib == null) {
809
810 return null;
811
812 }
813
814 else {
815
816 return attrib.getValue();
817
818 }
819
820 }
821
822 public String attributeValue(String name, String defaultValue) {
823
824 String answer = attributeValue(name);
825
826 return (answer != null) ? answer : defaultValue;
827
828 }
829
830 public String attributeValue(QName qName, String defaultValue) {
831
832 String answer = attributeValue(qName);
833
834 return (answer != null) ? answer : defaultValue;
835
836 }
837
838 /***
839 * @deprecated As of version 0.5. Please use
840 * {@link #addAttribute(String,String)} instead.
841 * WILL BE REMOVED IN dom4j-1.6 !!
842 **/
843 public void setAttributeValue(String name, String value) {
844
845 addAttribute(name, value);
846
847 }
848
849 /***
850 * @deprecated As of version 0.5. Please use
851 * {@link #addAttribute(String,String)} instead.
852 * WILL BE REMOVED IN dom4j-1.6 !!
853 **/
854 public void setAttributeValue(QName qName, String value) {
855
856 addAttribute(qName, value);
857
858 }
859
860 public void add(Attribute attribute) {
861
862 if (attribute.getParent() != null) {
863
864 String message =
865 "The Attribute already has an existing parent \""
866 + attribute.getParent().getQualifiedName()
867 + "\"";
868
869 throw new IllegalAddException(this, attribute, message);
870
871 }
872
873 if (attribute.getValue() == null) {
874
875
876
877
878
879
880
881 Attribute oldAttribute = attribute(attribute.getQName());
882
883 if (oldAttribute != null) {
884
885 remove(oldAttribute);
886
887 }
888
889 }
890
891 else {
892
893 attributeList().add(attribute);
894
895 childAdded(attribute);
896
897 }
898
899 }
900
901 public boolean remove(Attribute attribute) {
902
903 List list = attributeList();
904
905 boolean answer = list.remove(attribute);
906
907 if (answer) {
908
909 childRemoved(attribute);
910
911 }
912
913 else {
914
915
916
917 Attribute copy = attribute(attribute.getQName());
918
919 if (copy != null) {
920
921 list.remove(copy);
922
923 answer = true;
924
925 }
926
927 }
928
929 return answer;
930
931 }
932
933
934
935
936
937 public List processingInstructions() {
938
939 List list = contentList();
940
941 BackedList answer = createResultList();
942
943 int size = list.size();
944
945 for (int i = 0; i < size; i++) {
946
947 Object object = list.get(i);
948
949 if (object instanceof ProcessingInstruction) {
950
951 answer.addLocal(object);
952
953 }
954
955 }
956
957 return answer;
958
959 }
960
961 public List processingInstructions(String target) {
962
963 List list = contentList();
964
965 BackedList answer = createResultList();
966
967 int size = list.size();
968
969 for (int i = 0; i < size; i++) {
970
971 Object object = list.get(i);
972
973 if (object instanceof ProcessingInstruction) {
974
975 ProcessingInstruction pi = (ProcessingInstruction) object;
976
977 if (target.equals(pi.getName())) {
978
979 answer.addLocal(pi);
980
981 }
982
983 }
984
985 }
986
987 return answer;
988
989 }
990
991 public ProcessingInstruction processingInstruction(String target) {
992
993 List list = contentList();
994
995 int size = list.size();
996
997 for (int i = 0; i < size; i++) {
998
999 Object object = list.get(i);
1000
1001 if (object instanceof ProcessingInstruction) {
1002
1003 ProcessingInstruction pi = (ProcessingInstruction) object;
1004
1005 if (target.equals(pi.getName())) {
1006
1007 return pi;
1008
1009 }
1010
1011 }
1012
1013 }
1014
1015 return null;
1016
1017 }
1018
1019 public boolean removeProcessingInstruction(String target) {
1020
1021 List list = contentList();
1022
1023 for (Iterator iter = list.iterator(); iter.hasNext();) {
1024
1025 Object object = iter.next();
1026
1027 if (object instanceof ProcessingInstruction) {
1028
1029 ProcessingInstruction pi = (ProcessingInstruction) object;
1030
1031 if (target.equals(pi.getName())) {
1032
1033 iter.remove();
1034
1035 return true;
1036
1037 }
1038
1039 }
1040
1041 }
1042
1043 return false;
1044
1045 }
1046
1047
1048
1049
1050
1051 public Node getXPathResult(int index) {
1052
1053 Node answer = node(index);
1054
1055 if (answer != null && !answer.supportsParent()) {
1056
1057 return answer.asXPathResult(this);
1058
1059 }
1060
1061 return answer;
1062
1063 }
1064
1065 public Element addAttribute(String name, String value) {
1066
1067
1068
1069 Attribute attribute = attribute(name);
1070
1071 if (value != null) {
1072
1073 if (attribute == null) {
1074
1075 add(getDocumentFactory().createAttribute(this, name, value));
1076
1077 }
1078
1079 else if (attribute.isReadOnly()) {
1080
1081 remove(attribute);
1082
1083 add(getDocumentFactory().createAttribute(this, name, value));
1084
1085 }
1086
1087 else {
1088
1089 attribute.setValue(value);
1090
1091 }
1092
1093 }
1094
1095 else if (attribute != null) {
1096
1097 remove(attribute);
1098
1099 }
1100
1101 return this;
1102
1103 }
1104
1105 public Element addAttribute(QName qName, String value) {
1106
1107
1108
1109 Attribute attribute = attribute(qName);
1110
1111 if (value != null) {
1112
1113 if (attribute == null) {
1114
1115 add(getDocumentFactory().createAttribute(this, qName, value));
1116
1117 }
1118
1119 else if (attribute.isReadOnly()) {
1120
1121 remove(attribute);
1122
1123 add(getDocumentFactory().createAttribute(this, qName, value));
1124
1125 }
1126
1127 else {
1128
1129 attribute.setValue(value);
1130
1131 }
1132
1133 }
1134
1135 else if (attribute != null) {
1136
1137 remove(attribute);
1138
1139 }
1140
1141 return this;
1142
1143 }
1144
1145 public Element addCDATA(String cdata) {
1146
1147 CDATA node = getDocumentFactory().createCDATA(cdata);
1148
1149 addNewNode(node);
1150
1151 return this;
1152
1153 }
1154
1155 public Element addComment(String comment) {
1156
1157 Comment node = getDocumentFactory().createComment(comment);
1158
1159 addNewNode(node);
1160
1161 return this;
1162
1163 }
1164
1165 public Element addElement(String name) {
1166
1167 DocumentFactory factory = getDocumentFactory();
1168
1169 int index = name.indexOf(":");
1170
1171 String prefix = "";
1172
1173 String localName = name;
1174
1175 Namespace namespace = null;
1176
1177 if (index > 0) {
1178
1179 prefix = name.substring(0, index);
1180
1181 localName = name.substring(index + 1);
1182
1183 namespace = getNamespaceForPrefix(prefix);
1184
1185 if (namespace == null) {
1186
1187 throw new IllegalAddException(
1188 "No such namespace prefix: "
1189 + prefix
1190 + " is in scope on: "
1191 + this
1192 + " so cannot add element: "
1193 + name);
1194
1195 }
1196
1197 }
1198
1199 else {
1200
1201 namespace = getNamespaceForPrefix("");
1202
1203 }
1204
1205 Element node;
1206
1207 if (namespace != null) {
1208
1209 QName qname = factory.createQName(localName, namespace);
1210
1211 node = factory.createElement(qname);
1212
1213 }
1214
1215 else {
1216
1217 node = factory.createElement(name);
1218
1219 }
1220
1221 addNewNode(node);
1222
1223 return node;
1224
1225 }
1226
1227 public Element addEntity(String name, String text) {
1228
1229 Entity node = getDocumentFactory().createEntity(name, text);
1230
1231 addNewNode(node);
1232
1233 return this;
1234
1235 }
1236
1237 public Element addNamespace(String prefix, String uri) {
1238
1239 Namespace node = getDocumentFactory().createNamespace(prefix, uri);
1240
1241 addNewNode(node);
1242
1243 return this;
1244
1245 }
1246
1247 public Element addProcessingInstruction(String target, String data) {
1248
1249 ProcessingInstruction node =
1250 getDocumentFactory().createProcessingInstruction(target, data);
1251
1252 addNewNode(node);
1253
1254 return this;
1255
1256 }
1257
1258 public Element addProcessingInstruction(String target, Map data) {
1259
1260 ProcessingInstruction node =
1261 getDocumentFactory().createProcessingInstruction(target, data);
1262
1263 addNewNode(node);
1264
1265 return this;
1266
1267 }
1268
1269 public Element addText(String text) {
1270
1271 Text node = getDocumentFactory().createText(text);
1272
1273 addNewNode(node);
1274
1275 return this;
1276
1277 }
1278
1279
1280
1281 public void add(Node node) {
1282
1283 switch (node.getNodeType()) {
1284
1285 case ELEMENT_NODE :
1286
1287 add((Element) node);
1288
1289 break;
1290
1291 case ATTRIBUTE_NODE :
1292
1293 add((Attribute) node);
1294
1295 break;
1296
1297 case TEXT_NODE :
1298
1299 add((Text) node);
1300
1301 break;
1302
1303 case CDATA_SECTION_NODE :
1304
1305 add((CDATA) node);
1306
1307 break;
1308
1309 case ENTITY_REFERENCE_NODE :
1310
1311 add((Entity) node);
1312
1313 break;
1314
1315 case PROCESSING_INSTRUCTION_NODE :
1316
1317 add((ProcessingInstruction) node);
1318
1319 break;
1320
1321 case COMMENT_NODE :
1322
1323 add((Comment) node);
1324
1325 break;
1326
1327
1328
1329
1330
1331
1332
1333 case NAMESPACE_NODE :
1334
1335 add((Namespace) node);
1336
1337 break;
1338
1339 default :
1340
1341 invalidNodeTypeAddException(node);
1342
1343 }
1344
1345 }
1346
1347 public boolean remove(Node node) {
1348
1349 switch (node.getNodeType()) {
1350
1351 case ELEMENT_NODE :
1352
1353 return remove((Element) node);
1354
1355 case ATTRIBUTE_NODE :
1356
1357 return remove((Attribute) node);
1358
1359 case TEXT_NODE :
1360
1361 return remove((Text) node);
1362
1363 case CDATA_SECTION_NODE :
1364
1365 return remove((CDATA) node);
1366
1367 case ENTITY_REFERENCE_NODE :
1368
1369 return remove((Entity) node);
1370
1371 case PROCESSING_INSTRUCTION_NODE :
1372
1373 return remove((ProcessingInstruction) node);
1374
1375 case COMMENT_NODE :
1376
1377 return remove((Comment) node);
1378
1379
1380
1381
1382
1383
1384 case NAMESPACE_NODE :
1385
1386 return remove((Namespace) node);
1387
1388 default :
1389
1390 return false;
1391
1392 }
1393
1394 }
1395
1396
1397
1398 public void add(CDATA cdata) {
1399
1400 addNode(cdata);
1401
1402 }
1403
1404 public void add(Comment comment) {
1405
1406 addNode(comment);
1407
1408 }
1409
1410 public void add(Element element) {
1411
1412 addNode(element);
1413
1414 }
1415
1416 public void add(Entity entity) {
1417
1418 addNode(entity);
1419
1420 }
1421
1422 public void add(Namespace namespace) {
1423
1424 addNode(namespace);
1425
1426 }
1427
1428 public void add(ProcessingInstruction pi) {
1429
1430 addNode(pi);
1431
1432 }
1433
1434 public void add(Text text) {
1435
1436 addNode(text);
1437
1438 }
1439
1440 public boolean remove(CDATA cdata) {
1441
1442 return removeNode(cdata);
1443
1444 }
1445
1446 public boolean remove(Comment comment) {
1447
1448 return removeNode(comment);
1449
1450 }
1451
1452 public boolean remove(Element element) {
1453
1454 return removeNode(element);
1455
1456 }
1457
1458 public boolean remove(Entity entity) {
1459
1460 return removeNode(entity);
1461
1462 }
1463
1464 public boolean remove(Namespace namespace) {
1465
1466 return removeNode(namespace);
1467
1468 }
1469
1470 public boolean remove(ProcessingInstruction pi) {
1471
1472 return removeNode(pi);
1473
1474 }
1475
1476 public boolean remove(Text text) {
1477
1478 return removeNode(text);
1479
1480 }
1481
1482
1483
1484
1485
1486 public boolean hasMixedContent() {
1487
1488 List content = contentList();
1489
1490 if (content == null || content.isEmpty() || content.size() < 2) {
1491
1492 return false;
1493
1494 }
1495
1496 Class prevClass = null;
1497
1498 for (Iterator iter = content.iterator(); iter.hasNext();) {
1499
1500 Object object = iter.next();
1501
1502 Class newClass = object.getClass();
1503
1504 if (newClass != prevClass) {
1505
1506 if (prevClass != null) {
1507
1508 return true;
1509
1510 }
1511
1512 prevClass = newClass;
1513
1514 }
1515
1516 }
1517
1518 return false;
1519
1520 }
1521
1522 public boolean isTextOnly() {
1523
1524 List content = contentList();
1525
1526 if (content == null || content.isEmpty()) {
1527
1528 return true;
1529
1530 }
1531
1532 for (Iterator iter = content.iterator(); iter.hasNext();) {
1533
1534 Object object = iter.next();
1535
1536 if (!(object instanceof CharacterData) && !(object instanceof String)) {
1537
1538 return false;
1539
1540 }
1541
1542 }
1543
1544 return true;
1545
1546 }
1547
1548 public void setText(String text) {
1549
1550
1551 List allContent = contentList();
1552 if (allContent != null) {
1553 Iterator it = allContent.iterator();
1554 while (it.hasNext()) {
1555 Node node = (Node) it.next();
1556 switch (node.getNodeType()) {
1557 case CDATA_SECTION_NODE:
1558
1559 case ENTITY_REFERENCE_NODE:
1560 case TEXT_NODE:
1561 it.remove();
1562 }
1563 }
1564 }
1565
1566 addText(text);
1567
1568 }
1569
1570 public String getStringValue() {
1571
1572 List list = contentList();
1573
1574 int size = list.size();
1575
1576 if (size > 0) {
1577
1578 if (size == 1) {
1579
1580
1581
1582 return getContentAsStringValue(list.get(0));
1583
1584 }
1585
1586 else {
1587
1588 StringBuffer buffer = new StringBuffer();
1589
1590 for (int i = 0; i < size; i++) {
1591
1592 Object node = list.get(i);
1593
1594 String string = getContentAsStringValue(node);
1595
1596 if (string.length() > 0) {
1597
1598 if (USE_STRINGVALUE_SEPARATOR) {
1599
1600 if (buffer.length() > 0) {
1601
1602 buffer.append(' ');
1603
1604 }
1605
1606 }
1607
1608 buffer.append(string);
1609
1610 }
1611
1612 }
1613
1614 return buffer.toString();
1615
1616 }
1617
1618 }
1619
1620 return "";
1621
1622 }
1623
1624 /***
1625 * Puts all <code>Text</code> nodes in the full depth of the sub-tree
1626 * underneath this <code>Node</code>, including attribute nodes, into a
1627 * "normal" form where only structure (e.g., elements, comments,
1628 * processing instructions, CDATA sections, and entity references)
1629 * separates <code>Text</code> nodes, i.e., there are neither adjacent
1630 * <code>Text</code> nodes nor empty <code>Text</code> nodes. This can
1631 * be used to ensure that the DOM view of a document is the same as if
1632 * it were saved and re-loaded, and is useful when operations (such as
1633 * XPointer lookups) that depend on a particular document tree
1634 * structure are to be used.In cases where the document contains
1635 * <code>CDATASections</code>, the normalize operation alone may not be
1636 * sufficient, since XPointers do not differentiate between
1637 * <code>Text</code> nodes and <code>CDATASection</code> nodes.
1638 * @since DOM Level 2
1639 */
1640
1641 public void normalize() {
1642
1643 List content = contentList();
1644
1645 Text previousText = null;
1646
1647 int i = 0;
1648
1649 while (i < content.size()) {
1650
1651 Node node = (Node) content.get(i);
1652
1653 if (node instanceof Text) {
1654
1655 Text text = (Text) node;
1656
1657 if (previousText != null) {
1658
1659 previousText.appendText(text.getText());
1660
1661 remove(text);
1662
1663 }
1664
1665 else {
1666
1667 String value = text.getText();
1668
1669
1670
1671
1672
1673 if (value == null || value.length() <= 0) {
1674
1675 remove(text);
1676
1677 }
1678
1679 else {
1680
1681 previousText = text;
1682
1683 i++;
1684
1685 }
1686
1687 }
1688
1689 }
1690
1691 else {
1692
1693 if (node instanceof Element) {
1694
1695 Element element = (Element) node;
1696
1697 element.normalize();
1698
1699 }
1700
1701 previousText = null;
1702
1703 i++;
1704
1705 }
1706
1707 }
1708
1709 }
1710
1711 public String elementText(String name) {
1712
1713 Element element = element(name);
1714
1715 return (element != null) ? element.getText() : null;
1716
1717 }
1718
1719 public String elementText(QName qName) {
1720
1721 Element element = element(qName);
1722
1723 return (element != null) ? element.getText() : null;
1724
1725 }
1726
1727 public String elementTextTrim(String name) {
1728
1729 Element element = element(name);
1730
1731 return (element != null) ? element.getTextTrim() : null;
1732
1733 }
1734
1735 public String elementTextTrim(QName qName) {
1736
1737 Element element = element(qName);
1738
1739 return (element != null) ? element.getTextTrim() : null;
1740
1741 }
1742
1743
1744
1745
1746
1747 public void appendAttributes(Element element) {
1748
1749 for (int i = 0, size = element.attributeCount(); i < size; i++) {
1750
1751 Attribute attribute = element.attribute(i);
1752
1753 if (attribute.supportsParent()) {
1754
1755 addAttribute(attribute.getQName(), attribute.getValue());
1756
1757 }
1758
1759 else {
1760
1761 add(attribute);
1762
1763 }
1764
1765 }
1766
1767 }
1768
1769 /*** <p>This returns a deep clone of this element.
1770 * The new element is detached from its parent, and getParent() on the
1771 * clone will return null.</p>
1772 *
1773 * @return the clone of this element
1774 */
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785 public Element createCopy() {
1786
1787 Element clone = createElement(getQName());
1788
1789 clone.appendAttributes(this);
1790
1791 clone.appendContent(this);
1792
1793 return clone;
1794
1795 }
1796
1797 public Element createCopy(String name) {
1798
1799 Element clone = createElement(name);
1800
1801 clone.appendAttributes(this);
1802
1803 clone.appendContent(this);
1804
1805 return clone;
1806
1807 }
1808
1809 public Element createCopy(QName qName) {
1810
1811 Element clone = createElement(qName);
1812
1813 clone.appendAttributes(this);
1814
1815 clone.appendContent(this);
1816
1817 return clone;
1818
1819 }
1820
1821 public QName getQName(String qualifiedName) {
1822
1823 String prefix = "";
1824
1825 String localName = qualifiedName;
1826
1827 int index = qualifiedName.indexOf(":");
1828
1829 if (index > 0) {
1830
1831 prefix = qualifiedName.substring(0, index);
1832
1833 localName = qualifiedName.substring(index + 1);
1834
1835 }
1836
1837 Namespace namespace = getNamespaceForPrefix(prefix);
1838
1839 if (namespace != null) {
1840
1841 return getDocumentFactory().createQName(localName, namespace);
1842
1843 }
1844
1845 else {
1846
1847 return getDocumentFactory().createQName(localName);
1848
1849 }
1850
1851 }
1852
1853 public Namespace getNamespaceForPrefix(String prefix) {
1854
1855 if (prefix == null) {
1856
1857 prefix = "";
1858
1859 }
1860
1861 if (prefix.equals(getNamespacePrefix())) {
1862
1863 return getNamespace();
1864
1865 }
1866
1867 else if (prefix.equals("xml")) {
1868
1869 return Namespace.XML_NAMESPACE;
1870
1871 }
1872
1873 else {
1874
1875 List list = contentList();
1876
1877 int size = list.size();
1878
1879 for (int i = 0; i < size; i++) {
1880
1881 Object object = list.get(i);
1882
1883 if (object instanceof Namespace) {
1884
1885 Namespace namespace = (Namespace) object;
1886
1887 if (prefix.equals(namespace.getPrefix())) {
1888
1889 return namespace;
1890
1891 }
1892
1893 }
1894
1895 }
1896
1897 }
1898
1899 Element parent = getParent();
1900
1901 if (parent != null) {
1902
1903 Namespace answer = parent.getNamespaceForPrefix(prefix);
1904
1905 if (answer != null) {
1906
1907 return answer;
1908
1909 }
1910
1911 }
1912
1913 if (prefix == null || prefix.length() <= 0) {
1914
1915 return Namespace.NO_NAMESPACE;
1916
1917 }
1918
1919 return null;
1920
1921 }
1922
1923 public Namespace getNamespaceForURI(String uri) {
1924
1925 if (uri == null || uri.length() <= 0) {
1926
1927 return Namespace.NO_NAMESPACE;
1928
1929 }
1930
1931 else if (uri.equals(getNamespaceURI())) {
1932
1933 return getNamespace();
1934
1935 }
1936
1937 else {
1938
1939 List list = contentList();
1940
1941 int size = list.size();
1942
1943 for (int i = 0; i < size; i++) {
1944
1945 Object object = list.get(i);
1946
1947 if (object instanceof Namespace) {
1948
1949 Namespace namespace = (Namespace) object;
1950
1951 if (uri.equals(namespace.getURI())) {
1952
1953 return namespace;
1954
1955 }
1956
1957 }
1958
1959 }
1960
1961 return null;
1962
1963 }
1964
1965 }
1966
1967 public List getNamespacesForURI(String uri) {
1968
1969 BackedList answer = createResultList();
1970
1971
1972
1973
1974
1975
1976
1977 List list = contentList();
1978
1979 int size = list.size();
1980
1981 for (int i = 0; i < size; i++) {
1982
1983 Object object = list.get(i);
1984
1985 if ((object instanceof Namespace)
1986
1987 && ((Namespace) object).getURI().equals(uri)) {
1988
1989 answer.addLocal(object);
1990
1991 }
1992
1993 }
1994
1995 return answer;
1996
1997 }
1998
1999 public List declaredNamespaces() {
2000
2001 BackedList answer = createResultList();
2002
2003
2004
2005
2006
2007
2008
2009 List list = contentList();
2010
2011 int size = list.size();
2012
2013 for (int i = 0; i < size; i++) {
2014
2015 Object object = list.get(i);
2016
2017 if (object instanceof Namespace) {
2018
2019 answer.addLocal(object);
2020
2021 }
2022
2023 }
2024
2025 return answer;
2026
2027 }
2028
2029 public List additionalNamespaces() {
2030
2031 List list = contentList();
2032
2033 int size = list.size();
2034
2035 BackedList answer = createResultList();
2036
2037 for (int i = 0; i < size; i++) {
2038
2039 Object object = list.get(i);
2040
2041 if (object instanceof Namespace) {
2042
2043 Namespace namespace = (Namespace) object;
2044
2045 if (! namespace.equals(getNamespace())) {
2046
2047 answer.addLocal(namespace);
2048 }
2049
2050 }
2051
2052 }
2053
2054 return answer;
2055
2056 }
2057
2058 public List additionalNamespaces(String defaultNamespaceURI) {
2059
2060 List list = contentList();
2061
2062 BackedList answer = createResultList();
2063
2064 int size = list.size();
2065
2066 for (int i = 0; i < size; i++) {
2067
2068 Object object = list.get(i);
2069
2070 if (object instanceof Namespace) {
2071
2072 Namespace namespace = (Namespace) object;
2073
2074 if (!defaultNamespaceURI.equals(namespace.getURI())) {
2075
2076 answer.addLocal(namespace);
2077
2078 }
2079
2080 }
2081
2082 }
2083
2084 return answer;
2085
2086 }
2087
2088
2089
2090
2091
2092 /*** Ensures that the list of attributes has the given size */
2093
2094 public void ensureAttributesCapacity(int minCapacity) {
2095
2096 if (minCapacity > 1) {
2097
2098 List list = attributeList();
2099
2100 if (list instanceof ArrayList) {
2101
2102 ArrayList arrayList = (ArrayList) list;
2103
2104 arrayList.ensureCapacity(minCapacity);
2105
2106 }
2107
2108 }
2109
2110 }
2111
2112
2113
2114
2115
2116 protected Element createElement(String name) {
2117
2118 return getDocumentFactory().createElement(name);
2119
2120 }
2121
2122 protected Element createElement(QName qName) {
2123
2124 return getDocumentFactory().createElement(qName);
2125
2126 }
2127
2128 protected void addNode(Node node) {
2129
2130 if (node.getParent() != null) {
2131
2132
2133
2134 String message =
2135 "The Node already has an existing parent of \""
2136 + node.getParent().getQualifiedName()
2137 + "\"";
2138
2139 throw new IllegalAddException(this, node, message);
2140
2141 }
2142
2143 addNewNode(node);
2144
2145 }
2146
2147 protected void addNode(int index, Node node) {
2148
2149 if (node.getParent() != null) {
2150
2151
2152
2153 String message =
2154 "The Node already has an existing parent of \""
2155 + node.getParent().getQualifiedName()
2156 + "\"";
2157
2158 throw new IllegalAddException(this, node, message);
2159
2160 }
2161
2162 addNewNode(index, node);
2163
2164 }
2165
2166 /*** Like addNode() but does not require a parent check */
2167
2168 protected void addNewNode(Node node) {
2169
2170 contentList().add(node);
2171
2172 childAdded(node);
2173
2174 }
2175
2176 protected void addNewNode(int index, Node node) {
2177
2178 contentList().add(index, node);
2179
2180 childAdded(node);
2181
2182 }
2183
2184 protected boolean removeNode(Node node) {
2185
2186 boolean answer = contentList().remove(node);
2187
2188 if (answer) {
2189
2190 childRemoved(node);
2191
2192 }
2193
2194 return answer;
2195
2196 }
2197
2198 /*** Called when a new child node is added to
2199 * create any parent relationships
2200 */
2201
2202 protected void childAdded(Node node) {
2203
2204 if (node != null) {
2205
2206 node.setParent(this);
2207
2208 }
2209
2210 }
2211
2212 protected void childRemoved(Node node) {
2213
2214 if (node != null) {
2215
2216 node.setParent(null);
2217
2218 node.setDocument(null);
2219
2220 }
2221
2222 }
2223
2224 /*** @return the internal List used to store attributes or
2225 * creates one if one is not available
2226 */
2227
2228 protected abstract List attributeList();
2229
2230 /*** @return the internal List used to store attributes or
2231 * creates one with the specified size if one is not available
2232 */
2233
2234 protected abstract List attributeList(int attributeCount);
2235
2236 protected DocumentFactory getDocumentFactory() {
2237
2238 QName qName = getQName();
2239
2240
2241
2242 if (qName != null) {
2243
2244 DocumentFactory factory = qName.getDocumentFactory();
2245
2246 if (factory != null) {
2247
2248 return factory;
2249
2250 }
2251
2252 }
2253
2254 return DOCUMENT_FACTORY;
2255
2256 }
2257
2258 /*** A Factory Method pattern which creates
2259 * a List implementation used to store attributes
2260 */
2261
2262 protected List createAttributeList() {
2263
2264 return createAttributeList(DEFAULT_CONTENT_LIST_SIZE);
2265
2266 }
2267
2268 /*** A Factory Method pattern which creates
2269 * a List implementation used to store attributes
2270 */
2271
2272 protected List createAttributeList(int size) {
2273
2274 return new ArrayList(size);
2275
2276 }
2277
2278 protected Iterator createSingleIterator(Object result) {
2279
2280 return new SingleIterator(result);
2281
2282 }
2283
2284 }
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329