Mercurial > repos > pfrommolt > ngsrich
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NGSrich_0.5.5/src/org/jdom/Document.java Mon Nov 21 08:12:19 2011 -0500 @@ -0,0 +1,767 @@ +/*-- + + $Id: Document.java,v 1.85 2007/11/10 05:28:58 jhunter Exp $ + + Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the disclaimer that follows + these conditions in the documentation and/or other materials + provided with the distribution. + + 3. The name "JDOM" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact <request_AT_jdom_DOT_org>. + + 4. Products derived from this software may not be called "JDOM", nor + may "JDOM" appear in their name, without prior written permission + from the JDOM Project Management <request_AT_jdom_DOT_org>. + + In addition, we request (but do not require) that you include in the + end-user documentation provided with the redistribution and/or in the + software itself an acknowledgement equivalent to the following: + "This product includes software developed by the + JDOM Project (http://www.jdom.org/)." + Alternatively, the acknowledgment may be graphical using the logos + available at http://www.jdom.org/images/logos. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + This software consists of voluntary contributions made by many + individuals on behalf of the JDOM Project and was originally + created by Jason Hunter <jhunter_AT_jdom_DOT_org> and + Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information + on the JDOM Project, please see <http://www.jdom.org/>. + + */ + +package org.jdom; + +import java.util.*; +import org.jdom.filter.*; + +/** + * An XML document. Methods allow access to the root element as well as the + * {@link DocType} and other document-level information. + * + * @version $Revision: 1.85 $, $Date: 2007/11/10 05:28:58 $ + * @author Brett McLaughlin + * @author Jason Hunter + * @author Jools Enticknap + * @author Bradley S. Huffman + */ +public class Document implements Parent { + + private static final String CVS_ID = + "@(#) $RCSfile: Document.java,v $ $Revision: 1.85 $ $Date: 2007/11/10 05:28:58 $ $Name: jdom_1_1_1 $"; + + /** + * This document's content including comments, PIs, a possible + * DocType, and a root element. + * Subclassers have to track content using their own + * mechanism. + */ + ContentList content = new ContentList(this); + + /** + * See http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/core.html#baseURIs-Considerations + */ + protected String baseURI = null; + + // Supports the setProperty/getProperty calls + private HashMap propertyMap = null; + + /** + * Creates a new empty document. A document must have a root element, + * so this document will not be well-formed and accessor methods will + * throw an IllegalStateException if this document is accessed before a + * root element is added. This method is most useful for build tools. + */ + public Document() {} + + /** + * This will create a new <code>Document</code>, + * with the supplied <code>{@link Element}</code> + * as the root element, the supplied + * <code>{@link DocType}</code> declaration, and the specified + * base URI. + * + * @param rootElement <code>Element</code> for document root. + * @param docType <code>DocType</code> declaration. + * @param baseURI the URI from which this doucment was loaded. + * @throws IllegalAddException if the given docType object + * is already attached to a document or the given + * rootElement already has a parent + */ + public Document(Element rootElement, DocType docType, String baseURI) { + if (rootElement != null) { + setRootElement(rootElement); + } + if (docType != null) { + setDocType(docType); + } + if (baseURI != null) { + setBaseURI(baseURI); + } + } + + /** + * This will create a new <code>Document</code>, + * with the supplied <code>{@link Element}</code> + * as the root element and the supplied + * <code>{@link DocType}</code> declaration. + * + * @param rootElement <code>Element</code> for document root. + * @param docType <code>DocType</code> declaration. + * @throws IllegalAddException if the given DocType object + * is already attached to a document or the given + * rootElement already has a parent + */ + public Document(Element rootElement, DocType docType) { + this(rootElement, docType, null); + } + + /** + * This will create a new <code>Document</code>, + * with the supplied <code>{@link Element}</code> + * as the root element, and no <code>{@link DocType}</code> + * declaration. + * + * @param rootElement <code>Element</code> for document root + * @throws IllegalAddException if the given rootElement already has + * a parent. + */ + public Document(Element rootElement) { + this(rootElement, null, null); + } + + /** + * This will create a new <code>Document</code>, + * with the supplied list of content, and a + * <code>{@link DocType}</code> declaration only if the content + * contains a DocType instance. A null list is treated the + * same as the no-arg constructor. + * + * @param content <code>List</code> of starter content + * @throws IllegalAddException if the List contains more than + * one Element or objects of illegal types. + */ + public Document(List content) { + setContent(content); + } + + public int getContentSize() { + return content.size(); + } + + public int indexOf(Content child) { + return content.indexOf(child); + } + +// /** +// * Starting at the given index (inclusive), return the index of +// * the first child matching the supplied filter, or -1 +// * if none is found. +// * +// * @return index of child, or -1 if none found. +// */ +// private int indexOf(int start, Filter filter) { +// int size = getContentSize(); +// for (int i = start; i < size; i++) { +// if (filter.matches(getContent(i))) { +// return i; +// } +// } +// return -1; +// } + + /** + * This will return <code>true</code> if this document has a + * root element, <code>false</code> otherwise. + * + * @return <code>true</code> if this document has a root element, + * <code>false</code> otherwise. + */ + public boolean hasRootElement() { + return (content.indexOfFirstElement() < 0) ? false : true; + } + + /** + * This will return the root <code>Element</code> + * for this <code>Document</code> + * + * @return <code>Element</code> - the document's root element + * @throws IllegalStateException if the root element hasn't been set + */ + public Element getRootElement() { + int index = content.indexOfFirstElement(); + if (index < 0) { + throw new IllegalStateException("Root element not set"); + } + return (Element) content.get(index); + } + + /** + * This sets the root <code>{@link Element}</code> for the + * <code>Document</code>. If the document already has a root + * element, it is replaced. + * + * @param rootElement <code>Element</code> to be new root. + * @return <code>Document</code> - modified Document. + * @throws IllegalAddException if the given rootElement already has + * a parent. + */ + public Document setRootElement(Element rootElement) { + int index = content.indexOfFirstElement(); + if (index < 0) { + content.add(rootElement); + } + else { + content.set(index, rootElement); + } + return this; + } + + /** + * Detach the root <code>{@link Element}</code> from this document. + * + * @return removed root <code>Element</code> + */ + public Element detachRootElement() { + int index = content.indexOfFirstElement(); + if (index < 0) + return null; + return (Element) removeContent(index); + } + + /** + * This will return the <code>{@link DocType}</code> + * declaration for this <code>Document</code>, or + * <code>null</code> if none exists. + * + * @return <code>DocType</code> - the DOCTYPE declaration. + */ + public DocType getDocType() { + int index = content.indexOfDocType(); + if (index < 0) { + return null; + } + else { + return (DocType) content.get(index); + } + } + + /** + * This will set the <code>{@link DocType}</code> + * declaration for this <code>Document</code>. Note + * that a DocType can only be attached to one Document. + * Attempting to set the DocType to a DocType object + * that already belongs to a Document will result in an + * IllegalAddException being thrown. + * + * @param docType <code>DocType</code> declaration. + * @return object on which the method was invoked + * @throws IllegalAddException if the given docType is + * already attached to a Document. + */ + public Document setDocType(DocType docType) { + if (docType == null) { + // Remove any existing doctype + int docTypeIndex = content.indexOfDocType(); + if (docTypeIndex >= 0) content.remove(docTypeIndex); + return this; + } + + if (docType.getParent() != null) { + throw new IllegalAddException(docType, + "The DocType already is attached to a document"); + } + + // Add DocType to head if new, replace old otherwise + int docTypeIndex = content.indexOfDocType(); + if (docTypeIndex < 0) { + content.add(0, docType); + } + else { + content.set(docTypeIndex, docType); + } + + return this; + } + + /** + * Appends the child to the end of the content list. + * + * @param child child to append to end of content list + * @return the document on which the method was called + * @throws IllegalAddException if the given child already has a parent. + */ + public Document addContent(Content child) { + content.add(child); + return this; + } + + /** + * Appends all children in the given collection to the end of + * the content list. In event of an exception during add the + * original content will be unchanged and the objects in the supplied + * collection will be unaltered. + * + * @param c collection to append + * @return the document on which the method was called + * @throws IllegalAddException if any item in the collection + * already has a parent or is of an illegal type. + */ + public Document addContent(Collection c) { + content.addAll(c); + return this; + } + + /** + * Inserts the child into the content list at the given index. + * + * @param index location for adding the collection + * @param child child to insert + * @return the parent on which the method was called + * @throws IndexOutOfBoundsException if index is negative or beyond + * the current number of children + * @throws IllegalAddException if the given child already has a parent. + */ + public Document addContent(int index, Content child) { + content.add(index, child); + return this; + } + + /** + * Inserts the content in a collection into the content list + * at the given index. In event of an exception the original content + * will be unchanged and the objects in the supplied collection will be + * unaltered. + * + * @param index location for adding the collection + * @param c collection to insert + * @return the parent on which the method was called + * @throws IndexOutOfBoundsException if index is negative or beyond + * the current number of children + * @throws IllegalAddException if any item in the collection + * already has a parent or is of an illegal type. + */ + public Document addContent(int index, Collection c) { + content.addAll(index, c); + return this; + } + + public List cloneContent() { + int size = getContentSize(); + List list = new ArrayList(size); + for (int i = 0; i < size; i++) { + Content child = getContent(i); + list.add(child.clone()); + } + return list; + } + + public Content getContent(int index) { + return (Content) content.get(index); + } + +// public Content getChild(Filter filter) { +// int i = indexOf(0, filter); +// return (i < 0) ? null : getContent(i); +// } + + /** + * This will return all content for the <code>Document</code>. + * The returned list is "live" in document order and changes to it + * affect the document's actual content. + * + * <p> + * Sequential traversal through the List is best done with a Iterator + * since the underlying implement of List.size() may require walking the + * entire list. + * </p> + * + * @return <code>List</code> - all Document content + * @throws IllegalStateException if the root element hasn't been set + */ + public List getContent() { + if (!hasRootElement()) + throw new IllegalStateException("Root element not set"); + return content; + } + + /** + * Return a filtered view of this <code>Document</code>'s content. + * + * <p> + * Sequential traversal through the List is best done with a Iterator + * since the underlying implement of List.size() may require walking the + * entire list. + * </p> + * + * @param filter <code>Filter</code> to apply + * @return <code>List</code> - filtered Document content + * @throws IllegalStateException if the root element hasn't been set + */ + public List getContent(Filter filter) { + if (!hasRootElement()) + throw new IllegalStateException("Root element not set"); + return content.getView(filter); + } + + /** + * Removes all child content from this parent. + * + * @return list of the old children detached from this parent + */ + public List removeContent() { + List old = new ArrayList(content); + content.clear(); + return old; + } + + /** + * Remove all child content from this parent matching the supplied filter. + * + * @param filter filter to select which content to remove + * @return list of the old children detached from this parent + */ + public List removeContent(Filter filter) { + List old = new ArrayList(); + Iterator itr = content.getView(filter).iterator(); + while (itr.hasNext()) { + Content child = (Content) itr.next(); + old.add(child); + itr.remove(); + } + return old; + } + + /** + * This sets the content of the <code>Document</code>. The supplied + * List should contain only objects of type <code>Element</code>, + * <code>Comment</code>, and <code>ProcessingInstruction</code>. + * + * <p> + * When all objects in the supplied List are legal and before the new + * content is added, all objects in the old content will have their + * parentage set to null (no parent) and the old content list will be + * cleared. This has the effect that any active list (previously obtained + * with a call to {@link #getContent}) will also + * change to reflect the new content. In addition, all objects in the + * supplied List will have their parentage set to this document, but the + * List itself will not be "live" and further removals and additions will + * have no effect on this document content. If the user wants to continue + * working with a "live" list, then a call to setContent should be + * followed by a call to {@link #getContent} to + * obtain a "live" version of the content. + * </p> + * + * <p> + * Passing a null or empty List clears the existing content. + * </p> + * + * <p> + * In event of an exception the original content will be unchanged and + * the objects in the supplied content will be unaltered. + * </p> + * + * @param newContent <code>List</code> of content to set + * @return this document modified + * @throws IllegalAddException if the List contains objects of + * illegal types or with existing parentage. + */ + public Document setContent(Collection newContent) { + content.clearAndSet(newContent); + return this; + } + + /** + * + * <p> + * Sets the effective URI from which this document was loaded, + * and against which relative URLs in this document will be resolved. + * </p> + * + * @param uri the base URI of this document + */ + public final void setBaseURI(String uri) { + this.baseURI = uri; // XXX We don't check the URI + } + + /** + * <p> + * Returns the URI from which this document was loaded, + * or null if this is not known. + * </p> + * + * @return the base URI of this document + */ + public final String getBaseURI() { + return baseURI; + } + + /* + * Replace the current child the given index with the supplied child. + * <p> + * In event of an exception the original content will be unchanged and + * the supplied child will be unaltered. + * </p> + * + * @param index - index of child to replace. + * @param child - child to add. + * @throws IllegalAddException if the supplied child is already attached + * or not legal content for this parent. + * @throws IndexOutOfBoundsException if index is negative or greater + * than the current number of children. + */ + public Document setContent(int index, Content child) { + content.set(index, child); + return this; + } + + /** + * Replace the child at the given index whith the supplied + * collection. + * <p> + * In event of an exception the original content will be unchanged and + * the content in the supplied collection will be unaltered. + * </p> + * + * @param index - index of child to replace. + * @param collection - collection of content to add. + * @return object on which the method was invoked + * @throws IllegalAddException if the collection contains objects of + * illegal types. + * @throws IndexOutOfBoundsException if index is negative or greater + * than the current number of children. + */ + public Document setContent(int index, Collection collection) { + content.remove(index); + content.addAll(index, collection); + return this; + } + + public boolean removeContent(Content child) { + return content.remove(child); + } + + public Content removeContent(int index) { + return (Content) content.remove(index); + } + + /** + * Set this document's content to be the supplied child. + * <p> + * If the supplied child is legal content for a Document and before + * it is added, all content in the current content list will + * be cleared and all current children will have their parentage set to + * null. + * <p> + * This has the effect that any active list (previously obtained with + * a call to one of the {@link #getContent} methods will also change + * to reflect the new content. In addition, all content in the supplied + * collection will have their parentage set to this Document. If the user + * wants to continue working with a <b>"live"</b> list of this Document's + * child, then a call to setContent should be followed by a call to one + * of the {@link #getContent} methods to obtain a <b>"live"</b> + * version of the children. + * <p> + * Passing a null child clears the existing content. + * <p> + * In event of an exception the original content will be unchanged and + * the supplied child will be unaltered. + * + * @param child new content to replace existing content + * @return the parent on which the method was called + * @throws IllegalAddException if the supplied child is already attached + * or not legal content for this parent + */ + public Document setContent(Content child) { + content.clear(); + content.add(child); + return this; + } + + /** + * This returns a <code>String</code> representation of the + * <code>Document</code>, suitable for debugging. If the XML + * representation of the <code>Document</code> is desired, + * {@link org.jdom.output.XMLOutputter#outputString(Document)} + * should be used. + * + * @return <code>String</code> - information about the + * <code>Document</code> + */ + public String toString() { + StringBuffer stringForm = new StringBuffer() + .append("[Document: "); + + DocType docType = getDocType(); + if (docType != null) { + stringForm.append(docType.toString()) + .append(", "); + } else { + stringForm.append(" No DOCTYPE declaration, "); + } + + Element rootElement = getRootElement(); + if (rootElement != null) { + stringForm.append("Root is ") + .append(rootElement.toString()); + } else { + stringForm.append(" No root element"); // shouldn't happen + } + + stringForm.append("]"); + + return stringForm.toString(); + } + + /** + * This tests for equality of this <code>Document</code> to the supplied + * <code>Object</code>. + * + * @param ob <code>Object</code> to compare to + * @return <code>boolean</code> whether the <code>Document</code> is + * equal to the supplied <code>Object</code> + */ + public final boolean equals(Object ob) { + return (ob == this); + } + + /** + * This returns the hash code for this <code>Document</code>. + * + * @return <code>int</code> hash code + */ + public final int hashCode() { + return super.hashCode(); + } + + /** + * This will return a deep clone of this <code>Document</code>. + * + * @return <code>Object</code> clone of this <code>Document</code> + */ + public Object clone() { + Document doc = null; + + try { + doc = (Document) super.clone(); + } catch (CloneNotSupportedException ce) { + // Can't happen + } + + // The clone has a reference to this object's content list, so + // owerwrite with a empty list + doc.content = new ContentList(doc); + + // Add the cloned content to clone + + for (int i = 0; i < content.size(); i++) { + Object obj = content.get(i); + if (obj instanceof Element) { + Element element = (Element)((Element)obj).clone(); + doc.content.add(element); + } + else if (obj instanceof Comment) { + Comment comment = (Comment)((Comment)obj).clone(); + doc.content.add(comment); + } + else if (obj instanceof ProcessingInstruction) { + ProcessingInstruction pi = (ProcessingInstruction) + ((ProcessingInstruction)obj).clone(); + doc.content.add(pi); + } + else if (obj instanceof DocType) { + DocType dt = (DocType) ((DocType)obj).clone(); + doc.content.add(dt); + } + } + + return doc; + } + + /** + * Returns an iterator that walks over all descendants in document order. + * + * @return an iterator to walk descendants + */ + public Iterator getDescendants() { + return new DescendantIterator(this); + } + + /** + * Returns an iterator that walks over all descendants in document order + * applying the Filter to return only elements that match the filter rule. + * With filters you can match only Elements, only Comments, Elements or + * Comments, only Elements with a given name and/or prefix, and so on. + * + * @param filter filter to select which descendants to see + * @return an iterator to walk descendants within a filter + */ + public Iterator getDescendants(Filter filter) { + return new FilterIterator(new DescendantIterator(this), filter); + } + + public Parent getParent() { + return null; // documents never have parents + } + + + + /** + * @see org.jdom.Parent#getDocument() + */ + public Document getDocument() { + return this; + } + + /** + * Assigns an arbitrary object to be associated with this document under + * the given "id" string. Null values are permitted. Strings beginning + * with "http://www.jdom.org/ are reserved for JDOM use. + * + * @param id the id of the stored object + * @param value the object to store + */ + public void setProperty(String id, Object value) { + if (propertyMap == null) { + propertyMap = new HashMap(); + } + propertyMap.put(id, value); + } + + /** + * Returns the object associated with this document under the given "id" + * string, or null if there is no binding or if the binding explicitly + * stored a null value. + * + * @param id the id of the stored object to return + * @return the object associated with the given id + */ + public Object getProperty(String id) { + if (propertyMap == null) return null; + return propertyMap.get(id); + } +}