001/*
002 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
003 * 
004 * This software is open source. 
005 * See the bottom of this file for the licence.
006 * 
007 * $Id: DefaultDocument.java,v 1.24 2001/08/02 07:09:45 jstrachan Exp $
008 */
009
010package org.dom4j.tree;
011
012import java.util.ArrayList;
013import java.util.Collections;
014import java.util.Iterator;
015import java.util.List;
016
017import org.dom4j.Comment;
018import org.dom4j.Document;
019import org.dom4j.DocumentFactory;
020import org.dom4j.DocumentType;
021import org.dom4j.Element;
022import org.dom4j.IllegalAddException;
023import org.dom4j.Node;
024import org.dom4j.ProcessingInstruction;
025
026import org.xml.sax.EntityResolver;
027
028/** <p><code>DefaultDocument</code> is the default DOM4J default implementation
029  * of an XML document.</p>
030  *
031  * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
032  * @version $Revision: 1.24 $
033  */
034public class DefaultDocument extends AbstractDocument {
035
036    protected static final List EMPTY_LIST = Collections.EMPTY_LIST;
037    protected static final Iterator EMPTY_ITERATOR = EMPTY_LIST.iterator();
038    
039    /** The name of the document */
040    private String name;
041
042    /** The root element of this document */
043    private Element rootElement;
044    
045    /** Store the contents of the document as a lazily created <code>List</code> */
046    private List content;
047    
048    /** The document type for this document */
049    private DocumentType docType;
050    
051    /** The document factory used by default */
052    private DocumentFactory documentFactory = DocumentFactory.getInstance();
053
054    /** The resolver of URIs */
055    private transient EntityResolver entityResolver;
056    
057    
058    public DefaultDocument() { 
059    }
060
061    public DefaultDocument(String name) { 
062        this.name = name;
063    }
064
065    public DefaultDocument(Element rootElement) { 
066        this.rootElement = rootElement;
067    }
068
069    public DefaultDocument(DocumentType docType) {
070        this.docType = docType;
071    }
072
073    public DefaultDocument(Element rootElement, DocumentType docType) {
074        this.rootElement = rootElement;
075        this.docType = docType;
076    }
077
078    public DefaultDocument(String name, Element rootElement, DocumentType docType) {
079        this.name = name;
080        this.rootElement = rootElement;
081        this.docType = docType;
082    }
083
084    public String getName() {
085        return name;
086    }
087    
088    public void setName(String name) {
089        this.name = name;
090    }
091
092    
093    public Element getRootElement() {
094        return rootElement;
095    }
096    
097    public DocumentType getDocType() {
098        return docType;
099    }
100    
101    public void setDocType(DocumentType docType) {
102        this.docType = docType;
103    }
104    
105    public Document addDocType(String name, String publicId, String systemId) {
106        setDocType( getDocumentFactory().createDocType( name, publicId, systemId ) );
107        return this;
108    }    
109    
110    public EntityResolver getEntityResolver() {
111        return entityResolver;
112    }    
113    
114    public void setEntityResolver(EntityResolver entityResolver) {
115        this.entityResolver = entityResolver;
116    }
117    
118    public Object clone() {
119        DefaultDocument document = (DefaultDocument) super.clone();
120        document.rootElement = null;
121        document.content = null;
122        document.appendContent(this);
123        return document;
124    }    
125    
126    public List processingInstructions() {
127        List source = contentList();
128        List answer = createResultList();
129        int size = source.size();
130        for ( int i = 0; i < size; i++ ) {
131            Object object = source.get(i);
132            if ( object instanceof ProcessingInstruction ) {
133                answer.add( object );
134            }
135        }
136        return answer;
137    }
138    
139    public List processingInstructions(String target) {
140        List source = contentList();
141        List answer = createResultList();
142        int size = source.size();
143        for ( int i = 0; i < size; i++ ) {
144            Object object = source.get(i);
145            if ( object instanceof ProcessingInstruction ) {
146                ProcessingInstruction pi = (ProcessingInstruction) object;
147                if ( target.equals( pi.getName() ) ) {                  
148                    answer.add( pi );
149                }
150            }
151        }
152        return answer;
153    }
154    
155    public ProcessingInstruction processingInstruction(String target) {
156        List source = contentList();
157        int size = source.size();
158        for ( int i = 0; i < size; i++ ) {
159            Object object = source.get(i);
160            if ( object instanceof ProcessingInstruction ) {
161                ProcessingInstruction pi = (ProcessingInstruction) object;
162                if ( target.equals( pi.getName() ) ) {                  
163                    return pi;
164                }
165            }
166        }
167        return null;
168    }
169    
170    public boolean removeProcessingInstruction(String target) {
171        List source = contentList();
172        for ( Iterator iter = source.iterator(); iter.hasNext(); ) {
173            Object object = iter.next();
174            if ( object instanceof ProcessingInstruction ) {
175                ProcessingInstruction pi = (ProcessingInstruction) object;
176                if ( target.equals( pi.getName() ) ) {                  
177                    iter.remove();
178                    return true;
179                }
180            }
181        }
182        return false;
183    }
184    
185    
186    public void setContent(List content) {
187        rootElement = null;
188        contentRemoved();
189        if ( content instanceof ContentListFacade ) {
190            content = ((ContentListFacade) content).getBackingList();
191        }
192        if ( content == null ) {
193            this.content = null;
194        }
195        else {
196            int size = content.size();
197            List newContent = createContentList( size );
198            for ( int i = 0; i < size; i++ ) {
199                Object object = content.get(i);
200                if ( object instanceof Node ) {
201                    Node node = (Node) object;
202                    Document doc = node.getDocument();
203                    if ( doc != null && doc != this ) {
204                        node = (Node) node.clone();
205                    }
206                    if ( node instanceof Element ) {
207                        if ( rootElement == null ) {
208                            rootElement = (Element) node;
209                        }
210                        else {
211                            throw new IllegalAddException( "A document may only contain one Element: " + content );
212                        }
213                    }
214                    newContent.add( node );
215                    childAdded( node );
216                }
217            }
218            this.content = newContent;
219        }
220    }
221    
222    public void clearContent() {
223        contentRemoved();
224        content = null;
225        rootElement = null;
226    }
227    
228    
229    public void setDocumentFactory(DocumentFactory documentFactory) {
230        this.documentFactory = documentFactory;
231    }
232
233    
234    // Implementation methods
235    //-------------------------------------------------------------------------
236    protected List contentList() {
237        if (content == null) {
238            content = createContentList();
239            if (rootElement != null) {
240                content.add( rootElement );
241            }
242        }
243        return content;
244    }
245    
246    
247    protected void addNode(Node node) {
248        if ( node != null ) {
249            Document document = node.getDocument();
250            if (document != null && document != this) {
251                // XXX: could clone here
252                String message = "The Node already has an existing document: " + document;
253                throw new IllegalAddException(this, node, message);
254            }
255            contentList().add(node);
256            childAdded(node);
257        }
258    }
259
260    protected boolean removeNode(Node node) {
261        if ( node == rootElement) {
262            rootElement = null;
263        }
264        if (contentList().remove(node)) {
265            childRemoved(node);
266            return true;
267        }
268        return false;
269    }
270
271    protected void rootElementAdded(Element element) {
272        this.rootElement = element;
273        element.setDocument(this);
274    }
275    
276    
277    protected DocumentFactory getDocumentFactory() {
278        return documentFactory;
279    }
280
281}
282
283
284
285
286/*
287 * Redistribution and use of this software and associated documentation
288 * ("Software"), with or without modification, are permitted provided
289 * that the following conditions are met:
290 *
291 * 1. Redistributions of source code must retain copyright
292 *    statements and notices.  Redistributions must also contain a
293 *    copy of this document.
294 *
295 * 2. Redistributions in binary form must reproduce the
296 *    above copyright notice, this list of conditions and the
297 *    following disclaimer in the documentation and/or other
298 *    materials provided with the distribution.
299 *
300 * 3. The name "DOM4J" must not be used to endorse or promote
301 *    products derived from this Software without prior written
302 *    permission of MetaStuff, Ltd.  For written permission,
303 *    please contact dom4j-info@metastuff.com.
304 *
305 * 4. Products derived from this Software may not be called "DOM4J"
306 *    nor may "DOM4J" appear in their names without prior written
307 *    permission of MetaStuff, Ltd. DOM4J is a registered
308 *    trademark of MetaStuff, Ltd.
309 *
310 * 5. Due credit should be given to the DOM4J Project
311 *    (http://dom4j.org/).
312 *
313 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
314 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
315 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
316 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
317 * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
318 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
319 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
320 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
322 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
323 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
324 * OF THE POSSIBILITY OF SUCH DAMAGE.
325 *
326 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
327 *
328 * $Id: DefaultDocument.java,v 1.24 2001/08/02 07:09:45 jstrachan Exp $
329 */