KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dom4j > tree > AbstractElement


1 /*
2  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3  *
4  * This software is open source.
5  * See the bottom of this file for the licence.
6  */

7
8 package org.dom4j.tree;
9
10 import java.io.IOException JavaDoc;
11 import java.io.StringWriter JavaDoc;
12 import java.io.Writer JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collections JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Map JavaDoc;
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 JavaDoc;
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 JavaDoc EMPTY_LIST = Collections.EMPTY_LIST;
55
56     protected static final Iterator JavaDoc 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 JavaDoc 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 JavaDoc getXPathNameStep() {
100         String JavaDoc uri = getNamespaceURI();
101
102         if ((uri == null) || (uri.length() == 0)) {
103             return getName();
104         }
105
106         String JavaDoc prefix = getNamespacePrefix();
107
108         if ((prefix == null) || (prefix.length() == 0)) {
109             return "*[name()='" + getName() + "']";
110         }
111
112         return getQualifiedName();
113     }
114
115     public String JavaDoc 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 JavaDoc getUniquePath(Element context) {
132         Element parent = getParent();
133
134         if (parent == null) {
135             return "/" + getXPathNameStep();
136         }
137
138         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
139
140         if (parent != context) {
141             buffer.append(parent.getUniquePath(context));
142
143             buffer.append("/");
144         }
145
146         buffer.append(getXPathNameStep());
147
148         List JavaDoc 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 JavaDoc asXML() {
166         try {
167             StringWriter JavaDoc out = new StringWriter JavaDoc();
168             XMLWriter writer = new XMLWriter(out, new OutputFormat());
169
170             writer.write(this);
171             writer.flush();
172
173             return out.toString();
174         } catch (IOException JavaDoc e) {
175             throw new RuntimeException JavaDoc("IOException while generating "
176                     + "textual representation: " + e.getMessage());
177         }
178     }
179
180     public void write(Writer JavaDoc out) throws IOException JavaDoc {
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         // visit attributes
198
for (int i = 0, size = attributeCount(); i < size; i++) {
199             Attribute attribute = attribute(i);
200
201             visitor.visit(attribute);
202         }
203
204         // visit content
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 JavaDoc toString() {
213         String JavaDoc 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     // QName methods
238
// -------------------------------------------------------------------------
239
public Namespace getNamespace() {
240         return getQName().getNamespace();
241     }
242
243     public String JavaDoc getName() {
244         return getQName().getName();
245     }
246
247     public String JavaDoc getNamespacePrefix() {
248         return getQName().getNamespacePrefix();
249     }
250
251     public String JavaDoc getNamespaceURI() {
252         return getQName().getNamespaceURI();
253     }
254
255     public String JavaDoc getQualifiedName() {
256         return getQName().getQualifiedName();
257     }
258
259     public Object JavaDoc getData() {
260         return getText();
261     }
262
263     public void setData(Object JavaDoc data) {
264         // ignore this method
265
}
266
267     // Node methods
268
// -------------------------------------------------------------------------
269
public Node node(int index) {
270         if (index >= 0) {
271             List JavaDoc list = contentList();
272
273             if (index >= list.size()) {
274                 return null;
275             }
276
277             Object JavaDoc 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 JavaDoc nodeIterator() {
300         return contentList().iterator();
301     }
302
303     // Element methods
304
// -------------------------------------------------------------------------
305
public Element element(String JavaDoc name) {
306         List JavaDoc list = contentList();
307
308         int size = list.size();
309
310         for (int i = 0; i < size; i++) {
311             Object JavaDoc 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 JavaDoc list = contentList();
327
328         int size = list.size();
329
330         for (int i = 0; i < size; i++) {
331             Object JavaDoc 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 JavaDoc name, Namespace namespace) {
346         return element(getDocumentFactory().createQName(name, namespace));
347     }
348
349     public List JavaDoc elements() {
350         List JavaDoc list = contentList();
351
352         BackedList answer = createResultList();
353
354         int size = list.size();
355
356         for (int i = 0; i < size; i++) {
357             Object JavaDoc 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 JavaDoc elements(String JavaDoc name) {
368         List JavaDoc list = contentList();
369
370         BackedList answer = createResultList();
371
372         int size = list.size();
373
374         for (int i = 0; i < size; i++) {
375             Object JavaDoc 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 JavaDoc elements(QName qName) {
390         List JavaDoc list = contentList();
391
392         BackedList answer = createResultList();
393
394         int size = list.size();
395
396         for (int i = 0; i < size; i++) {
397             Object JavaDoc 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 JavaDoc elements(String JavaDoc name, Namespace namespace) {
412         return elements(getDocumentFactory().createQName(name, namespace));
413     }
414
415     public Iterator JavaDoc elementIterator() {
416         List JavaDoc list = elements();
417
418         return list.iterator();
419     }
420
421     public Iterator JavaDoc elementIterator(String JavaDoc name) {
422         List JavaDoc list = elements(name);
423
424         return list.iterator();
425     }
426
427     public Iterator JavaDoc elementIterator(QName qName) {
428         List JavaDoc list = elements(qName);
429
430         return list.iterator();
431     }
432
433     public Iterator JavaDoc elementIterator(String JavaDoc name, Namespace ns) {
434         return elementIterator(getDocumentFactory().createQName(name, ns));
435     }
436
437     // Attribute methods
438
// -------------------------------------------------------------------------
439
public List JavaDoc attributes() {
440         return new ContentListFacade(this, attributeList());
441     }
442
443     public Iterator JavaDoc 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 JavaDoc name) {
456         List JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc attributes,
503             NamespaceStack namespaceStack, boolean noNamespaceAttributes) {
504         // now lets add all attribute values
505
int size = attributes.getLength();
506
507         if (size > 0) {
508             DocumentFactory factory = getDocumentFactory();
509
510             if (size == 1) {
511                 // allow lazy construction of the List of Attributes
512
String JavaDoc name = attributes.getQName(0);
513
514                 if (noNamespaceAttributes || !name.startsWith("xmlns")) {
515                     String JavaDoc attributeURI = attributes.getURI(0);
516
517                     String JavaDoc attributeLocalName = attributes.getLocalName(0);
518
519                     String JavaDoc 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 JavaDoc list = attributeList(size);
529
530                 list.clear();
531
532                 for (int i = 0; i < size; i++) {
533                     // optimised to avoid the call to attribute(QName) to
534
// lookup an attribute for a given QName
535
String JavaDoc attributeName = attributes.getQName(i);
536
537                     if (noNamespaceAttributes
538                             || !attributeName.startsWith("xmlns")) {
539                         String JavaDoc attributeURI = attributes.getURI(i);
540
541                         String JavaDoc attributeLocalName = attributes.getLocalName(i);
542
543                         String JavaDoc 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 JavaDoc attributeValue(String JavaDoc 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 JavaDoc 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 JavaDoc attributeValue(String JavaDoc name, String JavaDoc defaultValue) {
582         String JavaDoc answer = attributeValue(name);
583
584         return (answer != null) ? answer : defaultValue;
585     }
586
587     public String JavaDoc attributeValue(QName qName, String JavaDoc defaultValue) {
588         String JavaDoc 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 JavaDoc name, String JavaDoc 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 JavaDoc value) {
622         addAttribute(qName, value);
623     }
624
625     public void add(Attribute attribute) {
626         if (attribute.getParent() != null) {
627             String JavaDoc 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             // try remove a previous attribute with the same
635
// name since adding an attribute with a null value
636
// is equivalent to removing it.
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 JavaDoc list = attributeList();
651
652         boolean answer = list.remove(attribute);
653
654         if (answer) {
655             childRemoved(attribute);
656         } else {
657             // we may have a copy of the attribute
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     // Processing instruction API
671
// -------------------------------------------------------------------------
672
public List JavaDoc processingInstructions() {
673         List JavaDoc list = contentList();
674
675         BackedList answer = createResultList();
676
677         int size = list.size();
678
679         for (int i = 0; i < size; i++) {
680             Object JavaDoc 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 JavaDoc processingInstructions(String JavaDoc target) {
691         List JavaDoc list = contentList();
692
693         BackedList answer = createResultList();
694
695         int size = list.size();
696
697         for (int i = 0; i < size; i++) {
698             Object JavaDoc 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 JavaDoc target) {
713         List JavaDoc list = contentList();
714
715         int size = list.size();
716
717         for (int i = 0; i < size; i++) {
718             Object JavaDoc 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 JavaDoc target) {
733         List JavaDoc list = contentList();
734
735         for (Iterator JavaDoc iter = list.iterator(); iter.hasNext();) {
736             Object JavaDoc 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     // Content Model methods
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 JavaDoc name, String JavaDoc value) {
765         // adding a null value is equivalent to removing the attribute
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 JavaDoc value) {
786         // adding a null value is equivalent to removing the attribute
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 JavaDoc cdata) {
807         CDATA node = getDocumentFactory().createCDATA(cdata);
808
809         addNewNode(node);
810
811         return this;
812     }
813
814     public Element addComment(String JavaDoc comment) {
815         Comment node = getDocumentFactory().createComment(comment);
816
817         addNewNode(node);
818
819         return this;
820     }
821
822     public Element addElement(String JavaDoc name) {
823         DocumentFactory factory = getDocumentFactory();
824
825         int index = name.indexOf(":");
826
827         String JavaDoc prefix = "";
828
829         String JavaDoc 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 JavaDoc name, String JavaDoc text) {
865         Entity node = getDocumentFactory().createEntity(name, text);
866
867         addNewNode(node);
868
869         return this;
870     }
871
872     public Element addNamespace(String JavaDoc prefix, String JavaDoc uri) {
873         Namespace node = getDocumentFactory().createNamespace(prefix, uri);
874
875         addNewNode(node);
876
877         return this;
878     }
879
880     public Element addProcessingInstruction(String JavaDoc target, String JavaDoc data) {
881         ProcessingInstruction node = getDocumentFactory()
882                 .createProcessingInstruction(target, data);
883
884         addNewNode(node);
885
886         return this;
887     }
888
889     public Element addProcessingInstruction(String JavaDoc target, Map JavaDoc data) {
890         ProcessingInstruction node = getDocumentFactory()
891                 .createProcessingInstruction(target, data);
892
893         addNewNode(node);
894
895         return this;
896     }
897
898     public Element addText(String JavaDoc text) {
899         Text node = getDocumentFactory().createText(text);
900
901         addNewNode(node);
902
903         return this;
904     }
905
906     // polymorphic node methods
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              * XXXX: to do! case DOCUMENT_TYPE_NODE: add((DocumentType) node);
946              * break;
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              * case DOCUMENT_TYPE_NODE: return remove((DocumentType) node);
983              */

984             case NAMESPACE_NODE:
985                 return remove((Namespace) node);
986
987             default:
988                 return false;
989         }
990     }
991
992     // typesafe versions using node classes
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    // Helper methods
1050
// -------------------------------------------------------------------------
1051
public boolean hasMixedContent() {
1052        List JavaDoc content = contentList();
1053
1054        if ((content == null) || content.isEmpty() || (content.size() < 2)) {
1055            return false;
1056        }
1057
1058        Class JavaDoc prevClass = null;
1059
1060        for (Iterator JavaDoc iter = content.iterator(); iter.hasNext();) {
1061            Object JavaDoc object = iter.next();
1062
1063            Class JavaDoc 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 JavaDoc content = contentList();
1079
1080        if ((content == null) || content.isEmpty()) {
1081            return true;
1082        }
1083
1084        for (Iterator JavaDoc iter = content.iterator(); iter.hasNext();) {
1085            Object JavaDoc object = iter.next();
1086
1087            if (!(object instanceof CharacterData)
1088                    && !(object instanceof String JavaDoc)) {
1089                return false;
1090            }
1091        }
1092
1093        return true;
1094    }
1095
1096    public void setText(String JavaDoc text) {
1097        /* remove all text nodes */
1098        List JavaDoc allContent = contentList();
1099
1100        if (allContent != null) {
1101            Iterator JavaDoc 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                    // case ENTITY_NODE:
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 JavaDoc getStringValue() {
1124        List JavaDoc list = contentList();
1125
1126        int size = list.size();
1127
1128        if (size > 0) {
1129            if (size == 1) {
1130                // optimised to avoid StringBuffer creation
1131
return getContentAsStringValue(list.get(0));
1132            } else {
1133                StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
1134
1135                for (int i = 0; i < size; i++) {
1136                    Object JavaDoc node = list.get(i);
1137
1138                    String JavaDoc 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 JavaDoc 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 JavaDoc value = text.getText();
1194
1195                    // only remove empty Text nodes, not whitespace nodes
1196
// if ( value == null || value.trim().length() <= 0 ) {
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 JavaDoc elementText(String JavaDoc name) {
1220        Element element = element(name);
1221
1222        return (element != null) ? element.getText() : null;
1223    }
1224
1225    public String JavaDoc elementText(QName qName) {
1226        Element element = element(qName);
1227
1228        return (element != null) ? element.getText() : null;
1229    }
1230
1231    public String JavaDoc elementTextTrim(String JavaDoc name) {
1232        Element element = element(name);
1233
1234        return (element != null) ? element.getTextTrim() : null;
1235    }
1236
1237    public String JavaDoc elementTextTrim(QName qName) {
1238        Element element = element(qName);
1239
1240        return (element != null) ? element.getTextTrim() : null;
1241    }
1242
1243    // add to me content from another element
1244
// analagous to the addAll(collection) methods in Java 2 collections
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     * public Object clone() { Element clone = createElement(getQName());
1268     * clone.appendAttributes(this); clone.appendContent(this); return clone; }
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 JavaDoc 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 JavaDoc qualifiedName) {
1301        String JavaDoc prefix = "";
1302
1303        String JavaDoc 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 JavaDoc 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 JavaDoc list = contentList();
1333
1334            int size = list.size();
1335
1336            for (int i = 0; i < size; i++) {
1337                Object JavaDoc 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 JavaDoc 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 JavaDoc list = contentList();
1373
1374            int size = list.size();
1375
1376            for (int i = 0; i < size; i++) {
1377                Object JavaDoc 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 JavaDoc getNamespacesForURI(String JavaDoc uri) {
1393        BackedList answer = createResultList();
1394
1395        // if (getNamespaceURI().equals(uri)) {
1396
//
1397
// answer.addLocal(getNamespace());
1398
//
1399
// }
1400
List JavaDoc list = contentList();
1401
1402        int size = list.size();
1403
1404        for (int i = 0; i < size; i++) {
1405            Object JavaDoc 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 JavaDoc declaredNamespaces() {
1417        BackedList answer = createResultList();
1418
1419        // if (getNamespaceURI().length() > 0) {
1420
//
1421
// answer.addLocal(getNamespace());
1422
//
1423
// }
1424
//
1425
List JavaDoc list = contentList();
1426
1427        int size = list.size();
1428
1429        for (int i = 0; i < size; i++) {
1430            Object JavaDoc 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 JavaDoc additionalNamespaces() {
1441        List JavaDoc list = contentList();
1442
1443        int size = list.size();
1444
1445        BackedList answer = createResultList();
1446
1447        for (int i = 0; i < size; i++) {
1448            Object JavaDoc 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 JavaDoc additionalNamespaces(String JavaDoc defaultNamespaceURI) {
1463        List JavaDoc list = contentList();
1464
1465        BackedList answer = createResultList();
1466
1467        int size = list.size();
1468
1469        for (int i = 0; i < size; i++) {
1470            Object JavaDoc 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    // Implementation helper methods
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 JavaDoc list = attributeList();
1496
1497            if (list instanceof ArrayList JavaDoc) {
1498                ArrayList JavaDoc arrayList = (ArrayList JavaDoc) list;
1499
1500                arrayList.ensureCapacity(minCapacity);
1501            }
1502        }
1503    }
1504
1505    // Implementation methods
1506
// -------------------------------------------------------------------------
1507
protected Element createElement(String JavaDoc 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            // XXX: could clone here
1518
String JavaDoc 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            // XXX: could clone here
1530
String JavaDoc 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 JavaDoc 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 JavaDoc attributeList(int attributeCount);
1605
1606    protected DocumentFactory getDocumentFactory() {
1607        QName qName = getQName();
1608
1609        // QName might be null as we might not have been constructed yet
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 JavaDoc 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 JavaDoc createAttributeList(int size) {
1641        return new ArrayList JavaDoc(size);
1642    }
1643
1644    protected Iterator JavaDoc createSingleIterator(Object JavaDoc result) {
1645        return new SingleIterator(result);
1646    }
1647}
1648
1649/*
1650 * Redistribution and use of this software and associated documentation
1651 * ("Software"), with or without modification, are permitted provided that the
1652 * following conditions are met:
1653 *
1654 * 1. Redistributions of source code must retain copyright statements and
1655 * notices. Redistributions must also contain a copy of this document.
1656 *
1657 * 2. Redistributions in binary form must reproduce the above copyright notice,
1658 * this list of conditions and the following disclaimer in the documentation
1659 * and/or other materials provided with the distribution.
1660 *
1661 * 3. The name "DOM4J" must not be used to endorse or promote products derived
1662 * from this Software without prior written permission of MetaStuff, Ltd. For
1663 * written permission, please contact dom4j-info@metastuff.com.
1664 *
1665 * 4. Products derived from this Software may not be called "DOM4J" nor may
1666 * "DOM4J" appear in their names without prior written permission of MetaStuff,
1667 * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
1668 *
1669 * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
1670 *
1671 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
1672 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1673 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1674 * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
1675 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1676 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1677 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1678 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1679 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1680 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1681 * POSSIBILITY OF SUCH DAMAGE.
1682 *
1683 * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
1684 */

1685
Popular Tags