1
2
3
4
5
6
7
8 package org.dom4j.tree;
9
10 import java.util.ArrayList;
11 import java.util.Iterator;
12 import java.util.List;
13
14 import org.dom4j.Attribute;
15 import org.dom4j.Branch;
16 import org.dom4j.Document;
17 import org.dom4j.DocumentFactory;
18 import org.dom4j.Element;
19 import org.dom4j.IllegalAddException;
20 import org.dom4j.Namespace;
21 import org.dom4j.Node;
22 import org.dom4j.ProcessingInstruction;
23 import org.dom4j.QName;
24
25 /***
26 * <p>
27 * <code>DefaultElement</code> is the default DOM4J default implementation of
28 * an XML element.
29 * </p>
30 *
31 * @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
32 * @version $Revision: 1.59 $
33 */
34 public class DefaultElement extends AbstractElement {
35 /*** The <code>DocumentFactory</code> instance used by default */
36 private static final transient DocumentFactory DOCUMENT_FACTORY =
37 DocumentFactory.getInstance();
38
39 /*** The <code>QName</code> for this element */
40 private QName qname;
41
42 /***
43 * Stores the parent branch of this node which is either a Document if this
44 * element is the root element in a document, or another Element if it is a
45 * child of the root document, or null if it has not been added to a
46 * document yet.
47 */
48 private Branch parentBranch;
49
50 /***
51 * Stores null for no content, a Node for a single content node or a List
52 * for multiple content nodes. The List will be lazily constructed when
53 * required.
54 */
55 private Object content;
56
57 /*** Lazily constructes list of attributes */
58 private Object attributes;
59
60 public DefaultElement(String name) {
61 this.qname = DOCUMENT_FACTORY.createQName(name);
62 }
63
64 public DefaultElement(QName qname) {
65 this.qname = qname;
66 }
67
68 public DefaultElement(QName qname, int attributeCount) {
69 this.qname = qname;
70
71 if (attributeCount > 1) {
72 this.attributes = new ArrayList(attributeCount);
73 }
74 }
75
76 public DefaultElement(String name, Namespace namespace) {
77 this.qname = DOCUMENT_FACTORY.createQName(name, namespace);
78 }
79
80 public Element getParent() {
81 Element result = null;
82
83 if (parentBranch instanceof Element) {
84 result = (Element) parentBranch;
85 }
86
87 return result;
88 }
89
90 public void setParent(Element parent) {
91 if (parentBranch instanceof Element || (parent != null)) {
92 parentBranch = parent;
93 }
94 }
95
96 public Document getDocument() {
97 if (parentBranch instanceof Document) {
98 return (Document) parentBranch;
99 } else if (parentBranch instanceof Element) {
100 Element parent = (Element) parentBranch;
101
102 return parent.getDocument();
103 }
104
105 return null;
106 }
107
108 public void setDocument(Document document) {
109 if (parentBranch instanceof Document || (document != null)) {
110 parentBranch = document;
111 }
112 }
113
114 public boolean supportsParent() {
115 return true;
116 }
117
118 public QName getQName() {
119 return qname;
120 }
121
122 public void setQName(QName name) {
123 this.qname = name;
124 }
125
126 public String getText() {
127 final Object contentShadow = content;
128
129 if (contentShadow instanceof List) {
130 return super.getText();
131 } else {
132 if (contentShadow != null) {
133 return getContentAsText(contentShadow);
134 } else {
135 return "";
136 }
137 }
138 }
139
140 public String getStringValue() {
141 final Object contentShadow = content;
142
143 if (contentShadow instanceof List) {
144 List list = (List) contentShadow;
145
146 int size = list.size();
147
148 if (size > 0) {
149 if (size == 1) {
150
151 return getContentAsStringValue(list.get(0));
152 } else {
153 StringBuffer buffer = new StringBuffer();
154
155 for (int i = 0; i < size; i++) {
156 Object node = list.get(i);
157
158 String string = getContentAsStringValue(node);
159
160 if (string.length() > 0) {
161 if (USE_STRINGVALUE_SEPARATOR) {
162 if (buffer.length() > 0) {
163 buffer.append(' ');
164 }
165 }
166
167 buffer.append(string);
168 }
169 }
170
171 return buffer.toString();
172 }
173 }
174 } else {
175 if (contentShadow != null) {
176 return getContentAsStringValue(contentShadow);
177 }
178 }
179
180 return "";
181 }
182
183 public Object clone() {
184 DefaultElement answer = (DefaultElement) super.clone();
185
186 if (answer != this) {
187 answer.content = null;
188
189 answer.attributes = null;
190
191 answer.appendAttributes(this);
192
193 answer.appendContent(this);
194 }
195
196 return answer;
197 }
198
199 public Namespace getNamespaceForPrefix(String prefix) {
200 if (prefix == null) {
201 prefix = "";
202 }
203
204 if (prefix.equals(getNamespacePrefix())) {
205 return getNamespace();
206 } else if (prefix.equals("xml")) {
207 return Namespace.XML_NAMESPACE;
208 } else {
209 final Object contentShadow = content;
210
211 if (contentShadow instanceof List) {
212 List list = (List) contentShadow;
213
214 int size = list.size();
215
216 for (int i = 0; i < size; i++) {
217 Object object = list.get(i);
218
219 if (object instanceof Namespace) {
220 Namespace namespace = (Namespace) object;
221
222 if (prefix.equals(namespace.getPrefix())) {
223 return namespace;
224 }
225 }
226 }
227 } else if (contentShadow instanceof Namespace) {
228 Namespace namespace = (Namespace) contentShadow;
229
230 if (prefix.equals(namespace.getPrefix())) {
231 return namespace;
232 }
233 }
234 }
235
236 Element parent = getParent();
237
238 if (parent != null) {
239 Namespace answer = parent.getNamespaceForPrefix(prefix);
240
241 if (answer != null) {
242 return answer;
243 }
244 }
245
246 if ((prefix == null) || (prefix.length() <= 0)) {
247 return Namespace.NO_NAMESPACE;
248 }
249
250 return null;
251 }
252
253 public Namespace getNamespaceForURI(String uri) {
254 if ((uri == null) || (uri.length() <= 0)) {
255 return Namespace.NO_NAMESPACE;
256 } else if (uri.equals(getNamespaceURI())) {
257 return getNamespace();
258 } else {
259 final Object contentShadow = content;
260
261 if (contentShadow instanceof List) {
262 List list = (List) contentShadow;
263
264 int size = list.size();
265
266 for (int i = 0; i < size; i++) {
267 Object object = list.get(i);
268
269 if (object instanceof Namespace) {
270 Namespace namespace = (Namespace) object;
271
272 if (uri.equals(namespace.getURI())) {
273 return namespace;
274 }
275 }
276 }
277 } else if (contentShadow instanceof Namespace) {
278 Namespace namespace = (Namespace) contentShadow;
279
280 if (uri.equals(namespace.getURI())) {
281 return namespace;
282 }
283 }
284
285 Element parent = getParent();
286
287 if (parent != null) {
288 return parent.getNamespaceForURI(uri);
289 }
290
291 return null;
292 }
293 }
294
295 public List declaredNamespaces() {
296 BackedList answer = createResultList();
297
298
299
300
301
302
303 final Object contentShadow = content;
304
305 if (contentShadow instanceof List) {
306 List list = (List) contentShadow;
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 Namespace) {
314 answer.addLocal(object);
315 }
316 }
317 } else {
318 if (contentShadow instanceof Namespace) {
319 answer.addLocal(contentShadow);
320 }
321 }
322
323 return answer;
324 }
325
326 public List additionalNamespaces() {
327 final Object contentShadow = content;
328
329 if (contentShadow instanceof List) {
330 List list = (List) contentShadow;
331
332 int size = list.size();
333
334 BackedList answer = createResultList();
335
336 for (int i = 0; i < size; i++) {
337 Object object = list.get(i);
338
339 if (object instanceof Namespace) {
340 Namespace namespace = (Namespace) object;
341
342 if (!namespace.equals(getNamespace())) {
343 answer.addLocal(namespace);
344 }
345 }
346 }
347
348 return answer;
349 } else {
350 if (contentShadow instanceof Namespace) {
351 Namespace namespace = (Namespace) contentShadow;
352
353 if (namespace.equals(getNamespace())) {
354 return createEmptyList();
355 }
356
357 return createSingleResultList(namespace);
358 } else {
359 return createEmptyList();
360 }
361 }
362 }
363
364 public List additionalNamespaces(String defaultNamespaceURI) {
365 final Object contentShadow = content;
366
367 if (contentShadow instanceof List) {
368 List list = (List) contentShadow;
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 Namespace) {
378 Namespace namespace = (Namespace) object;
379
380 if (!defaultNamespaceURI.equals(namespace.getURI())) {
381 answer.addLocal(namespace);
382 }
383 }
384 }
385
386 return answer;
387 } else {
388 if (contentShadow instanceof Namespace) {
389 Namespace namespace = (Namespace) contentShadow;
390
391 if (!defaultNamespaceURI.equals(namespace.getURI())) {
392 return createSingleResultList(namespace);
393 }
394 }
395 }
396
397 return createEmptyList();
398 }
399
400
401 public List processingInstructions() {
402 final Object contentShadow = content;
403
404 if (contentShadow instanceof List) {
405 List list = (List) contentShadow;
406
407 BackedList answer = createResultList();
408
409 int size = list.size();
410
411 for (int i = 0; i < size; i++) {
412 Object object = list.get(i);
413
414 if (object instanceof ProcessingInstruction) {
415 answer.addLocal(object);
416 }
417 }
418
419 return answer;
420 } else {
421 if (contentShadow instanceof ProcessingInstruction) {
422 return createSingleResultList(contentShadow);
423 }
424
425 return createEmptyList();
426 }
427 }
428
429 public List processingInstructions(String target) {
430 final Object shadow = content;
431
432 if (shadow instanceof List) {
433 List list = (List) shadow;
434
435 BackedList answer = createResultList();
436
437 int size = list.size();
438
439 for (int i = 0; i < size; i++) {
440 Object object = list.get(i);
441
442 if (object instanceof ProcessingInstruction) {
443 ProcessingInstruction pi = (ProcessingInstruction) object;
444
445 if (target.equals(pi.getName())) {
446 answer.addLocal(pi);
447 }
448 }
449 }
450
451 return answer;
452 } else {
453 if (shadow instanceof ProcessingInstruction) {
454 ProcessingInstruction pi = (ProcessingInstruction) shadow;
455
456 if (target.equals(pi.getName())) {
457 return createSingleResultList(pi);
458 }
459 }
460
461 return createEmptyList();
462 }
463 }
464
465 public ProcessingInstruction processingInstruction(String target) {
466 final Object shadow = content;
467
468 if (shadow instanceof List) {
469 List list = (List) shadow;
470
471 int size = list.size();
472
473 for (int i = 0; i < size; i++) {
474 Object object = list.get(i);
475
476 if (object instanceof ProcessingInstruction) {
477 ProcessingInstruction pi = (ProcessingInstruction) object;
478
479 if (target.equals(pi.getName())) {
480 return pi;
481 }
482 }
483 }
484 } else {
485 if (shadow instanceof ProcessingInstruction) {
486 ProcessingInstruction pi = (ProcessingInstruction) shadow;
487
488 if (target.equals(pi.getName())) {
489 return pi;
490 }
491 }
492 }
493
494 return null;
495 }
496
497 public boolean removeProcessingInstruction(String target) {
498 final Object shadow = content;
499
500 if (shadow instanceof List) {
501 List list = (List) shadow;
502
503 for (Iterator iter = list.iterator(); iter.hasNext();) {
504 Object object = iter.next();
505
506 if (object instanceof ProcessingInstruction) {
507 ProcessingInstruction pi = (ProcessingInstruction) object;
508
509 if (target.equals(pi.getName())) {
510 iter.remove();
511
512 return true;
513 }
514 }
515 }
516 } else {
517 if (shadow instanceof ProcessingInstruction) {
518 ProcessingInstruction pi = (ProcessingInstruction) shadow;
519
520 if (target.equals(pi.getName())) {
521 this.content = null;
522
523 return true;
524 }
525 }
526 }
527
528 return false;
529 }
530
531 public Element element(String name) {
532 final Object contentShadow = content;
533
534 if (contentShadow instanceof List) {
535 List list = (List) contentShadow;
536
537 int size = list.size();
538
539 for (int i = 0; i < size; i++) {
540 Object object = list.get(i);
541
542 if (object instanceof Element) {
543 Element element = (Element) object;
544
545 if (name.equals(element.getName())) {
546 return element;
547 }
548 }
549 }
550 } else {
551 if (contentShadow instanceof Element) {
552 Element element = (Element) contentShadow;
553
554 if (name.equals(element.getName())) {
555 return element;
556 }
557 }
558 }
559
560 return null;
561 }
562
563 public Element element(QName qName) {
564 final Object contentShadow = content;
565
566 if (contentShadow instanceof List) {
567 List list = (List) contentShadow;
568
569 int size = list.size();
570
571 for (int i = 0; i < size; i++) {
572 Object object = list.get(i);
573
574 if (object instanceof Element) {
575 Element element = (Element) object;
576
577 if (qName.equals(element.getQName())) {
578 return element;
579 }
580 }
581 }
582 } else {
583 if (contentShadow instanceof Element) {
584 Element element = (Element) contentShadow;
585
586 if (qName.equals(element.getQName())) {
587 return element;
588 }
589 }
590 }
591
592 return null;
593 }
594
595 public Element element(String name, Namespace namespace) {
596 return element(getDocumentFactory().createQName(name, namespace));
597 }
598
599 public void setContent(List content) {
600 contentRemoved();
601
602 if (content instanceof ContentListFacade) {
603 content = ((ContentListFacade) content).getBackingList();
604 }
605
606 if (content == null) {
607 this.content = null;
608 } else {
609 int size = content.size();
610
611 List newContent = createContentList(size);
612
613 for (int i = 0; i < size; i++) {
614 Object object = content.get(i);
615
616 if (object instanceof Node) {
617 Node node = (Node) object;
618 Element parent = node.getParent();
619
620 if ((parent != null) && (parent != this)) {
621 node = (Node) node.clone();
622 }
623
624 newContent.add(node);
625 childAdded(node);
626 } else if (object != null) {
627 String text = object.toString();
628 Node node = getDocumentFactory().createText(text);
629 newContent.add(node);
630 childAdded(node);
631 }
632 }
633
634 this.content = newContent;
635 }
636 }
637
638 public void clearContent() {
639 if (content != null) {
640 contentRemoved();
641
642 content = null;
643 }
644 }
645
646 public Node node(int index) {
647 if (index >= 0) {
648 final Object contentShadow = content;
649 Object node;
650
651 if (contentShadow instanceof List) {
652 List list = (List) contentShadow;
653
654 if (index >= list.size()) {
655 return null;
656 }
657
658 node = list.get(index);
659 } else {
660 node = (index == 0) ? contentShadow : null;
661 }
662
663 if (node != null) {
664 if (node instanceof Node) {
665 return (Node) node;
666 } else {
667 return new DefaultText(node.toString());
668 }
669 }
670 }
671
672 return null;
673 }
674
675 public int indexOf(Node node) {
676 final Object contentShadow = content;
677
678 if (contentShadow instanceof List) {
679 List list = (List) contentShadow;
680
681 return list.indexOf(node);
682 } else {
683 if ((contentShadow != null) && contentShadow.equals(node)) {
684 return 0;
685 } else {
686 return -1;
687 }
688 }
689 }
690
691 public int nodeCount() {
692 final Object contentShadow = content;
693
694 if (contentShadow instanceof List) {
695 List list = (List) contentShadow;
696
697 return list.size();
698 } else {
699 return (contentShadow != null) ? 1 : 0;
700 }
701 }
702
703 public Iterator nodeIterator() {
704 final Object contentShadow = content;
705
706 if (contentShadow instanceof List) {
707 List list = (List) contentShadow;
708
709 return list.iterator();
710 } else {
711 if (contentShadow != null) {
712 return createSingleIterator(contentShadow);
713 } else {
714 return EMPTY_ITERATOR;
715 }
716 }
717 }
718
719 public List attributes() {
720 return new ContentListFacade(this, attributeList());
721 }
722
723 public void setAttributes(List attributes) {
724 if (attributes instanceof ContentListFacade) {
725 attributes = ((ContentListFacade) attributes).getBackingList();
726 }
727
728 this.attributes = attributes;
729 }
730
731 public Iterator attributeIterator() {
732 final Object attributesShadow = this.attributes;
733
734 if (attributesShadow instanceof List) {
735 List list = (List) attributesShadow;
736
737 return list.iterator();
738 } else if (attributesShadow != null) {
739 return createSingleIterator(attributesShadow);
740 } else {
741 return EMPTY_ITERATOR;
742 }
743 }
744
745 public Attribute attribute(int index) {
746 final Object attributesShadow = this.attributes;
747
748 if (attributesShadow instanceof List) {
749 List list = (List) attributesShadow;
750
751 return (Attribute) list.get(index);
752 } else if ((attributesShadow != null) && (index == 0)) {
753 return (Attribute) attributesShadow;
754 } else {
755 return null;
756 }
757 }
758
759 public int attributeCount() {
760 final Object attributesShadow = this.attributes;
761
762 if (attributesShadow instanceof List) {
763 List list = (List) attributesShadow;
764
765 return list.size();
766 } else {
767 return (attributesShadow != null) ? 1 : 0;
768 }
769 }
770
771 public Attribute attribute(String name) {
772 final Object attributesShadow = this.attributes;
773
774 if (attributesShadow instanceof List) {
775 List list = (List) attributesShadow;
776
777 int size = list.size();
778
779 for (int i = 0; i < size; i++) {
780 Attribute attribute = (Attribute) list.get(i);
781
782 if (name.equals(attribute.getName())) {
783 return attribute;
784 }
785 }
786 } else if (attributesShadow != null) {
787 Attribute attribute = (Attribute) attributesShadow;
788
789 if (name.equals(attribute.getName())) {
790 return attribute;
791 }
792 }
793
794 return null;
795 }
796
797 public Attribute attribute(QName qName) {
798 final Object attributesShadow = this.attributes;
799
800 if (attributesShadow instanceof List) {
801 List list = (List) attributesShadow;
802
803 int size = list.size();
804
805 for (int i = 0; i < size; i++) {
806 Attribute attribute = (Attribute) list.get(i);
807
808 if (qName.equals(attribute.getQName())) {
809 return attribute;
810 }
811 }
812 } else if (attributesShadow != null) {
813 Attribute attribute = (Attribute) attributesShadow;
814
815 if (qName.equals(attribute.getQName())) {
816 return attribute;
817 }
818 }
819
820 return null;
821 }
822
823 public Attribute attribute(String name, Namespace namespace) {
824 return attribute(getDocumentFactory().createQName(name, namespace));
825 }
826
827 public void add(Attribute attribute) {
828 if (attribute.getParent() != null) {
829 String message = "The Attribute already has an existing parent \""
830 + attribute.getParent().getQualifiedName() + "\"";
831
832 throw new IllegalAddException(this, attribute, message);
833 }
834
835 if (attribute.getValue() == null) {
836
837
838
839 Attribute oldAttribute = attribute(attribute.getQName());
840
841 if (oldAttribute != null) {
842 remove(oldAttribute);
843 }
844 } else {
845 if (attributes == null) {
846 attributes = attribute;
847 } else {
848 attributeList().add(attribute);
849 }
850
851 childAdded(attribute);
852 }
853 }
854
855 public boolean remove(Attribute attribute) {
856 boolean answer = false;
857 final Object attributesShadow = this.attributes;
858
859 if (attributesShadow instanceof List) {
860 List list = (List) attributesShadow;
861
862 answer = list.remove(attribute);
863
864 if (!answer) {
865
866 Attribute copy = attribute(attribute.getQName());
867
868 if (copy != null) {
869 list.remove(copy);
870
871 answer = true;
872 }
873 }
874 } else if (attributesShadow != null) {
875 if (attribute.equals(attributesShadow)) {
876 this.attributes = null;
877
878 answer = true;
879 } else {
880
881 Attribute other = (Attribute) attributesShadow;
882
883 if (attribute.getQName().equals(other.getQName())) {
884 attributes = null;
885
886 answer = true;
887 }
888 }
889 }
890
891 if (answer) {
892 childRemoved(attribute);
893 }
894
895 return answer;
896 }
897
898
899
900 protected void addNewNode(Node node) {
901 final Object contentShadow = content;
902
903 if (contentShadow == null) {
904 this.content = node;
905 } else {
906 if (contentShadow instanceof List) {
907 List list = (List) contentShadow;
908
909 list.add(node);
910 } else {
911 List list = createContentList();
912
913 list.add(contentShadow);
914
915 list.add(node);
916
917 this.content = list;
918 }
919 }
920
921 childAdded(node);
922 }
923
924 protected boolean removeNode(Node node) {
925 boolean answer = false;
926 final Object contentShadow = content;
927
928 if (contentShadow != null) {
929 if (contentShadow == node) {
930 this.content = null;
931
932 answer = true;
933 } else if (contentShadow instanceof List) {
934 List list = (List) contentShadow;
935
936 answer = list.remove(node);
937 }
938 }
939
940 if (answer) {
941 childRemoved(node);
942 }
943
944 return answer;
945 }
946
947 protected List contentList() {
948 final Object contentShadow = content;
949
950 if (contentShadow instanceof List) {
951 return (List) contentShadow;
952 } else {
953 List list = createContentList();
954
955 if (contentShadow != null) {
956 list.add(contentShadow);
957 }
958
959 this.content = list;
960
961 return list;
962 }
963 }
964
965 protected List attributeList() {
966 final Object attributesShadow = this.attributes;
967
968 if (attributesShadow instanceof List) {
969 return (List) attributesShadow;
970 } else if (attributesShadow != null) {
971 List list = createAttributeList();
972
973 list.add(attributesShadow);
974
975 this.attributes = list;
976
977 return list;
978 } else {
979 List list = createAttributeList();
980
981 this.attributes = list;
982
983 return list;
984 }
985 }
986
987 protected List attributeList(int size) {
988 final Object attributesShadow = this.attributes;
989
990 if (attributesShadow instanceof List) {
991 return (List) attributesShadow;
992 } else if (attributesShadow != null) {
993 List list = createAttributeList(size);
994
995 list.add(attributesShadow);
996
997 this.attributes = list;
998
999 return list;
1000 } else {
1001 List list = createAttributeList(size);
1002
1003 this.attributes = list;
1004
1005 return list;
1006 }
1007 }
1008
1009 protected void setAttributeList(List attributeList) {
1010 this.attributes = attributeList;
1011 }
1012
1013 protected DocumentFactory getDocumentFactory() {
1014 DocumentFactory factory = qname.getDocumentFactory();
1015
1016 return (factory != null) ? factory : DOCUMENT_FACTORY;
1017 }
1018 }
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055