1
2
3
4
5
6
7
8
9
10 package org.dom4j.io;
11
12 import org.dom4j.Element;
13 import org.dom4j.ElementHandler;
14 import org.dom4j.ElementPath;
15
16 /*** <p><code>ElementStack</code> is used internally inside the
17 * {@link SAXContentHandler} to maintain a stack of {@link Element}
18 * instances.
19 * It opens an integration possibility allowing derivations to prune the tree
20 * when a node is complete.</p>
21 *
22 * @author <a href="mailto:james.strachan@metastuff.com">James Strachan</a>
23 * @version $Revision: 1.12 $
24 */
25 class ElementStack implements ElementPath {
26
27 /*** stack of <code>Element</code> objects */
28 protected Element[] stack;
29
30 /*** index of the item at the top of the stack or -1 if the stack is empty */
31 protected int lastElementIndex = -1;
32
33 private DispatchHandler handler = null;
34
35
36 public ElementStack() {
37 this(50);
38 }
39
40 public ElementStack(int defaultCapacity) {
41 stack = new Element[defaultCapacity];
42 }
43
44 public void setDispatchHandler(DispatchHandler handler)
45 {
46 this.handler = handler;
47 }
48
49 public DispatchHandler getDispatchHandler(){
50 return this.handler;
51 }
52
53 /*** Peeks at the top element on the stack without changing the contents
54 * of the stack.
55 *
56 * @return the current element on the stack
57 */
58 public void clear() {
59 lastElementIndex = -1;
60 }
61
62 /*** Peeks at the top element on the stack without changing the contents
63 * of the stack.
64 *
65 * @return the current element on the stack
66 */
67 public Element peekElement() {
68 if ( lastElementIndex < 0 ) {
69 return null;
70 }
71 return stack[ lastElementIndex ];
72 }
73
74 /*** Pops the element off the stack
75 *
76 * @return the element that has just been popped off the stack
77 */
78 public Element popElement() {
79 if ( lastElementIndex < 0 ) {
80 return null;
81 }
82 return stack[ lastElementIndex-- ];
83 }
84
85 /*** Pushes a new element onto the stack
86 *
87 * @return pushes the new element onto the stack and add it to its parent
88 * if there is one.
89 */
90 public void pushElement(Element element) {
91 int length = stack.length;
92 if ( ++lastElementIndex >= length ) {
93 reallocate( length * 2 );
94 }
95 stack[lastElementIndex] = element;
96 }
97
98 /*** Reallocates the stack to the given size
99 */
100 protected void reallocate( int size ) {
101 Element[] oldStack = stack;
102 stack = new Element[ size ];
103 System.arraycopy( oldStack, 0, stack, 0, oldStack.length );
104 }
105
106
107
108 public int size()
109 {
110 return lastElementIndex + 1;
111 }
112
113 public Element getElement(int depth)
114 {
115 Element element;
116 try {
117 element = (Element)stack[depth];
118 }
119 catch (ArrayIndexOutOfBoundsException e)
120 {
121 element = null;
122 }
123 return element;
124 }
125
126 public String getPath()
127 {
128 if (handler == null) {
129 setDispatchHandler(new DispatchHandler());
130 }
131 return handler.getPath();
132 }
133
134 public Element getCurrent()
135 {
136 return peekElement();
137 }
138
139 public void addHandler(String path, ElementHandler handler) {
140 this.handler.addHandler(getHandlerPath(path), handler);
141 }
142
143 public void removeHandler(String path) {
144 this.handler.removeHandler(getHandlerPath(path));
145 }
146
147 /*** @return true when an <code>ElementHandler</code> is registered for
148 * the specified path.
149 */
150 public boolean containsHandler(String path) {
151 return this.handler.containsHandler(path);
152 }
153
154 private String getHandlerPath(String path) {
155 String handlerPath;
156 if (this.handler == null) {
157 setDispatchHandler(new DispatchHandler());
158 }
159 if (path.startsWith("/")) {
160 handlerPath = path;
161 }
162 else if (getPath().equals("/")) {
163 handlerPath = getPath() + path;
164 }
165 else {
166 handlerPath = getPath() + "/" + path;
167 }
168 return handlerPath;
169 }
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218