|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
TreeWalkerImpl.java | 17.4% | 27.8% | 23.5% | 24.7% |
|
1 | /* | |
2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
3 | * contributor license agreements. See the NOTICE file distributed with | |
4 | * this work for additional information regarding copyright ownership. | |
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
6 | * (the "License"); you may not use this file except in compliance with | |
7 | * the License. You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | * | |
17 | * $Id: TreeWalkerImpl.java 541508 2007-05-25 01:54:12Z vgritsenko $ | |
18 | */ | |
19 | ||
20 | package org.apache.xindice.xml.dom.traversal; | |
21 | ||
22 | import org.apache.xindice.xml.dom.NodeImpl; | |
23 | ||
24 | import org.w3c.dom.DOMException; | |
25 | import org.w3c.dom.Node; | |
26 | import org.w3c.dom.traversal.NodeFilter; | |
27 | import org.w3c.dom.traversal.NodeIterator; | |
28 | import org.w3c.dom.traversal.TreeWalker; | |
29 | ||
30 | /** | |
31 | * TreeWalkerImpl | |
32 | * | |
33 | * @version $Revision: 541508 $, $Date: 2007-05-24 18:54:12 -0700 (Thu, 24 May 2007) $ | |
34 | */ | |
35 | public final class TreeWalkerImpl implements TreeWalker, NodeIterator { | |
36 | protected boolean valid; | |
37 | protected Node root; | |
38 | protected Node current; | |
39 | protected int whatToShow; | |
40 | protected NodeFilter filter; | |
41 | protected boolean expand; | |
42 | ||
43 | ||
44 | 471 | public TreeWalkerImpl(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) throws DOMException { |
45 | 471 | this.valid = true; |
46 | 471 | this.root = root; |
47 | 471 | this.current = root; |
48 | 471 | this.whatToShow = whatToShow; |
49 | 471 | this.filter = filter; |
50 | 471 | this.expand = entityReferenceExpansion; |
51 | } | |
52 | ||
53 | 5266 | private int getShowType(Node node) { |
54 | 5266 | switch (node.getNodeType()) { |
55 | 0 | case Node.ATTRIBUTE_NODE: |
56 | 0 | return NodeFilter.SHOW_ATTRIBUTE; |
57 | 6 | case Node.CDATA_SECTION_NODE: |
58 | 6 | return NodeFilter.SHOW_CDATA_SECTION; |
59 | 6 | case Node.COMMENT_NODE: |
60 | 6 | return NodeFilter.SHOW_COMMENT; |
61 | 0 | case Node.DOCUMENT_FRAGMENT_NODE: |
62 | 0 | return NodeFilter.SHOW_DOCUMENT_FRAGMENT; |
63 | 0 | case Node.DOCUMENT_NODE: |
64 | 0 | return NodeFilter.SHOW_DOCUMENT; |
65 | 0 | case Node.DOCUMENT_TYPE_NODE: |
66 | 0 | return NodeFilter.SHOW_DOCUMENT_TYPE; |
67 | 4115 | case Node.ELEMENT_NODE: |
68 | 4115 | return NodeFilter.SHOW_ELEMENT; |
69 | 0 | case Node.ENTITY_NODE: |
70 | 0 | return NodeFilter.SHOW_ENTITY; |
71 | 0 | case Node.ENTITY_REFERENCE_NODE: |
72 | 0 | return NodeFilter.SHOW_ENTITY_REFERENCE; |
73 | 0 | case Node.NOTATION_NODE: |
74 | 0 | return NodeFilter.SHOW_NOTATION; |
75 | 0 | case Node.PROCESSING_INSTRUCTION_NODE: |
76 | 0 | return NodeFilter.SHOW_PROCESSING_INSTRUCTION; |
77 | 1139 | case Node.TEXT_NODE: |
78 | 1139 | return NodeFilter.SHOW_TEXT; |
79 | 0 | default: |
80 | 0 | return 0; |
81 | } | |
82 | } | |
83 | ||
84 | 5266 | private boolean acceptNode(Node node) { |
85 | 5266 | return ((getShowType(node) & whatToShow) > 0) |
86 | && (filter == null || filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT); | |
87 | } | |
88 | ||
89 | /** | |
90 | * The root node of the Iterator, as specified when it was created. | |
91 | */ | |
92 | 0 | public Node getRoot() { |
93 | 0 | return root; |
94 | } | |
95 | ||
96 | /** | |
97 | * This attribute determines which node types are presented via the | |
98 | * iterator. The available set of constants is defined in the | |
99 | * <code>NodeFilter</code> interface. | |
100 | */ | |
101 | 0 | public int getWhatToShow() { |
102 | 0 | return whatToShow; |
103 | } | |
104 | ||
105 | /** | |
106 | * The filter used to screen nodes. | |
107 | */ | |
108 | 0 | public NodeFilter getFilter() { |
109 | 0 | return filter; |
110 | } | |
111 | ||
112 | /** | |
113 | * The value of this flag determines whether the children of entity | |
114 | * reference nodes are visible to the iterator. If false, they will be | |
115 | * skipped over. | |
116 | * | |
117 | * <br>To produce a view of the document that has entity references | |
118 | * expanded and does not expose the entity reference node itself, use the | |
119 | * whatToShow flags to hide the entity reference node and set | |
120 | * expandEntityReferences to true when creating the iterator. To produce | |
121 | * a view of the document that has entity reference nodes but no entity | |
122 | * expansion, use the whatToShow flags to show the entity reference node | |
123 | * and set expandEntityReferences to false. | |
124 | */ | |
125 | 0 | public boolean getExpandEntityReferences() { |
126 | 0 | return expand; |
127 | } | |
128 | ||
129 | /** | |
130 | * Detaches the iterator from the set which it iterated over, releasing | |
131 | * any computational resources and placing the iterator in the INVALID | |
132 | * state. After<code>detach</code> has been invoked, calls to | |
133 | * <code>nextNode</code> or<code>previousNode</code> will raise the | |
134 | * exception INVALID_STATE_ERR. | |
135 | */ | |
136 | 0 | public void detach() { |
137 | 0 | valid = false; |
138 | } | |
139 | ||
140 | /** | |
141 | * The node at which the TreeWalker is currently positioned. | |
142 | * | |
143 | * <br>The value must not be null. Alterations to the DOM tree may cause | |
144 | * the current node to no longer be accepted by the TreeWalker's | |
145 | * associated filter. currentNode may also be explicitly set to any node, | |
146 | * whether or not it is within the subtree specified by the root node or | |
147 | * would be accepted by the filter and whatToShow flags. Further | |
148 | * traversal occurs relative to currentNode even if it is not part of the | |
149 | * current view by applying the filters in the requested direction (not | |
150 | * changing currentNode where no traversal is possible). | |
151 | * | |
152 | * @exception DOMException | |
153 | * NOT_SUPPORTED_ERR: Raised if the specified <code>currentNode</code> | |
154 | * is<code>null</code> . | |
155 | */ | |
156 | 0 | public Node getCurrentNode() { |
157 | 0 | return current; |
158 | } | |
159 | ||
160 | 0 | public void setCurrentNode(Node currentNode) throws DOMException { |
161 | 0 | if (!valid) { |
162 | 0 | throw NodeImpl.EX_INVALID_STATE; |
163 | } | |
164 | 0 | if (currentNode == null) { |
165 | 0 | throw new DOMException(DOMException.NOT_SUPPORTED_ERR, |
166 | "Current node can not be set to null."); | |
167 | } | |
168 | 0 | this.current = currentNode; |
169 | } | |
170 | ||
171 | /** | |
172 | * Moves to and returns the closest visible ancestor node of the current | |
173 | * node. If the search for parentNode attempts to step upward from the | |
174 | * TreeWalker's root node, or if it fails to find a visible ancestor | |
175 | * node, this method retains the current position and returns null. | |
176 | * | |
177 | * @return The new parent node, or null if the current node has no parent | |
178 | * in the TreeWalker's logical view. | |
179 | */ | |
180 | 0 | public Node parentNode() { |
181 | 0 | Node node = this.current; |
182 | 0 | while (node != null) { |
183 | 0 | if (node == root) { |
184 | 0 | return null; |
185 | } | |
186 | 0 | node = node.getParentNode(); |
187 | 0 | if (node == null) { |
188 | 0 | return null; |
189 | 0 | } else if (acceptNode(node)) { |
190 | 0 | this.current = node; |
191 | 0 | return this.current; |
192 | } | |
193 | } | |
194 | 0 | return null; |
195 | } | |
196 | ||
197 | /** | |
198 | * Moves the <code>TreeWalker</code> to the first visible child of the | |
199 | * current node, and returns the new node. If the current node has no | |
200 | * visible children, returns <code>null</code> , and retains the current | |
201 | * node. | |
202 | * | |
203 | * @return The new node, or <code>null</code> if the current node has no | |
204 | * visible children in the TreeWalker's logical view. | |
205 | */ | |
206 | 0 | public Node firstChild() { |
207 | 0 | Node node = this.current.getFirstChild(); |
208 | 0 | while (node != null) { |
209 | 0 | if (acceptNode(node)) { |
210 | 0 | this.current = node; |
211 | 0 | return this.current; |
212 | } | |
213 | ||
214 | 0 | node = node.getNextSibling(); |
215 | } | |
216 | 0 | return null; |
217 | } | |
218 | ||
219 | /** | |
220 | * Moves the <code>TreeWalker</code> to the last visible child of the | |
221 | * current node, and returns the new node. If the current node has no | |
222 | * visible children, returns <code>null</code> , and retains the current | |
223 | * node. | |
224 | * | |
225 | * @return The new node, or <code>null</code> if the current node has no | |
226 | * children in the TreeWalker's logical view. | |
227 | */ | |
228 | 0 | public Node lastChild() { |
229 | 0 | Node node = this.current.getLastChild(); |
230 | 0 | while (node != null) { |
231 | 0 | if (acceptNode(node)) { |
232 | 0 | this.current = node; |
233 | 0 | return this.current; |
234 | } | |
235 | ||
236 | 0 | node = node.getPreviousSibling(); |
237 | } | |
238 | 0 | return null; |
239 | } | |
240 | ||
241 | /** | |
242 | * Moves the <code>TreeWalker</code> to the previous sibling of the | |
243 | * current node, and returns the new node. If the current node has no | |
244 | * visible previous sibling, returns <code>null</code> , and retains the | |
245 | * current node. | |
246 | * | |
247 | * @return The new node, or <code>null</code> if the current node has no | |
248 | * previous sibling in the TreeWalker's logical view. | |
249 | */ | |
250 | 0 | public Node previousSibling() { |
251 | 0 | Node node = this.current.getPreviousSibling(); |
252 | 0 | while (node != null) { |
253 | 0 | if (acceptNode(node)) { |
254 | 0 | this.current = node; |
255 | 0 | return this.current; |
256 | } | |
257 | ||
258 | 0 | node = node.getPreviousSibling(); |
259 | } | |
260 | 0 | return null; |
261 | } | |
262 | ||
263 | /** | |
264 | * Moves the <code>TreeWalker</code> to the next sibling of the current | |
265 | * node, and returns the new node. If the current node has no visible | |
266 | * next sibling, returns <code>null</code> , and retains the current node. | |
267 | * | |
268 | * @return The new node, or <code>null</code> if the current node has no | |
269 | * next sibling in the TreeWalker's logical view. | |
270 | */ | |
271 | 0 | public Node nextSibling() { |
272 | 0 | Node node = this.current.getNextSibling(); |
273 | 0 | while (node != null) { |
274 | 0 | if (acceptNode(node)) { |
275 | 0 | this.current = node; |
276 | 0 | return this.current; |
277 | } | |
278 | ||
279 | 0 | node = node.getNextSibling(); |
280 | } | |
281 | 0 | return null; |
282 | } | |
283 | ||
284 | /** | |
285 | * Moves the <code>TreeWalker</code> to the previous visible node in | |
286 | * document order relative to the current node, and returns the new node. | |
287 | * If the current node has no previous node, or if the search for | |
288 | * previousNode attempts to step upward from the TreeWalker's root node, | |
289 | * returns <code>null</code> , and retains the current node. | |
290 | * | |
291 | * @return The new node, or <code>null</code> if the current node has no | |
292 | * previous node in the TreeWalker's logical view. | |
293 | */ | |
294 | 0 | public Node previousNode() { |
295 | 0 | Node node = this.current; |
296 | 0 | while (true) { |
297 | 0 | Node tmp = node.getPreviousSibling(); |
298 | 0 | if (tmp == null) { |
299 | 0 | if (node == root) { |
300 | // Do not go out of the root | |
301 | 0 | return null; |
302 | } | |
303 | ||
304 | 0 | tmp = node.getParentNode(); |
305 | } else { | |
306 | 0 | while (tmp.hasChildNodes()) { |
307 | 0 | tmp = tmp.getLastChild(); |
308 | } | |
309 | } | |
310 | 0 | node = tmp; |
311 | ||
312 | 0 | if (node == null) { |
313 | 0 | return null; |
314 | 0 | } else if (acceptNode(node)) { |
315 | 0 | this.current = node; |
316 | 0 | return this.current; |
317 | } | |
318 | } | |
319 | } | |
320 | ||
321 | /** | |
322 | * Moves the <code>TreeWalker</code> to the next visible node in document | |
323 | * order relative to the current node, and returns the new node. If the | |
324 | * current node has no next node, or if the search for nextNode attempts | |
325 | * to step upward from the TreeWalker's root node, returns | |
326 | * <code>null</code> , and retains the current node. | |
327 | * | |
328 | * @return The new node, or <code>null</code> if the current node has no | |
329 | * next node in the TreeWalker's logical view. | |
330 | */ | |
331 | 4288 | public Node nextNode() { |
332 | 4288 | Node node = this.current; |
333 | 4288 | while (true) { |
334 | 5737 | if (node.hasChildNodes()) { |
335 | 662 | node = node.getFirstChild(); |
336 | } else { | |
337 | 5075 | while (true) { |
338 | 5266 | Node old = node; |
339 | 5266 | node = node.getNextSibling(); |
340 | 5266 | if (node == null) { |
341 | 662 | node = old; |
342 | 662 | node = node.getParentNode(); |
343 | 662 | if (node == null || node == root) { |
344 | // this.next stays the same | |
345 | 471 | return null; |
346 | } | |
347 | } else { | |
348 | 4604 | break; |
349 | } | |
350 | } | |
351 | } | |
352 | 5266 | if (node != null && acceptNode(node)) { |
353 | 3817 | this.current = node; |
354 | 3817 | return node; |
355 | } | |
356 | } | |
357 | } | |
358 | } |
|