You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by tn...@apache.org on 2013/01/26 21:14:44 UTC

svn commit: r1438955 - in /commons/proper/collections/trunk: ./ src/changes/ src/main/java/org/apache/commons/collections/ src/main/java/org/apache/commons/collections/iterators/ src/test/java/org/apache/commons/collections/ src/test/java/org/apache/co...

Author: tn
Date: Sat Jan 26 20:14:43 2013
New Revision: 1438955

URL: http://svn.apache.org/viewvc?rev=1438955&view=rev
Log:
[COLLECTIONS-322] Added new NodeListIterator to iterate over a dom NodeList, thanks to Thomas Vahrst.

Added:
    commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/iterators/NodeListIterator.java   (with props)
    commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/iterators/NodeListIteratorTest.java   (with props)
Modified:
    commons/proper/collections/trunk/pom.xml
    commons/proper/collections/trunk/src/changes/changes.xml
    commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/IteratorUtils.java
    commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/IteratorUtilsTest.java

Modified: commons/proper/collections/trunk/pom.xml
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/pom.xml?rev=1438955&r1=1438954&r2=1438955&view=diff
==============================================================================
--- commons/proper/collections/trunk/pom.xml (original)
+++ commons/proper/collections/trunk/pom.xml Sat Jan 26 20:14:43 2013
@@ -382,6 +382,9 @@
       <name>Kazuya Ujihara</name>
     </contributor>
     <contributor>
+      <name>Thomas Vahrst</name>
+    </contributor>
+    <contributor>
       <name>Jeff Varszegi</name>
     </contributor>
     <contributor>

Modified: commons/proper/collections/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/changes/changes.xml?rev=1438955&r1=1438954&r2=1438955&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/changes/changes.xml (original)
+++ commons/proper/collections/trunk/src/changes/changes.xml Sat Jan 26 20:14:43 2013
@@ -22,6 +22,10 @@
   <body>
 
   <release version="4.0" date="TBA" description="Next release">
+    <action issue="COLLECTIONS-322" dev="tn" type="add" due-to="Thomas Vahrst">
+      Added NodeListIterator and convenience methods in IteratorUtils to iterate over
+      a org.w3c.dom.NodeList.
+    </action>
     <action issue="COLLECTIONS-436" dev="tn" type="add" due-to="Arman Sharif">
       Added "emptyIfNull" methods to classes "CollectionUtils", "ListUtils", "SetUtils"
       and "MapUtils".

Modified: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/IteratorUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/IteratorUtils.java?rev=1438955&r1=1438954&r2=1438955&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/IteratorUtils.java (original)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/IteratorUtils.java Sat Jan 26 20:14:43 2013
@@ -46,6 +46,7 @@ import org.apache.commons.collections.it
 import org.apache.commons.collections.iterators.ListIteratorWrapper;
 import org.apache.commons.collections.iterators.LoopingIterator;
 import org.apache.commons.collections.iterators.LoopingListIterator;
+import org.apache.commons.collections.iterators.NodeListIterator;
 import org.apache.commons.collections.iterators.ObjectArrayIterator;
 import org.apache.commons.collections.iterators.ObjectArrayListIterator;
 import org.apache.commons.collections.iterators.ObjectGraphIterator;
