001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.dom;
019:
020: import org.w3c.dom.DOMException;
021: import org.w3c.dom.Document;
022: import org.w3c.dom.Node;
023: import org.w3c.dom.traversal.NodeFilter;
024: import org.w3c.dom.traversal.TreeWalker;
025:
026: /**
027: * This class implements the TreeWalker interface.
028: *
029: * @xerces.internal
030: *
031: * @version $Id: TreeWalkerImpl.java 536630 2007-05-09 19:37:05Z mrglavas $
032: */
033: public class TreeWalkerImpl implements TreeWalker {
034:
035: //
036: // Data
037: //
038:
039: /** When TRUE, the children of entites references are returned in the iterator. */
040: private boolean fEntityReferenceExpansion = false;
041: /** The whatToShow mask. */
042: int fWhatToShow = NodeFilter.SHOW_ALL;
043: /** The NodeFilter reference. */
044: NodeFilter fNodeFilter;
045: /** The current Node. */
046: Node fCurrentNode;
047: /** The root Node. */
048: Node fRoot;
049: /** Use Node.isSameNode() to check if one node is the same as another. */
050: private boolean fUseIsSameNode;
051:
052: //
053: // Implementation Note: No state is kept except the data above
054: // (fWhatToShow, fNodeFilter, fCurrentNode, fRoot) such that
055: // setters could be created for these data values and the
056: // implementation will still work.
057:
058: //
059: // Constructor
060: //
061:
062: /** Public constructor */
063: public TreeWalkerImpl(Node root, int whatToShow,
064: NodeFilter nodeFilter, boolean entityReferenceExpansion) {
065: fCurrentNode = root;
066: fRoot = root;
067: fUseIsSameNode = useIsSameNode(root);
068: fWhatToShow = whatToShow;
069: fNodeFilter = nodeFilter;
070: fEntityReferenceExpansion = entityReferenceExpansion;
071: }
072:
073: public Node getRoot() {
074: return fRoot;
075: }
076:
077: /** Return the whatToShow value */
078: public int getWhatToShow() {
079: return fWhatToShow;
080: }
081:
082: public void setWhatShow(int whatToShow) {
083: fWhatToShow = whatToShow;
084: }
085:
086: /** Return the NodeFilter */
087: public NodeFilter getFilter() {
088: return fNodeFilter;
089: }
090:
091: /** Return whether children entity references are included in the iterator. */
092: public boolean getExpandEntityReferences() {
093: return fEntityReferenceExpansion;
094: }
095:
096: /** Return the current Node. */
097: public Node getCurrentNode() {
098: return fCurrentNode;
099: }
100:
101: /** Return the current Node. */
102: public void setCurrentNode(Node node) {
103: if (node == null) {
104: String msg = DOMMessageFormatter.formatMessage(
105: DOMMessageFormatter.DOM_DOMAIN,
106: "NOT_SUPPORTED_ERR", null);
107: throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
108: }
109:
110: fCurrentNode = node;
111: }
112:
113: /** Return the parent Node from the current node,
114: * after applying filter, whatToshow.
115: * If result is not null, set the current Node.
116: */
117: public Node parentNode() {
118:
119: if (fCurrentNode == null)
120: return null;
121:
122: Node node = getParentNode(fCurrentNode);
123: if (node != null) {
124: fCurrentNode = node;
125: }
126: return node;
127:
128: }
129:
130: /** Return the first child Node from the current node,
131: * after applying filter, whatToshow.
132: * If result is not null, set the current Node.
133: */
134: public Node firstChild() {
135:
136: if (fCurrentNode == null)
137: return null;
138:
139: Node node = getFirstChild(fCurrentNode);
140: if (node != null) {
141: fCurrentNode = node;
142: }
143: return node;
144: }
145:
146: /** Return the last child Node from the current node,
147: * after applying filter, whatToshow.
148: * If result is not null, set the current Node.
149: */
150: public Node lastChild() {
151:
152: if (fCurrentNode == null)
153: return null;
154:
155: Node node = getLastChild(fCurrentNode);
156: if (node != null) {
157: fCurrentNode = node;
158: }
159: return node;
160: }
161:
162: /** Return the previous sibling Node from the current node,
163: * after applying filter, whatToshow.
164: * If result is not null, set the current Node.
165: */
166: public Node previousSibling() {
167:
168: if (fCurrentNode == null)
169: return null;
170:
171: Node node = getPreviousSibling(fCurrentNode);
172: if (node != null) {
173: fCurrentNode = node;
174: }
175: return node;
176: }
177:
178: /** Return the next sibling Node from the current node,
179: * after applying filter, whatToshow.
180: * If result is not null, set the current Node.
181: */
182: public Node nextSibling() {
183: if (fCurrentNode == null)
184: return null;
185:
186: Node node = getNextSibling(fCurrentNode);
187: if (node != null) {
188: fCurrentNode = node;
189: }
190: return node;
191: }
192:
193: /** Return the previous Node from the current node,
194: * after applying filter, whatToshow.
195: * If result is not null, set the current Node.
196: */
197: public Node previousNode() {
198: Node result;
199:
200: if (fCurrentNode == null)
201: return null;
202:
203: // get sibling
204: result = getPreviousSibling(fCurrentNode);
205: if (result == null) {
206: result = getParentNode(fCurrentNode);
207: if (result != null) {
208: fCurrentNode = result;
209: return fCurrentNode;
210: }
211: return null;
212: }
213:
214: // get the lastChild of result.
215: Node lastChild = getLastChild(result);
216:
217: Node prev = lastChild;
218: while (lastChild != null) {
219: prev = lastChild;
220: lastChild = getLastChild(prev);
221: }
222:
223: lastChild = prev;
224:
225: // if there is a lastChild which passes filters return it.
226: if (lastChild != null) {
227: fCurrentNode = lastChild;
228: return fCurrentNode;
229: }
230:
231: // otherwise return the previous sibling.
232: if (result != null) {
233: fCurrentNode = result;
234: return fCurrentNode;
235: }
236:
237: // otherwise return null.
238: return null;
239: }
240:
241: /** Return the next Node from the current node,
242: * after applying filter, whatToshow.
243: * If result is not null, set the current Node.
244: */
245: public Node nextNode() {
246:
247: if (fCurrentNode == null)
248: return null;
249:
250: Node result = getFirstChild(fCurrentNode);
251:
252: if (result != null) {
253: fCurrentNode = result;
254: return result;
255: }
256:
257: result = getNextSibling(fCurrentNode);
258:
259: if (result != null) {
260: fCurrentNode = result;
261: return result;
262: }
263:
264: // return parent's 1st sibling.
265: Node parent = getParentNode(fCurrentNode);
266: while (parent != null) {
267: result = getNextSibling(parent);
268: if (result != null) {
269: fCurrentNode = result;
270: return result;
271: } else {
272: parent = getParentNode(parent);
273: }
274: }
275:
276: // end , return null
277: return null;
278: }
279:
280: /** Internal function.
281: * Return the parent Node, from the input node
282: * after applying filter, whatToshow.
283: * The current node is not consulted or set.
284: */
285: Node getParentNode(Node node) {
286:
287: if (node == null || isSameNode(node, fRoot))
288: return null;
289:
290: Node newNode = node.getParentNode();
291: if (newNode == null)
292: return null;
293:
294: int accept = acceptNode(newNode);
295:
296: if (accept == NodeFilter.FILTER_ACCEPT)
297: return newNode;
298: else
299: //if (accept == NodeFilter.SKIP_NODE) // and REJECT too.
300: {
301: return getParentNode(newNode);
302: }
303:
304: }
305:
306: /** Internal function.
307: * Return the nextSibling Node, from the input node
308: * after applying filter, whatToshow.
309: * The current node is not consulted or set.
310: */
311: Node getNextSibling(Node node) {
312: return getNextSibling(node, fRoot);
313: }
314:
315: /** Internal function.
316: * Return the nextSibling Node, from the input node
317: * after applying filter, whatToshow.
318: * NEVER TRAVERSES ABOVE THE SPECIFIED ROOT NODE.
319: * The current node is not consulted or set.
320: */
321: Node getNextSibling(Node node, Node root) {
322:
323: if (node == null || isSameNode(node, root))
324: return null;
325:
326: Node newNode = node.getNextSibling();
327: if (newNode == null) {
328:
329: newNode = node.getParentNode();
330:
331: if (newNode == null || isSameNode(newNode, root))
332: return null;
333:
334: int parentAccept = acceptNode(newNode);
335:
336: if (parentAccept == NodeFilter.FILTER_SKIP) {
337: return getNextSibling(newNode, root);
338: }
339:
340: return null;
341: }
342:
343: int accept = acceptNode(newNode);
344:
345: if (accept == NodeFilter.FILTER_ACCEPT)
346: return newNode;
347: else if (accept == NodeFilter.FILTER_SKIP) {
348: Node fChild = getFirstChild(newNode);
349: if (fChild == null) {
350: return getNextSibling(newNode, root);
351: }
352: return fChild;
353: } else
354: //if (accept == NodeFilter.REJECT_NODE)
355: {
356: return getNextSibling(newNode, root);
357: }
358:
359: } // getNextSibling(Node node) {
360:
361: /** Internal function.
362: * Return the previous sibling Node, from the input node
363: * after applying filter, whatToshow.
364: * The current node is not consulted or set.
365: */
366: Node getPreviousSibling(Node node) {
367: return getPreviousSibling(node, fRoot);
368: }
369:
370: /** Internal function.
371: * Return the previousSibling Node, from the input node
372: * after applying filter, whatToshow.
373: * NEVER TRAVERSES ABOVE THE SPECIFIED ROOT NODE.
374: * The current node is not consulted or set.
375: */
376: Node getPreviousSibling(Node node, Node root) {
377:
378: if (node == null || isSameNode(node, root))
379: return null;
380:
381: Node newNode = node.getPreviousSibling();
382: if (newNode == null) {
383:
384: newNode = node.getParentNode();
385: if (newNode == null || isSameNode(newNode, root))
386: return null;
387:
388: int parentAccept = acceptNode(newNode);
389:
390: if (parentAccept == NodeFilter.FILTER_SKIP) {
391: return getPreviousSibling(newNode, root);
392: }
393:
394: return null;
395: }
396:
397: int accept = acceptNode(newNode);
398:
399: if (accept == NodeFilter.FILTER_ACCEPT)
400: return newNode;
401: else if (accept == NodeFilter.FILTER_SKIP) {
402: Node fChild = getLastChild(newNode);
403: if (fChild == null) {
404: return getPreviousSibling(newNode, root);
405: }
406: return fChild;
407: } else
408: //if (accept == NodeFilter.REJECT_NODE)
409: {
410: return getPreviousSibling(newNode, root);
411: }
412:
413: } // getPreviousSibling(Node node) {
414:
415: /** Internal function.
416: * Return the first child Node, from the input node
417: * after applying filter, whatToshow.
418: * The current node is not consulted or set.
419: */
420: Node getFirstChild(Node node) {
421: if (node == null)
422: return null;
423:
424: if (!fEntityReferenceExpansion
425: && node.getNodeType() == Node.ENTITY_REFERENCE_NODE)
426: return null;
427: Node newNode = node.getFirstChild();
428: if (newNode == null)
429: return null;
430: int accept = acceptNode(newNode);
431:
432: if (accept == NodeFilter.FILTER_ACCEPT)
433: return newNode;
434: else if (accept == NodeFilter.FILTER_SKIP
435: && newNode.hasChildNodes()) {
436: Node fChild = getFirstChild(newNode);
437:
438: if (fChild == null) {
439: return getNextSibling(newNode, node);
440: }
441: return fChild;
442: } else
443: //if (accept == NodeFilter.REJECT_NODE)
444: {
445: return getNextSibling(newNode, node);
446: }
447:
448: }
449:
450: /** Internal function.
451: * Return the last child Node, from the input node
452: * after applying filter, whatToshow.
453: * The current node is not consulted or set.
454: */
455: Node getLastChild(Node node) {
456:
457: if (node == null)
458: return null;
459:
460: if (!fEntityReferenceExpansion
461: && node.getNodeType() == Node.ENTITY_REFERENCE_NODE)
462: return null;
463:
464: Node newNode = node.getLastChild();
465: if (newNode == null)
466: return null;
467:
468: int accept = acceptNode(newNode);
469:
470: if (accept == NodeFilter.FILTER_ACCEPT)
471: return newNode;
472: else if (accept == NodeFilter.FILTER_SKIP
473: && newNode.hasChildNodes()) {
474: Node lChild = getLastChild(newNode);
475: if (lChild == null) {
476: return getPreviousSibling(newNode, node);
477: }
478: return lChild;
479: } else
480: //if (accept == NodeFilter.REJECT_NODE)
481: {
482: return getPreviousSibling(newNode, node);
483: }
484:
485: }
486:
487: /** Internal function.
488: * The node whatToShow and the filter are combined into one result. */
489: short acceptNode(Node node) {
490: /***
491: 7.1.2.4. Filters and whatToShow flags
492:
493: Iterator and TreeWalker apply whatToShow flags before applying Filters. If a node is rejected by the
494: active whatToShow flags, a Filter will not be called to evaluate that node. When a node is rejected by
495: the active whatToShow flags, children of that node will still be considered, and Filters may be called to
496: evaluate them.
497: ***/
498:
499: if (fNodeFilter == null) {
500: if ((fWhatToShow & (1 << node.getNodeType() - 1)) != 0) {
501: return NodeFilter.FILTER_ACCEPT;
502: } else {
503: return NodeFilter.FILTER_SKIP;
504: }
505: } else {
506: if ((fWhatToShow & (1 << node.getNodeType() - 1)) != 0) {
507: return fNodeFilter.acceptNode(node);
508: } else {
509: // What to show has failed. See above excerpt from spec.
510: // Equivalent to FILTER_SKIP.
511: return NodeFilter.FILTER_SKIP;
512: }
513: }
514: }
515:
516: /**
517: * Use isSameNode() for testing node identity if the DOM implementation
518: * supports DOM Level 3 core and it isn't the Xerces implementation.
519: */
520: private boolean useIsSameNode(Node node) {
521: if (node instanceof NodeImpl) {
522: return false;
523: }
524: Document doc = node.getNodeType() == Node.DOCUMENT_NODE ? (Document) node
525: : node.getOwnerDocument();
526: return (doc != null && doc.getImplementation().hasFeature(
527: "Core", "3.0"));
528: }
529:
530: /**
531: * Returns true if <code>m</code> is the same node <code>n</code>.
532: */
533: private boolean isSameNode(Node m, Node n) {
534: return (fUseIsSameNode) ? m.isSameNode(n) : m == n;
535: }
536: }
|