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