@@ -55,6 +56,8 @@ import org.apache.commons.collections.it
 import org.apache.commons.collections.iterators.UnmodifiableIterator;
 import org.apache.commons.collections.iterators.UnmodifiableListIterator;
 import org.apache.commons.collections.iterators.UnmodifiableMapIterator;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 
 /**
  * Provides static utility methods and decorators for {@link Iterator}
@@ -756,6 +759,45 @@ public class IteratorUtils {
         return new LoopingListIterator<E>(list);
     }
 
+    // org.w3c.dom.NodeList iterators
+    //-----------------------------------------------------------------------
+    /**
+     * Gets an {@link Iterator} that wraps the specified {@link NodeList}.
+     * The returned {@link Iterator} can be used for a single iteration.
+     *
+     * @param nodeList the node list to use, not null
+     * @return a new, single use {@link Iterator}
+     * @throws NullPointerException if nodeList is null
+     */
+    public static NodeListIterator nodeListIterator(final NodeList nodeList) {
+        if (nodeList == null) {
+            throw new NullPointerException("NodeList must not be null");
+        }
+        return new NodeListIterator(nodeList);
+    }
+
+    /**
+     * Gets an {@link Iterator} that wraps the specified node's childNodes.
+     * The returned {@link Iterator} can be used for a single iteration.
+     * <p>
+     * Convenience method, allows easy iteration over NodeLists:
+     * <pre>
+     *   for(Node childNode : IteratorUtils.asIterable(node)){
+     *     ...
+     *   }
+     * </pre>
+     *
+     * @param node the node to use, not null
+     * @return a new, single use {@link Iterator}
+     * @throws NullPointerException if node is null
+     */
+    public static NodeListIterator nodeListIterator(final Node node) {
+        if (node == null) {
+            throw new NullPointerException("Node must not be null");
+        }
+        return new NodeListIterator(node);
+    }
+
     // Views
     //-----------------------------------------------------------------------
     /**
@@ -823,6 +865,7 @@ public class IteratorUtils {
         return new IteratorIterable<E>(iterator, false);
     }
 
+    
     /**
      * Gets an iterable that wraps an iterator.  The returned iterable can be
      * used for multiple iterations.
@@ -957,6 +1000,8 @@ public class IteratorUtils {
      * <li>array - iterator over array returned
      * <li>object with iterator() public method accessed by reflection
      * <li>object - singleton iterator
+     * <li>NodeList - iterator over the list
+     * <li>Node - iterator over the child nodes
      * </ul>
      *
      * @param obj  the object to convert to an iterator
@@ -981,6 +1026,12 @@ public class IteratorUtils {
         if (obj instanceof Map) {
             return ((Map<?, ?>) obj).values().iterator();
         }
+        if (obj instanceof NodeList) {
+            return new NodeListIterator((NodeList) obj);
+        }
+        if (obj instanceof Node) {
+            return new NodeListIterator((Node) obj);
+        }
         if (obj instanceof Dictionary) {
             return new EnumerationIterator<Object>(((Dictionary<?, ?>) obj).elements());
         } else if (obj.getClass().isArray()) {

Added: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/iterators/NodeListIterator.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/iterators/NodeListIterator.java?rev=1438955&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/iterators/NodeListIterator.java (added)
+++ commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/iterators/NodeListIterator.java Sat Jan 26 20:14:43 2013
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2013 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.
+ */
+package org.apache.commons.collections.iterators;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * An {@link Iterator} over a {@link NodeList}.
+ * <p>
+ * This iterator does not support {@link #remove()} as a {@link NodeList} does not support
+ * removal of items.
+ *
+ * @since 4.0
+ * @version $Id$
+ * @see org.w3c.NodeList
+ */
+public class NodeListIterator implements Iterator<Node> {
+
+    /** the original NodeList instance */
+    private NodeList nodeList;
+    /** The current iterator index */
+    protected int index = 0;
+
+    /**
+     * Convenience constructor, which creates a new NodeListIterator from 
+     * the specified node's childNodes.
+     *
+     * @param node Node, who's child nodes are wrapped by this class. Must not be null
+     * @throws IllegalArgumentException if node is null
+     */
+    public NodeListIterator(Node node) {
+        if (node == null) {
+            throw new IllegalArgumentException("node must not be null!");
+        }
+        this.nodeList = node.getChildNodes();
+    }
+
+    /**
+     * Constructor, that creates a new NodeListIterator from the specified
+     * <code>org.w3c.NodeList</code>
+     *
+     * @param nodeList node list, which is wrapped by this class. Must not be null
+     * @throws IllegalArgumentException if nodeList is null
+     */
+    public NodeListIterator(NodeList nodeList) {
+        if (nodeList == null) {
+            throw new IllegalArgumentException("nodeList must not be null!");
+        }
+        this.nodeList = nodeList;
+    }
+    
+    public boolean hasNext() {
+        return nodeList == null ? false : index < nodeList.getLength();
+    }
+
+    public Node next() {
+        if (nodeList != null && index < nodeList.getLength()) {
+            return nodeList.item(index++);
+        } else {
+            throw new NoSuchElementException("underlying nodeList has no more elements");
+        }
+    }
+
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public void remove() {
+        throw new UnsupportedOperationException("remove() method not supported for an NodeListIterator.");
+    }
+}

Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/iterators/NodeListIterator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/iterators/NodeListIterator.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision HeadURL

Propchange: commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/iterators/NodeListIterator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/IteratorUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/IteratorUtilsTest.java?rev=1438955&r1=1438954&r2=1438955&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/IteratorUtilsTest.java (original)
+++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/IteratorUtilsTest.java Sat Jan 26 20:14:43 2013
@@ -30,13 +30,17 @@ import org.apache.commons.collections.it
 import org.apache.commons.collections.iterators.EmptyMapIterator;
 import org.apache.commons.collections.iterators.EmptyOrderedIterator;
 import org.apache.commons.collections.iterators.EmptyOrderedMapIterator;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
 
 /**
  * Tests for IteratorUtils.
  *
- * @version $Revision$
- *
- * @author Unknown
+ * @version $Id$
  */
 public class IteratorUtilsTest extends BulkTest {
 
@@ -69,7 +73,7 @@ public class IteratorUtilsTest extends B
             fail("should not be able to iterate twice");
         }
     }
