vgritsenko 2004/08/27 09:13:39
Modified: . status.xml java/src/org/apache/xindice/xml/dom/traversal TreeWalkerImpl.java Added: java/tests/src/org/apache/xindice/xml/dom TreeWalkerTest.java Log: Fix TreeWalker implementation. Add unit test. Revision Changes Path 1.47 +4 -0 xml-xindice/status.xml Index: status.xml =================================================================== RCS file: /home/cvs/xml-xindice/status.xml,v retrieving revision 1.46 retrieving revision 1.47 diff -u -r1.46 -r1.47 --- status.xml 27 Aug 2004 15:55:29 -0000 1.46 +++ status.xml 27 Aug 2004 16:13:39 -0000 1.47 @@ -74,6 +74,10 @@ <changes> <release version="1.1b5-dev"> + <action dev="VG" type="fix"> + Fixed bugs in TreeWalkerImpl, methods getRoot, getCurrentNode, + nextNode, previousNode. Added TreeWalker unit test. + </action> <action dev="VG" type="update"> Make SymbolTableSymbols singleton. </action> 1.9 +100 -93 xml-xindice/java/src/org/apache/xindice/xml/dom/traversal/TreeWalkerImpl.java Index: TreeWalkerImpl.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/xml/dom/traversal/TreeWalkerImpl.java,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- TreeWalkerImpl.java 8 Feb 2004 03:11:57 -0000 1.8 +++ TreeWalkerImpl.java 27 Aug 2004 16:13:39 -0000 1.9 @@ -32,28 +32,24 @@ * @version CVS $Revision$, $Date$ */ public final class TreeWalkerImpl implements TreeWalker, NodeIterator { - protected boolean valid = true; - protected Node root = null; - protected Node next = null; - protected int whatToShow = NodeFilter.SHOW_ALL; - protected NodeFilter filter = null; - protected boolean expand = false; + protected boolean valid; + protected Node root; + protected Node current; + protected int whatToShow; + protected NodeFilter filter; + protected boolean expand; public TreeWalkerImpl(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) throws DOMException { - this.root = null; - next = root; + this.valid = true; + this.root = root; + this.current = root; this.whatToShow = whatToShow; this.filter = filter; this.expand = entityReferenceExpansion; - if (acceptNode(root)) { - next = root; - } else { - nextNode(); - } } - public int getShowType(Node node) { + private int getShowType(Node node) { switch (node.getNodeType()) { case Node.ATTRIBUTE_NODE: return NodeFilter.SHOW_ATTRIBUTE; @@ -84,20 +80,20 @@ } } - public boolean acceptNode(Node node) { + private boolean acceptNode(Node node) { return ((getShowType(node) & whatToShow) > 0) && (filter == null || filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT); } /** - * The root node of the Iterator, as specified when it was created. + * The root node of the Iterator, as specified when it was created. */ public Node getRoot() { return root; } /** - * This attribute determines which node types are presented via the + * This attribute determines which node types are presented via the * iterator. The available set of constants is defined in the * <code>NodeFilter</code> interface. */ @@ -106,17 +102,18 @@ } /** - * The filter used to screen nodes. + * The filter used to screen nodes. */ public NodeFilter getFilter() { return filter; } /** - * The value of this flag determines whether the children of entity + * The value of this flag determines whether the children of entity * reference nodes are visible to the iterator. If false, they will be * skipped over. - * <br> To produce a view of the document that has entity references + * + * <br>To produce a view of the document that has entity references * expanded and does not expose the entity reference node itself, use the * whatToShow flags to hide the entity reference node and set * expandEntityReferences to true when creating the iterator. To produce @@ -129,7 +126,7 @@ } /** - * Detaches the iterator from the set which it iterated over, releasing + * Detaches the iterator from the set which it iterated over, releasing * any computational resources and placing the iterator in the INVALID * state. After<code>detach</code> has been invoked, calls to * <code>nextNode</code> or<code>previousNode</code> will raise the @@ -140,8 +137,9 @@ } /** - * The node at which the TreeWalker is currently positioned. - * <br> The value must not be null. Alterations to the DOM tree may cause + * The node at which the TreeWalker is currently positioned. + * + * <br>The value must not be null. Alterations to the DOM tree may cause * the current node to no longer be accepted by the TreeWalker's * associated filter. currentNode may also be explicitly set to any node, * whether or not it is within the subtree specified by the root node or @@ -149,31 +147,37 @@ * traversal occurs relative to currentNode even if it is not part of the * current view by applying the filters in the requested direction (not * changing currentNode where no traversal is possible). + * * @exception DOMException * NOT_SUPPORTED_ERR: Raised if the specified <code>currentNode</code> * is<code>null</code> . */ public Node getCurrentNode() { - return next; + return current; } public void setCurrentNode(Node currentNode) throws DOMException { if (!valid) { throw NodeImpl.EX_INVALID_STATE; } - next = currentNode; + if (currentNode == null) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + "Current node can not be set to null."); + } + this.current = currentNode; } /** - * Moves to and returns the closest visible ancestor node of the current + * Moves to and returns the closest visible ancestor node of the current * node. If the search for parentNode attempts to step upward from the * TreeWalker's root node, or if it fails to find a visible ancestor * node, this method retains the current position and returns null. + * * @return The new parent node, or null if the current node has no parent - * in the TreeWalker's logical view. + * in the TreeWalker's logical view. */ public Node parentNode() { - Node node = next; + Node node = this.current; while (node != null) { if (node == root) { return null; @@ -182,119 +186,133 @@ if (node == null) { return null; } else if (acceptNode(node)) { - next = node; - return next; + this.current = node; + return this.current; } } return null; } /** - * Moves the <code>TreeWalker</code> to the first visible child of the + * Moves the <code>TreeWalker</code> to the first visible child of the * current node, and returns the new node. If the current node has no * visible children, returns <code>null</code> , and retains the current * node. + * * @return The new node, or <code>null</code> if the current node has no - * visible children in the TreeWalker's logical view. + * visible children in the TreeWalker's logical view. */ public Node firstChild() { - Node node = next.getFirstChild(); + Node node = this.current.getFirstChild(); while (node != null) { if (acceptNode(node)) { - next = node; - return next; - } else - node = node.getNextSibling(); + this.current = node; + return this.current; + } + + node = node.getNextSibling(); } return null; } /** - * Moves the <code>TreeWalker</code> to the last visible child of the + * Moves the <code>TreeWalker</code> to the last visible child of the * current node, and returns the new node. If the current node has no * visible children, returns <code>null</code> , and retains the current * node. + * * @return The new node, or <code>null</code> if the current node has no - * children in the TreeWalker's logical view. + * children in the TreeWalker's logical view. */ public Node lastChild() { - Node node = next.getLastChild(); + Node node = this.current.getLastChild(); while (node != null) { if (acceptNode(node)) { - next = node; - return next; - } else - node = node.getPreviousSibling(); + this.current = node; + return this.current; + } + + node = node.getPreviousSibling(); } return null; } /** - * Moves the <code>TreeWalker</code> to the previous sibling of the + * Moves the <code>TreeWalker</code> to the previous sibling of the * current node, and returns the new node. If the current node has no * visible previous sibling, returns <code>null</code> , and retains the * current node. + * * @return The new node, or <code>null</code> if the current node has no - * previous sibling in the TreeWalker's logical view. + * previous sibling in the TreeWalker's logical view. */ public Node previousSibling() { - Node node = next.getPreviousSibling(); + Node node = this.current.getPreviousSibling(); while (node != null) { if (acceptNode(node)) { - next = node; - return next; - } else - node = node.getPreviousSibling(); + this.current = node; + return this.current; + } + + node = node.getPreviousSibling(); } return null; } /** - * Moves the <code>TreeWalker</code> to the next sibling of the current + * Moves the <code>TreeWalker</code> to the next sibling of the current * node, and returns the new node. If the current node has no visible * next sibling, returns <code>null</code> , and retains the current node. + * * @return The new node, or <code>null</code> if the current node has no - * next sibling in the TreeWalker's logical view. + * next sibling in the TreeWalker's logical view. */ public Node nextSibling() { - Node node = next.getNextSibling(); + Node node = this.current.getNextSibling(); while (node != null) { if (acceptNode(node)) { - next = node; - return next; - } else { - node = node.getNextSibling(); + this.current = node; + return this.current; } + + node = node.getNextSibling(); } return null; } /** - * Moves the <code>TreeWalker</code> to the previous visible node in + * Moves the <code>TreeWalker</code> to the previous visible node in * document order relative to the current node, and returns the new node. * If the current node has no previous node, or if the search for * previousNode attempts to step upward from the TreeWalker's root node, * returns <code>null</code> , and retains the current node. + * * @return The new node, or <code>null</code> if the current node has no - * previous node in the TreeWalker's logical view. + * previous node in the TreeWalker's logical view. */ public Node previousNode() { - Node node = next; + Node node = this.current; while (true) { - node = node.getPreviousSibling(); - if (node == null) { - node = node.getParentNode(); + Node tmp = node.getPreviousSibling(); + if (tmp == null) { + if (node == root) { + // Do not go out of the root + return null; + } + + tmp = node.getParentNode(); } else { - while (node.hasChildNodes()) { - node = node.getLastChild(); + while (tmp.hasChildNodes()) { + tmp = tmp.getLastChild(); } } - - if (node != null && acceptNode(node)) { - next = node; - return next; - } else if (node == null) { + node = tmp; + + if (node == null) { return null; + } else if (acceptNode(node)) { + this.current = node; + return this.current; } } } @@ -305,18 +323,12 @@ * current node has no next node, or if the search for nextNode attempts * to step upward from the TreeWalker's root node, returns * <code>null</code> , and retains the current node. + * * @return The new node, or <code>null</code> if the current node has no - * next node in the TreeWalker's logical view. + * next node in the TreeWalker's logical view. */ public Node nextNode() { - Node result = null; - if (next != null) { - result = next; - } else { - return null; - } - - Node node = next; + Node node = this.current; while (true) { if (node.hasChildNodes()) { node = node.getFirstChild(); @@ -326,24 +338,19 @@ node = node.getNextSibling(); if (node == null) { node = old; - /* - if ( node == root ) { - next = null; - return result; - } - */ node = node.getParentNode(); if (node == null || node == root) { - next = null; - return result; + // this.next stays the same + return null; } - } else + } else { break; + } } } if (node != null && acceptNode(node)) { - next = node; - return result; + this.current = node; + return node; } } } 1.1 xml-xindice/java/tests/src/org/apache/xindice/xml/dom/TreeWalkerTest.java Index: TreeWalkerTest.java =================================================================== /* * Copyright 1999-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * CVS $Id: TreeWalkerTest.java,v 1.1 2004/08/27 16:13:39 vgritsenko Exp $ */ package org.apache.xindice.xml.dom; import org.apache.xindice.xml.dom.traversal.TreeWalkerImpl; import junit.framework.TestCase; import org.w3c.dom.Node; import org.w3c.dom.traversal.NodeFilter; import org.w3c.dom.traversal.TreeWalker; /** * Tests TreeWalker class * * @version CVS $Revision: 1.1 $, $Date: 2004/08/27 16:13:39 $ */ public class TreeWalkerTest extends TestCase { private static final String XML = "<a>" + "<b/>" + "<c>" + "<d>" + "<e/>" + "<f/>" + "</d>" + "<g/>" + "<h/>" + "</c>" + "<i/>" + "</a>"; private Node dom; public void setUp() throws Exception { dom = DOMParser.toDocument(XML).getDocumentElement(); } public void testRootNode() throws Exception { TreeWalker tw = new TreeWalkerImpl(dom, NodeFilter.SHOW_ALL, null, false); assertEquals("a", tw.getRoot().getLocalName()); } public void testNextNode() throws Exception { TreeWalker tw = new TreeWalkerImpl(dom, NodeFilter.SHOW_ALL, null, false); assertEquals("a", tw.getCurrentNode().getLocalName()); assertEquals("b", tw.nextNode().getLocalName()); assertEquals("c", tw.nextNode().getLocalName()); assertEquals("d", tw.nextNode().getLocalName()); assertEquals("e", tw.nextNode().getLocalName()); assertEquals("f", tw.nextNode().getLocalName()); assertEquals("g", tw.nextNode().getLocalName()); assertEquals("h", tw.nextNode().getLocalName()); assertEquals("i", tw.nextNode().getLocalName()); assertEquals(null, tw.nextNode()); } public void testPreviousNode() throws Exception { TreeWalker tw = new TreeWalkerImpl(dom, NodeFilter.SHOW_ALL, null, false); tw.setCurrentNode(dom.getLastChild()); assertEquals("i", tw.getCurrentNode().getLocalName()); assertEquals("h", tw.previousNode().getLocalName()); assertEquals("g", tw.previousNode().getLocalName()); assertEquals("f", tw.previousNode().getLocalName()); assertEquals("e", tw.previousNode().getLocalName()); assertEquals("d", tw.previousNode().getLocalName()); assertEquals("c", tw.previousNode().getLocalName()); assertEquals("b", tw.previousNode().getLocalName()); assertEquals("a", tw.previousNode().getLocalName()); assertEquals(null, tw.previousNode()); } public void testCurrentNode() throws Exception { TreeWalker tw = new TreeWalkerImpl(dom, NodeFilter.SHOW_ALL, null, false); assertEquals("a", tw.getCurrentNode().getLocalName()); assertEquals(null, tw.previousNode()); assertEquals("a", tw.getCurrentNode().getLocalName()); tw.setCurrentNode(dom.getLastChild()); assertEquals("i", tw.getCurrentNode().getLocalName()); assertEquals(null, tw.nextNode()); assertEquals("i", tw.getCurrentNode().getLocalName()); } }