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 */