-
+    
     public void testAsIterableNull() {
         try {
             IteratorUtils.asIterable(null);
@@ -787,4 +791,83 @@ public class IteratorUtilsTest extends B
         }
     }
 
+    /**
+     * Tests method nodeListIterator(NodeList)
+     */
+    public void testNodeListIterator() {
+        Node[] nodes = createNodes();
+        NodeList nodeList = createNodeList(nodes);
+        
+        final Iterator<Node> iterator = IteratorUtils.nodeListIterator(nodeList);
+        int expectedNodeIndex = 0;
+        for (final Node actual : IteratorUtils.asIterable(iterator)) {
+            assertEquals(nodes[expectedNodeIndex], actual);
+            ++expectedNodeIndex;
+        }
+
+        // insure iteration occurred
+        assertTrue(expectedNodeIndex > 0);
+
+        // single use iterator
+        for (final Node actual : IteratorUtils.asIterable(iterator)) {
+            fail("should not be able to iterate twice");
+        }
+    }
+    /**
+     * Tests method nodeListIterator(Node)
+     */
+    public void testNodeIterator() {
+        Node[] nodes = createNodes();
+        NodeList nodeList = createNodeList(nodes);
+        Node parentNode = createMock(Node.class);
+        expect(parentNode.getChildNodes()).andStubReturn(nodeList);
+        replay(parentNode);
+        
+        final Iterator<Node> iterator = IteratorUtils.nodeListIterator(parentNode);
+        int expectedNodeIndex = 0;
+        for (final Node actual : IteratorUtils.asIterable(iterator)) {
+            assertEquals(nodes[expectedNodeIndex], actual);
+            ++expectedNodeIndex;
+        }
+
+        // insure iteration occurred
+        assertTrue(expectedNodeIndex > 0);
+
+        // single use iterator
+        for (final Node actual : IteratorUtils.asIterable(iterator)) {
+            fail("should not be able to iterate twice");
+        }
+    }
+    
+    /**
+     * creates an array of four Node instances, mocked by EasyMock.
+     * @return 
+     */
+    private Node[] createNodes() {
+        Node node1 = createMock(Node.class);
+        Node node2 = createMock(Node.class);
+        Node node3 = createMock(Node.class);
+        Node node4 = createMock(Node.class);
+        replay(node1);
+        replay(node2);
+        replay(node3);
+        replay(node4);
+
+        return new Node[]{node1, node2, node3, node4};
+}
+
+    /**
+     * Creates a NodeList containing the specified nodes.
+     */
+    private NodeList createNodeList(final Node[] nodes) {
+        return new NodeList() {
+            public Node item(int index) {
+                return nodes[index];
+            }
+            public int getLength() {
+                return nodes.length;
+            }
+        };
+    }
+
 }

