comparison NGSrich_0.5.5/src/org/jdom/Document.java @ 0:89ad0a9cca52 default tip

Uploaded
author pfrommolt
date Mon, 21 Nov 2011 08:12:19 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:89ad0a9cca52
1 /*--
2
3 $Id: Document.java,v 1.85 2007/11/10 05:28:58 jhunter Exp $
4
5 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions, and the following disclaimer.
14
15 2. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions, and the disclaimer that follows
17 these conditions in the documentation and/or other materials
18 provided with the distribution.
19
20 3. The name "JDOM" must not be used to endorse or promote products
21 derived from this software without prior written permission. For
22 written permission, please contact <request_AT_jdom_DOT_org>.
23
24 4. Products derived from this software may not be called "JDOM", nor
25 may "JDOM" appear in their name, without prior written permission
26 from the JDOM Project Management <request_AT_jdom_DOT_org>.
27
28 In addition, we request (but do not require) that you include in the
29 end-user documentation provided with the redistribution and/or in the
30 software itself an acknowledgement equivalent to the following:
31 "This product includes software developed by the
32 JDOM Project (http://www.jdom.org/)."
33 Alternatively, the acknowledgment may be graphical using the logos
34 available at http://www.jdom.org/images/logos.
35
36 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
40 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 SUCH DAMAGE.
48
49 This software consists of voluntary contributions made by many
50 individuals on behalf of the JDOM Project and was originally
51 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
52 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
53 on the JDOM Project, please see <http://www.jdom.org/>.
54
55 */
56
57 package org.jdom;
58
59 import java.util.*;
60 import org.jdom.filter.*;
61
62 /**
63 * An XML document. Methods allow access to the root element as well as the
64 * {@link DocType} and other document-level information.
65 *
66 * @version $Revision: 1.85 $, $Date: 2007/11/10 05:28:58 $
67 * @author Brett McLaughlin
68 * @author Jason Hunter
69 * @author Jools Enticknap
70 * @author Bradley S. Huffman
71 */
72 public class Document implements Parent {
73
74 private static final String CVS_ID =
75 "@(#) $RCSfile: Document.java,v $ $Revision: 1.85 $ $Date: 2007/11/10 05:28:58 $ $Name: jdom_1_1_1 $";
76
77 /**
78 * This document's content including comments, PIs, a possible
79 * DocType, and a root element.
80 * Subclassers have to track content using their own
81 * mechanism.
82 */
83 ContentList content = new ContentList(this);
84
85 /**
86 * See http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#baseURIs-Considerations
87 */
88 protected String baseURI = null;
89
90 // Supports the setProperty/getProperty calls
91 private HashMap propertyMap = null;
92
93 /**
94 * Creates a new empty document. A document must have a root element,
95 * so this document will not be well-formed and accessor methods will
96 * throw an IllegalStateException if this document is accessed before a
97 * root element is added. This method is most useful for build tools.
98 */
99 public Document() {}
100
101 /**
102 * This will create a new <code>Document</code>,
103 * with the supplied <code>{@link Element}</code>
104 * as the root element, the supplied
105 * <code>{@link DocType}</code> declaration, and the specified
106 * base URI.
107 *
108 * @param rootElement <code>Element</code> for document root.
109 * @param docType <code>DocType</code> declaration.
110 * @param baseURI the URI from which this doucment was loaded.
111 * @throws IllegalAddException if the given docType object
112 * is already attached to a document or the given
113 * rootElement already has a parent
114 */
115 public Document(Element rootElement, DocType docType, String baseURI) {
116 if (rootElement != null) {
117 setRootElement(rootElement);
118 }
119 if (docType != null) {
120 setDocType(docType);
121 }
122 if (baseURI != null) {
123 setBaseURI(baseURI);
124 }
125 }
126
127 /**
128 * This will create a new <code>Document</code>,
129 * with the supplied <code>{@link Element}</code>
130 * as the root element and the supplied
131 * <code>{@link DocType}</code> declaration.
132 *
133 * @param rootElement <code>Element</code> for document root.
134 * @param docType <code>DocType</code> declaration.
135 * @throws IllegalAddException if the given DocType object
136 * is already attached to a document or the given
137 * rootElement already has a parent
138 */
139 public Document(Element rootElement, DocType docType) {
140 this(rootElement, docType, null);
141 }
142
143 /**
144 * This will create a new <code>Document</code>,
145 * with the supplied <code>{@link Element}</code>
146 * as the root element, and no <code>{@link DocType}</code>
147 * declaration.
148 *
149 * @param rootElement <code>Element</code> for document root
150 * @throws IllegalAddException if the given rootElement already has
151 * a parent.
152 */
153 public Document(Element rootElement) {
154 this(rootElement, null, null);
155 }
156
157 /**
158 * This will create a new <code>Document</code>,
159 * with the supplied list of content, and a
160 * <code>{@link DocType}</code> declaration only if the content
161 * contains a DocType instance. A null list is treated the
162 * same as the no-arg constructor.
163 *
164 * @param content <code>List</code> of starter content
165 * @throws IllegalAddException if the List contains more than
166 * one Element or objects of illegal types.
167 */
168 public Document(List content) {
169 setContent(content);
170 }
171
172 public int getContentSize() {
173 return content.size();
174 }
175
176 public int indexOf(Content child) {
177 return content.indexOf(child);
178 }
179
180 // /**
181 // * Starting at the given index (inclusive), return the index of
182 // * the first child matching the supplied filter, or -1
183 // * if none is found.
184 // *
185 // * @return index of child, or -1 if none found.
186 // */
187 // private int indexOf(int start, Filter filter) {
188 // int size = getContentSize();
189 // for (int i = start; i < size; i++) {
190 // if (filter.matches(getContent(i))) {
191 // return i;
192 // }
193 // }
194 // return -1;
195 // }
196
197 /**
198 * This will return <code>true</code> if this document has a
199 * root element, <code>false</code> otherwise.
200 *
201 * @return <code>true</code> if this document has a root element,
202 * <code>false</code> otherwise.
203 */
204 public boolean hasRootElement() {
205 return (content.indexOfFirstElement() < 0) ? false : true;
206 }
207
208 /**
209 * This will return the root <code>Element</code>
210 * for this <code>Document</code>
211 *
212 * @return <code>Element</code> - the document's root element
213 * @throws IllegalStateException if the root element hasn't been set
214 */
215 public Element getRootElement() {
216 int index = content.indexOfFirstElement();
217 if (index < 0) {
218 throw new IllegalStateException("Root element not set");
219 }
220 return (Element) content.get(index);
221 }
222
223 /**
224 * This sets the root <code>{@link Element}</code> for the
225 * <code>Document</code>. If the document already has a root
226 * element, it is replaced.
227 *
228 * @param rootElement <code>Element</code> to be new root.
229 * @return <code>Document</code> - modified Document.
230 * @throws IllegalAddException if the given rootElement already has
231 * a parent.
232 */
233 public Document setRootElement(Element rootElement) {
234 int index = content.indexOfFirstElement();
235 if (index < 0) {
236 content.add(rootElement);
237 }
238 else {
239 content.set(index, rootElement);
240 }
241 return this;
242 }
243
244 /**
245 * Detach the root <code>{@link Element}</code> from this document.
246 *
247 * @return removed root <code>Element</code>
248 */
249 public Element detachRootElement() {
250 int index = content.indexOfFirstElement();
251 if (index < 0)
252 return null;
253 return (Element) removeContent(index);
254 }
255
256 /**
257 * This will return the <code>{@link DocType}</code>
258 * declaration for this <code>Document</code>, or
259 * <code>null</code> if none exists.
260 *
261 * @return <code>DocType</code> - the DOCTYPE declaration.
262 */
263 public DocType getDocType() {
264 int index = content.indexOfDocType();
265 if (index < 0) {
266 return null;
267 }
268 else {
269 return (DocType) content.get(index);
270 }
271 }
272
273 /**
274 * This will set the <code>{@link DocType}</code>
275 * declaration for this <code>Document</code>. Note
276 * that a DocType can only be attached to one Document.
277 * Attempting to set the DocType to a DocType object
278 * that already belongs to a Document will result in an
279 * IllegalAddException being thrown.
280 *
281 * @param docType <code>DocType</code> declaration.
282 * @return object on which the method was invoked
283 * @throws IllegalAddException if the given docType is
284 * already attached to a Document.
285 */
286 public Document setDocType(DocType docType) {
287 if (docType == null) {
288 // Remove any existing doctype
289 int docTypeIndex = content.indexOfDocType();
290 if (docTypeIndex >= 0) content.remove(docTypeIndex);
291 return this;
292 }
293
294 if (docType.getParent() != null) {
295 throw new IllegalAddException(docType,
296 "The DocType already is attached to a document");
297 }
298
299 // Add DocType to head if new, replace old otherwise
300 int docTypeIndex = content.indexOfDocType();
301 if (docTypeIndex < 0) {
302 content.add(0, docType);
303 }
304 else {
305 content.set(docTypeIndex, docType);
306 }
307
308 return this;
309 }
310
311 /**
312 * Appends the child to the end of the content list.
313 *
314 * @param child child to append to end of content list
315 * @return the document on which the method was called
316 * @throws IllegalAddException if the given child already has a parent.
317 */
318 public Document addContent(Content child) {
319 content.add(child);
320 return this;
321 }
322
323 /**
324 * Appends all children in the given collection to the end of
325 * the content list. In event of an exception during add the
326 * original content will be unchanged and the objects in the supplied
327 * collection will be unaltered.
328 *
329 * @param c collection to append
330 * @return the document on which the method was called
331 * @throws IllegalAddException if any item in the collection
332 * already has a parent or is of an illegal type.
333 */
334 public Document addContent(Collection c) {
335 content.addAll(c);
336 return this;
337 }
338
339 /**
340 * Inserts the child into the content list at the given index.
341 *
342 * @param index location for adding the collection
343 * @param child child to insert
344 * @return the parent on which the method was called
345 * @throws IndexOutOfBoundsException if index is negative or beyond
346 * the current number of children
347 * @throws IllegalAddException if the given child already has a parent.
348 */
349 public Document addContent(int index, Content child) {
350 content.add(index, child);
351 return this;
352 }
353
354 /**
355 * Inserts the content in a collection into the content list
356 * at the given index. In event of an exception the original content
357 * will be unchanged and the objects in the supplied collection will be
358 * unaltered.
359 *
360 * @param index location for adding the collection
361 * @param c collection to insert
362 * @return the parent on which the method was called
363 * @throws IndexOutOfBoundsException if index is negative or beyond
364 * the current number of children
365 * @throws IllegalAddException if any item in the collection
366 * already has a parent or is of an illegal type.
367 */
368 public Document addContent(int index, Collection c) {
369 content.addAll(index, c);
370 return this;
371 }
372
373 public List cloneContent() {
374 int size = getContentSize();
375 List list = new ArrayList(size);
376 for (int i = 0; i < size; i++) {
377 Content child = getContent(i);
378 list.add(child.clone());
379 }
380 return list;
381 }
382
383 public Content getContent(int index) {
384 return (Content) content.get(index);
385 }
386
387 // public Content getChild(Filter filter) {
388 // int i = indexOf(0, filter);
389 // return (i < 0) ? null : getContent(i);
390 // }
391
392 /**
393 * This will return all content for the <code>Document</code>.
394 * The returned list is "live" in document order and changes to it
395 * affect the document's actual content.
396 *
397 * <p>
398 * Sequential traversal through the List is best done with a Iterator
399 * since the underlying implement of List.size() may require walking the
400 * entire list.
401 * </p>
402 *
403 * @return <code>List</code> - all Document content
404 * @throws IllegalStateException if the root element hasn't been set
405 */
406 public List getContent() {
407 if (!hasRootElement())
408 throw new IllegalStateException("Root element not set");
409 return content;
410 }
411
412 /**
413 * Return a filtered view of this <code>Document</code>'s content.
414 *
415 * <p>
416 * Sequential traversal through the List is best done with a Iterator
417 * since the underlying implement of List.size() may require walking the
418 * entire list.
419 * </p>
420 *
421 * @param filter <code>Filter</code> to apply
422 * @return <code>List</code> - filtered Document content
423 * @throws IllegalStateException if the root element hasn't been set
424 */
425 public List getContent(Filter filter) {
426 if (!hasRootElement())
427 throw new IllegalStateException("Root element not set");
428 return content.getView(filter);
429 }
430
431 /**
432 * Removes all child content from this parent.
433 *
434 * @return list of the old children detached from this parent
435 */
436 public List removeContent() {
437 List old = new ArrayList(content);
438 content.clear();
439 return old;
440 }
441
442 /**
443 * Remove all child content from this parent matching the supplied filter.
444 *
445 * @param filter filter to select which content to remove
446 * @return list of the old children detached from this parent
447 */
448 public List removeContent(Filter filter) {
449 List old = new ArrayList();
450 Iterator itr = content.getView(filter).iterator();
451 while (itr.hasNext()) {
452 Content child = (Content) itr.next();
453 old.add(child);
454 itr.remove();
455 }
456 return old;
457 }
458
459 /**
460 * This sets the content of the <code>Document</code>. The supplied
461 * List should contain only objects of type <code>Element</code>,
462 * <code>Comment</code>, and <code>ProcessingInstruction</code>.
463 *
464 * <p>
465 * When all objects in the supplied List are legal and before the new
466 * content is added, all objects in the old content will have their
467 * parentage set to null (no parent) and the old content list will be
468 * cleared. This has the effect that any active list (previously obtained
469 * with a call to {@link #getContent}) will also
470 * change to reflect the new content. In addition, all objects in the
471 * supplied List will have their parentage set to this document, but the
472 * List itself will not be "live" and further removals and additions will
473 * have no effect on this document content. If the user wants to continue
474 * working with a "live" list, then a call to setContent should be
475 * followed by a call to {@link #getContent} to
476 * obtain a "live" version of the content.
477 * </p>
478 *
479 * <p>
480 * Passing a null or empty List clears the existing content.
481 * </p>
482 *
483 * <p>
484 * In event of an exception the original content will be unchanged and
485 * the objects in the supplied content will be unaltered.
486 * </p>
487 *
488 * @param newContent <code>List</code> of content to set
489 * @return this document modified
490 * @throws IllegalAddException if the List contains objects of
491 * illegal types or with existing parentage.
492 */
493 public Document setContent(Collection newContent) {
494 content.clearAndSet(newContent);
495 return this;
496 }
497
498 /**
499 *
500 * <p>
501 * Sets the effective URI from which this document was loaded,
502 * and against which relative URLs in this document will be resolved.
503 * </p>
504 *
505 * @param uri the base URI of this document
506 */
507 public final void setBaseURI(String uri) {
508 this.baseURI = uri; // XXX We don't check the URI
509 }
510
511 /**
512 * <p>
513 * Returns the URI from which this document was loaded,
514 * or null if this is not known.
515 * </p>
516 *
517 * @return the base URI of this document
518 */
519 public final String getBaseURI() {
520 return baseURI;
521 }
522
523 /*
524 * Replace the current child the given index with the supplied child.
525 * <p>
526 * In event of an exception the original content will be unchanged and
527 * the supplied child will be unaltered.
528 * </p>
529 *
530 * @param index - index of child to replace.
531 * @param child - child to add.
532 * @throws IllegalAddException if the supplied child is already attached
533 * or not legal content for this parent.
534 * @throws IndexOutOfBoundsException if index is negative or greater
535 * than the current number of children.
536 */
537 public Document setContent(int index, Content child) {
538 content.set(index, child);
539 return this;
540 }
541
542 /**
543 * Replace the child at the given index whith the supplied
544 * collection.
545 * <p>
546 * In event of an exception the original content will be unchanged and
547 * the content in the supplied collection will be unaltered.
548 * </p>
549 *
550 * @param index - index of child to replace.
551 * @param collection - collection of content to add.
552 * @return object on which the method was invoked
553 * @throws IllegalAddException if the collection contains objects of
554 * illegal types.
555 * @throws IndexOutOfBoundsException if index is negative or greater
556 * than the current number of children.
557 */
558 public Document setContent(int index, Collection collection) {
559 content.remove(index);
560 content.addAll(index, collection);
561 return this;
562 }
563
564 public boolean removeContent(Content child) {
565 return content.remove(child);
566 }
567
568 public Content removeContent(int index) {
569 return (Content) content.remove(index);
570 }
571
572 /**
573 * Set this document's content to be the supplied child.
574 * <p>
575 * If the supplied child is legal content for a Document and before
576 * it is added, all content in the current content list will
577 * be cleared and all current children will have their parentage set to
578 * null.
579 * <p>
580 * This has the effect that any active list (previously obtained with
581 * a call to one of the {@link #getContent} methods will also change
582 * to reflect the new content. In addition, all content in the supplied
583 * collection will have their parentage set to this Document. If the user
584 * wants to continue working with a <b>"live"</b> list of this Document's
585 * child, then a call to setContent should be followed by a call to one
586 * of the {@link #getContent} methods to obtain a <b>"live"</b>
587 * version of the children.
588 * <p>
589 * Passing a null child clears the existing content.
590 * <p>
591 * In event of an exception the original content will be unchanged and
592 * the supplied child will be unaltered.
593 *
594 * @param child new content to replace existing content
595 * @return the parent on which the method was called
596 * @throws IllegalAddException if the supplied child is already attached
597 * or not legal content for this parent
598 */
599 public Document setContent(Content child) {
600 content.clear();
601 content.add(child);
602 return this;
603 }
604
605 /**
606 * This returns a <code>String</code> representation of the
607 * <code>Document</code>, suitable for debugging. If the XML
608 * representation of the <code>Document</code> is desired,
609 * {@link org.jdom.output.XMLOutputter#outputString(Document)}
610 * should be used.
611 *
612 * @return <code>String</code> - information about the
613 * <code>Document</code>
614 */
615 public String toString() {
616 StringBuffer stringForm = new StringBuffer()
617 .append("[Document: ");
618
619 DocType docType = getDocType();
620 if (docType != null) {
621 stringForm.append(docType.toString())
622 .append(", ");
623 } else {
624 stringForm.append(" No DOCTYPE declaration, ");
625 }
626
627 Element rootElement = getRootElement();
628 if (rootElement != null) {
629 stringForm.append("Root is ")
630 .append(rootElement.toString());
631 } else {
632 stringForm.append(" No root element"); // shouldn't happen
633 }
634
635 stringForm.append("]");
636
637 return stringForm.toString();
638 }
639
640 /**
641 * This tests for equality of this <code>Document</code> to the supplied
642 * <code>Object</code>.
643 *
644 * @param ob <code>Object</code> to compare to
645 * @return <code>boolean</code> whether the <code>Document</code> is
646 * equal to the supplied <code>Object</code>
647 */
648 public final boolean equals(Object ob) {
649 return (ob == this);
650 }
651
652 /**
653 * This returns the hash code for this <code>Document</code>.
654 *
655 * @return <code>int</code> hash code
656 */
657 public final int hashCode() {
658 return super.hashCode();
659 }
660
661 /**
662 * This will return a deep clone of this <code>Document</code>.
663 *
664 * @return <code>Object</code> clone of this <code>Document</code>
665 */
666 public Object clone() {
667 Document doc = null;
668
669 try {
670 doc = (Document) super.clone();
671 } catch (CloneNotSupportedException ce) {
672 // Can't happen
673 }
674
675 // The clone has a reference to this object's content list, so
676 // owerwrite with a empty list
677 doc.content = new ContentList(doc);
678
679 // Add the cloned content to clone
680
681 for (int i = 0; i < content.size(); i++) {
682 Object obj = content.get(i);
683 if (obj instanceof Element) {
684 Element element = (Element)((Element)obj).clone();
685 doc.content.add(element);
686 }
687 else if (obj instanceof Comment) {
688 Comment comment = (Comment)((Comment)obj).clone();
689 doc.content.add(comment);
690 }
691 else if (obj instanceof ProcessingInstruction) {
692 ProcessingInstruction pi = (ProcessingInstruction)
693 ((ProcessingInstruction)obj).clone();
694 doc.content.add(pi);
695 }
696 else if (obj instanceof DocType) {
697 DocType dt = (DocType) ((DocType)obj).clone();
698 doc.content.add(dt);
699 }
700 }
701
702 return doc;
703 }
704
705 /**
706 * Returns an iterator that walks over all descendants in document order.
707 *
708 * @return an iterator to walk descendants
709 */
710 public Iterator getDescendants() {
711 return new DescendantIterator(this);
712 }
713
714 /**
715 * Returns an iterator that walks over all descendants in document order
716 * applying the Filter to return only elements that match the filter rule.
717 * With filters you can match only Elements, only Comments, Elements or
718 * Comments, only Elements with a given name and/or prefix, and so on.
719 *
720 * @param filter filter to select which descendants to see
721 * @return an iterator to walk descendants within a filter
722 */
723 public Iterator getDescendants(Filter filter) {
724 return new FilterIterator(new DescendantIterator(this), filter);
725 }
726
727 public Parent getParent() {
728 return null; // documents never have parents
729 }
730
731
732
733 /**
734 * @see org.jdom.Parent#getDocument()
735 */
736 public Document getDocument() {
737 return this;
738 }
739
740 /**
741 * Assigns an arbitrary object to be associated with this document under
742 * the given "id" string. Null values are permitted. Strings beginning
743 * with "http://www.jdom.org/ are reserved for JDOM use.
744 *
745 * @param id the id of the stored object
746 * @param value the object to store
747 */
748 public void setProperty(String id, Object value) {
749 if (propertyMap == null) {
750 propertyMap = new HashMap();
751 }
752 propertyMap.put(id, value);
753 }
754
755 /**
756 * Returns the object associated with this document under the given "id"
757 * string, or null if there is no binding or if the binding explicitly
758 * stored a null value.
759 *
760 * @param id the id of the stored object to return
761 * @return the object associated with the given id
762 */
763 public Object getProperty(String id) {
764 if (propertyMap == null) return null;
765 return propertyMap.get(id);
766 }
767 }