1
2
3
4
5
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
63
64
65
66
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154