Added: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/iterators/NodeListIteratorTest.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/iterators/NodeListIteratorTest.java?rev=1438955&view=auto
==============================================================================
--- commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/iterators/NodeListIteratorTest.java (added)
+++ commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/iterators/NodeListIteratorTest.java Sat Jan 26 20:14:43 2013
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2013 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.
+ */
+package org.apache.commons.collections.iterators;
+
+import java.util.Iterator;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+/**
+ * Tests the NodeListIterator.
+ */
+public class NodeListIteratorTest extends AbstractIteratorTest<Node> {
+
+    // Node array to be filled with mocked Node instances 
+    private Node[] nodes;
+    
+    // NodeListIterator supports two constructors. This flag allows to
+    // control, which constructor to use in makeObject() and makeEmtpyIterator
+    private boolean createIteratorWithStandardConstr = true;
+    
+    /**
+     * Constructor 
+     * @param testName 
+     */
+    public NodeListIteratorTest(final String testName) {
+        super(testName);
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp(); 
+
+        // Default: use standard constr.
+        createIteratorWithStandardConstr = true;
+        
+        
+        // create mocked Node Instances and fill Node[] to be used by test cases
+        Node node1 = createMock(Element.class);
+        Node node2 = createMock(Element.class);
+        Node node3 = createMock(Text.class);
+        Node node4 = createMock(Element.class);
+        nodes = new Node[] {node1, node2, node3, node4};
+        
+        replay(node1);
+        replay(node2);
+        replay(node3);
+        replay(node4);
+    }
+
+    @Override
+    public Iterator<Node> makeEmptyIterator() {
+        NodeList emptyNodeList = new NodeList() {
+            public Node item(int index) {
+                throw new IndexOutOfBoundsException();
+            }
+            public int getLength() {
+                return 0;
+            }
+        };
+        
+        if (createIteratorWithStandardConstr) {
+            return new NodeListIterator(emptyNodeList);
+        } else {
+            Node parentNode = createMock(Node.class);
+            expect(parentNode.getChildNodes()).andStubReturn(emptyNodeList);
+            replay(parentNode);
+            
+            return new NodeListIterator(parentNode);
+        }
+    }
+
+    @Override
+    public Iterator<Node> makeObject() {
+        NodeList nodeList = new NodeList() {
+            public Node item(int index) {
+                return nodes[index];
+            }
+            public int getLength() {
+                return nodes.length;
+            }
+        };
+
+        return new NodeListIterator(nodeList);
+    }
+
+    @Override
+    public boolean supportsRemove() {
+        return false;
+    }
+    
+    //-----------------------------------------------------------------------
+    public void testNullConstructor(){
+        try{
+            @SuppressWarnings("unused")
+            NodeListIterator iter = new NodeListIterator((Node) null);
+            fail("IllegalArgumentException expected!");
+        }catch(IllegalArgumentException e){
+            // expected.
+        }
+    }
+
+    /**
+     * tests the convenience Constructor with parameter type org.w3c.Node
+     */
+    public void testEmptyIteratorWithNodeConstructor(){
+        createIteratorWithStandardConstr = false;
+        testEmptyIterator();
+    }
+
+    /**
+     * tests the convenience Constructor with parameter type org.w3c.Node
+     */
+    public void testFullIteratorWithNodeConstructor(){
+        createIteratorWithStandardConstr = false;
+        testFullIterator();
+    }
+}

Propchange: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/iterators/NodeListIteratorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/iterators/NodeListIteratorTest.java
------------------------------------------------------------------------------
    svn:keywords = Id Revision HeadURL

Propchange: commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/iterators/NodeListIteratorTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain