View Javadoc

1   /*
2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3    *
4    * This software is open source.
5    * See the bottom of this file for the licence.
6    */
7   
8   package org.dom4j.io;
9   
10  import org.dom4j.Element;
11  import org.dom4j.ElementHandler;
12  
13  /***
14   * <p>
15   * <code>PruningElementStack</code> is a stack of {@link Element}instances
16   * which will prune the tree when a path expression is reached. This is useful
17   * for parsing very large documents where children of the root element can be
18   * processed individually rather than keeping them all in memory at the same
19   * time.
20   * </p>
21   * 
22   * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
23   * @version $Revision: 1.11 $
24   */
25  class PruningElementStack extends ElementStack {
26      /*** ElementHandler to call when pruning occurs */
27      private ElementHandler elementHandler;
28  
29      /***
30       * the element name path which denotes the node to remove from its parent
31       * when it is complete (i.e. when it is popped from the stack). The first
32       * entry in the path will be a child of the root node
33       */
34      private String[] path;
35  
36      /***
37       * The level at which a path match can occur. We match when we have popped
38       * the selected node so the and the lastElementIndex points to its parent so
39       * this value should be path.length - 2
40       */
41      private int matchingElementIndex;
42  
43      public PruningElementStack(String[] path, ElementHandler elementHandler) {
44          this.path = path;
45          this.elementHandler = elementHandler;
46          checkPath();
47      }
48  
49      public PruningElementStack(String[] path, ElementHandler elementHandler,
50              int defaultCapacity) {
51          super(defaultCapacity);
52          this.path = path;
53          this.elementHandler = elementHandler;
54          checkPath();
55      }
56  
57      public Element popElement() {
58          Element answer = super.popElement();
59  
60          if ((lastElementIndex == matchingElementIndex)
61                  && (lastElementIndex >= 0)) {
62              // we are popping the correct level in the tree
63              // lets check if the path fits
64              //
65              // NOTE: this is an inefficient way of doing it - we could
66              // maintain a history of which parts matched?
67              if (validElement(answer, lastElementIndex + 1)) {
68                  Element parent = null;
69  
70                  for (int i = 0; i <= lastElementIndex; i++) {
71                      parent = stack[i];
72  
73                      if (!validElement(parent, i)) {
74                          parent = null;
75  
76                          break;
77                      }
78                  }
79  
80                  if (parent != null) {
81                      pathMatches(parent, answer);
82                  }
83              }
84          }
85  
86          return answer;
87      }
88  
89      protected void pathMatches(Element parent, Element selectedNode) {
90          elementHandler.onEnd(this);
91          parent.remove(selectedNode);
92      }
93  
94      protected boolean validElement(Element element, int index) {
95          String requiredName = path[index];
96          String name = element.getName();
97  
98          if (requiredName == name) {
99              return true;
100         }
101 
102         if ((requiredName != null) && (name != null)) {
103             return requiredName.equals(name);
104         }
105 
106         return false;
107     }
108 
109     private void checkPath() {
110         if (path.length < 2) {
111             throw new RuntimeException("Invalid path of length: " + path.length
112                     + " it must be greater than 2");
113         }
114 
115         matchingElementIndex = path.length - 2;
116     }
117 }
118 
119 /*
120  * Redistribution and use of this software and associated documentation
121  * ("Software"), with or without modification, are permitted provided that the
122  * following conditions are met:
123  * 
124  * 1. Redistributions of source code must retain copyright statements and
125  * notices. Redistributions must also contain a copy of this document.
126  * 
127  * 2. Redistributions in binary form must reproduce the above copyright notice,
128  * this list of conditions and the following disclaimer in the documentation
129  * and/or other materials provided with the distribution.
130  * 
131  * 3. The name "DOM4J" must not be used to endorse or promote products derived
132  * from this Software without prior written permission of MetaStuff, Ltd. For
133  * written permission, please contact dom4j-info@metastuff.com.
134  * 
135  * 4. Products derived from this Software may not be called "DOM4J" nor may
136  * "DOM4J" appear in their names without prior written permission of MetaStuff,
137  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
138  * 
139  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
140  * 
141  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
142  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
143  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
144  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
145  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
146  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
147  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
148  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
149  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
150  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
151  * POSSIBILITY OF SUCH DAMAGE.
152  * 
153  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
154  */