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: PruningElementStack.java,v 1.5 2001/05/18 18:38:21 drwhite Exp $
008 */
009
010package org.dom4j.io;
011
012import java.util.ArrayList;
013
014import org.dom4j.Element;
015import org.dom4j.ElementHandler;
016
017/** <p><code>PruningElementStack</code> is a stack of {@link Element} 
018  * instances which will prune the tree when a path expression is reached. 
019  * This is useful for parsing very large documents where children of the
020  * root element can be processed individually rather than keeping them all
021  * in memory at the same time.</p>
022  *
023  * @author <a href="mailto:james.strachan@metastuff.com">James Strachan</a>
024  * @version $Revision: 1.5 $
025  */
026class PruningElementStack extends ElementStack {
027
028    /** ElementHandler to call when pruning occurs */
029    private ElementHandler elementHandler;
030 
031    /** the element name path which denotes the node to remove from its parent
032      * when it is complete (i.e. when it is popped from the stack).
033      * The first entry in the path will be a child of the root node
034      */
035    private String[] path;
036
037    /** The level at which a path match can occur. 
038      * We match when we have popped the selected node so the 
039      * and the lastElementIndex points to its parent so this
040      * value should be path.length - 2
041      */
042    private int matchingElementIndex;
043    
044    
045    
046    public PruningElementStack(String[] path, ElementHandler elementHandler) {
047        this.path = path;
048        this.elementHandler = elementHandler;
049        checkPath();
050    }
051    
052    public PruningElementStack(String[] path, ElementHandler elementHandler, int defaultCapacity) {
053        super(defaultCapacity);
054        this.path = path;
055        this.elementHandler = elementHandler;
056        checkPath();
057    }
058    
059    public Element popElement() {
060        Element answer = super.popElement();
061        
062        if ( lastElementIndex == matchingElementIndex && lastElementIndex >= 0 ) {
063            // we are popping the correct level in the tree
064            // lets check if the path fits
065            //
066            // NOTE: this is an inefficient way of doing it - we could 
067            // maintain a history of which parts matched?
068            if ( validElement( answer, lastElementIndex + 1 ) ) {
069                Element parent = null;
070                for ( int i = 0; i <= lastElementIndex; i++ ) {
071                    parent = stack[i];
072                    if ( ! validElement( parent, i ) ) {
073                        parent = null;
074                        break;
075                    }
076                }
077                if ( parent != null ) {
078                    pathMatches(parent, answer);
079                }
080            }
081        }
082        return answer;
083    }
084    
085    protected void pathMatches(Element parent, Element selectedNode) {
086        //System.out.println( "Matched: " + selectedNode + " about to call handler" );
087        
088        //elementHandler.handle( selectedNode );
089        elementHandler.onEnd(this);
090        
091        //System.out.println( "Pruning: removing " + selectedNode + " from parent: " + parent );
092        parent.remove( selectedNode );
093    }
094    
095    protected boolean validElement(Element element, int index) {
096        String requiredName = path[index];
097        String name = element.getName();
098        if (requiredName == name) { 
099            return true;
100        }
101        if (requiredName != null && name != null ) {
102            return requiredName.equals( name );
103        }
104        return false;
105    }
106    
107    
108    private void checkPath() {
109        if ( path.length < 2 ) {
110            throw new RuntimeException( "Invalid path of length: " + path.length + " it must be greater than 2" );
111        }
112        matchingElementIndex = path.length - 2;
113    }
114}
115
116
117
118
119/*
120 * Redistribution and use of this software and associated documentation
121 * ("Software"), with or without modification, are permitted provided
122 * that the following conditions are met:
123 *
124 * 1. Redistributions of source code must retain copyright
125 *    statements and notices.  Redistributions must also contain a
126 *    copy of this document.
127 *
128 * 2. Redistributions in binary form must reproduce the
129 *    above copyright notice, this list of conditions and the
130 *    following disclaimer in the documentation and/or other
131 *    materials provided with the distribution.
132 *
133 * 3. The name "DOM4J" must not be used to endorse or promote
134 *    products derived from this Software without prior written
135 *    permission of MetaStuff, Ltd.  For written permission,
136 *    please contact dom4j-info@metastuff.com.
137 *
138 * 4. Products derived from this Software may not be called "DOM4J"
139 *    nor may "DOM4J" appear in their names without prior written
140 *    permission of MetaStuff, Ltd. DOM4J is a registered
141 *    trademark of MetaStuff, Ltd.
142 *
143 * 5. Due credit should be given to the DOM4J Project
144 *    (http://dom4j.org/).
145 *
146 * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
147 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
148 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
149 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
150 * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
151 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
152 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
153 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
154 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
155 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
156 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
157 * OF THE POSSIBILITY OF SUCH DAMAGE.
158 *
159 * Copyright 2001 (C) MetaStuff, Ltd. All Rights Reserved.
160 *
161 * $Id: PruningElementStack.java,v 1.5 2001/05/18 18:38:21 drwhite Exp $
162 */