Permalink
Browse files

Fixes #70 - getDescendants() should return Iterable as well as Iterator.

  • Loading branch information...
1 parent d8f9b79 commit 27bb470910017fed5ad1554faa6d766b4e25befb @rolfl rolfl committed Mar 16, 2012
@@ -58,6 +58,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
import org.jdom2.Content;
import org.jdom2.Parent;
+import org.jdom2.util.IteratorIterable;
/**
* Traverse all a parent's descendants (all children at any level below
@@ -67,8 +68,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* @author Jason Hunter
* @author Rolf Lear
*/
-class DescendantIterator implements Iterator<Content> {
+class DescendantIterator implements IteratorIterable<Content> {
+ private final Parent parent;
private LinkedList<ListIterator<Content>> stack = new LinkedList<ListIterator<Content>>();
ListIterator<Content> current = null;
ListIterator<Content> following = null;
@@ -79,9 +81,15 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* @param parent document or element whose descendants will be iterated
*/
DescendantIterator(Parent parent) {
+ this.parent = parent;
// can trust that parent is not null, DescendantIterator is package-private.
current = parent.getContent().listIterator();
}
+
+ @Override
+ public DescendantIterator iterator() {
+ return new DescendantIterator(parent);
+ }
/**
* Returns <b>true</b> if the iteration has more {@link Content} descendants.
@@ -60,6 +60,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
import java.util.*;
import org.jdom2.filter.*;
+import org.jdom2.util.IteratorIterable;
/**
* An XML document. Methods allow access to the root element as well as the
@@ -713,7 +714,7 @@ else if (obj instanceof DocType) {
* @return an iterator to walk descendants
*/
@Override
- public Iterator<Content> getDescendants() {
+ public IteratorIterable<Content> getDescendants() {
return new DescendantIterator(this);
}
@@ -727,7 +728,7 @@ else if (obj instanceof DocType) {
* @return an iterator to walk descendants within a filter
*/
@Override
- public <F extends Content> Iterator<F> getDescendants(final Filter<F> filter) {
+ public <F extends Content> IteratorIterable<F> getDescendants(final Filter<F> filter) {
return new FilterIterator<F>(new DescendantIterator(this), filter);
}
@@ -72,6 +72,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
import org.jdom2.ContentList.FilterList;
import org.jdom2.filter.ElementFilter;
import org.jdom2.filter.Filter;
+import org.jdom2.util.IteratorIterable;
/**
* An XML element. Methods allow the user to get and manipulate its child
@@ -1416,7 +1417,7 @@ public Element clone() {
* @return an iterator to walk descendants
*/
@Override
- public Iterator<Content> getDescendants() {
+ public IteratorIterable<Content> getDescendants() {
return new DescendantIterator(this);
}
@@ -1430,7 +1431,7 @@ public Element clone() {
* @return an iterator to walk descendants within a filter
*/
@Override
- public <F extends Content> Iterator<F> getDescendants(final Filter<F> filter) {
+ public <F extends Content> IteratorIterable<F> getDescendants(final Filter<F> filter) {
return new FilterIterator<F>(new DescendantIterator(this), filter);
}
@@ -55,7 +55,9 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
package org.jdom2;
import java.util.*;
+
import org.jdom2.filter.*;
+import org.jdom2.util.IteratorIterable;
/**
* Traverse a parent's children that match the supplied filter.
@@ -64,14 +66,14 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* @author Rolf Lear
* @param <T> The Generic type of content returned by this FilterIterator.
*/
-class FilterIterator<T> implements Iterator<T> {
+class FilterIterator<T> implements IteratorIterable<T> {
- private Iterator<?> iterator;
+ private DescendantIterator iterator;
private Filter<T> filter;
private T nextObject;
private boolean canremove = false;
- public FilterIterator(Iterator<?> iterator, Filter<T> filter) {
+ public FilterIterator(DescendantIterator iterator, Filter<T> filter) {
// can trust that iterator is not null, but filter may be.
if (filter == null) {
throw new NullPointerException("Cannot specify a null Filter " +
@@ -80,6 +82,11 @@ public FilterIterator(Iterator<?> iterator, Filter<T> filter) {
this.iterator = iterator;
this.filter = filter;
}
+
+ @Override
+ public Iterator<T> iterator() {
+ return new FilterIterator<T>(iterator.iterator(), filter);
+ }
@Override
public boolean hasNext() {
@@ -57,6 +57,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
import java.io.Serializable;
import java.util.*;
import org.jdom2.filter.Filter;
+import org.jdom2.util.IteratorIterable;
/**
* Interface for JDOM objects which are allowed to contain
@@ -202,23 +203,61 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
/**
* Returns an {@link java.util.Iterator} that walks over all descendants
* in document order.
+ * <p>
+ * Note that this method returns an IteratorIterable instance, which means
+ * that you can use it either as an Iterator, or an Iterable, allowing both:
+ * <p>
+ * <pre>
+ * for (Iterator<Content> it = parent.getDescendants();
+ * it.hasNext();) {
+ * Content c = it.next();
+ * ....
+ * }
+ * </pre>
+ * and
+ * <pre>
+ * for (Content c : parent.getDescendants()) {
+ * ....
+ * }
+ * </pre>
+ * The Iterator version is most useful if you need to do list modification
+ * on the iterator (using remove()), and for compatibility with JDOM 1.x
*
* @return an iterator to walk descendants
*/
- Iterator<Content> getDescendants();
+ IteratorIterable<Content> getDescendants();
/**
* Returns an {@link java.util.Iterator} that walks over all descendants
- * in document order applying the Filter to return only elements that
+ * in document order applying the Filter to return only content that
* match the filter rule. With filters you can match only Elements,
* only Comments, Elements or Comments, only Elements with a given name
* and/or prefix, and so on.
- * @param <E> The generic type of the descendant data
- *
+ * <p>
+ * Note that this method returns an IteratorIterable instance, which means
+ * that you can use it either as an Iterator, or an Iterable, allowing both:
+ * <p>
+ * <pre>
+ * for (Iterator<Element> it = parent.getDescendants(Filters.element());
+ * it.hasNext();) {
+ * Element e = it.next();
+ * ....
+ * }
+ * </pre>
+ * and
+ * <pre>
+ * for (Element e : parent.getDescendants(Filters.element())) {
+ * ....
+ * }
+ * </pre>
+ * The Iterator version is most useful if you need to do list modification
+ * on the iterator (using remove()), and for compatibility with JDOM 1.x
+ *
+ * @param <E> The generic type of the returned descendant data
* @param filter filter to select which descendants to see
* @return an iterator to walk descendants that match a filter
*/
- <E extends Content> Iterator<E> getDescendants(Filter<E> filter);
+ <E extends Content> IteratorIterable<E> getDescendants(Filter<E> filter);
/**
* Return this parent's parent, or null if this parent is currently
@@ -0,0 +1,75 @@
+/*--
+
+ Copyright (C) 2012 Jason Hunter & Brett McLaughlin.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions, and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions, and the disclaimer that follows
+ these conditions in the documentation and/or other materials
+ provided with the distribution.
+
+ 3. The name "JDOM" must not be used to endorse or promote products
+ derived from this software without prior written permission. For
+ written permission, please contact <request_AT_jdom_DOT_org>.
+
+ 4. Products derived from this software may not be called "JDOM", nor
+ may "JDOM" appear in their name, without prior written permission
+ from the JDOM Project Management <request_AT_jdom_DOT_org>.
+
+ In addition, we request (but do not require) that you include in the
+ end-user documentation provided with the redistribution and/or in the
+ software itself an acknowledgement equivalent to the following:
+ "This product includes software developed by the
+ JDOM Project (http://www.jdom.org/)."
+ Alternatively, the acknowledgment may be graphical using the logos
+ available at http://www.jdom.org/images/logos.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ This software consists of voluntary contributions made by many
+ individuals on behalf of the JDOM Project and was originally
+ created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
+ Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
+ on the JDOM Project, please see <http://www.jdom.org/>.
+
+ */
+
+package org.jdom2.util;
+
+import java.util.Iterator;
+
+/**
+ * An interface that represents both a <code>java.util.Iterator</code>
+ * and a <code>java.lang.Iterable</code>.
+ * <p>
+ * JDOM 1.x has a number of methods that return an Iterator. These methods
+ * would (in some conditions) be better represented as an Iterable. To maintain
+ * compatibility, and to extend the functionality of these methods in JDOM2,
+ * they have been altered to return an instance of this interface.
+ *
+ * @author Rolf Lear
+ *
+ * @param <T> The generic type of the values returned by this interface
+ */
+public interface IteratorIterable<T> extends Iterable<T>, Iterator<T> {
+ // There is no functionality added by this interface other than
+ // to combine the Iterator and Iterable interfaces.
+}
@@ -10,9 +10,12 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
+import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.filter.ElementFilter;
+import org.jdom2.util.IteratorIterable;
+
import org.junit.Test;
@SuppressWarnings("javadoc")
@@ -22,7 +25,7 @@
"legolas", "aragorn", "gimli", "boromir", "gandalf"
};
- private static final Iterator<Element> buildIterator() {
+ private static final IteratorIterable<Element> buildIterator() {
Element root = new Element("root");
Document doc = new Document(root);
for (String c : fellowship) {
@@ -57,6 +60,22 @@ public void testIteration() {
}
@Test
+ public void testIterable() {
+ int i = 0;
+ for (Content c : buildIterator()) {
+ assertNotNull(c != null);
+ assertTrue(c instanceof Element);
+ Element e = (Element)c;
+ if (i == 0) {
+ assertEquals("root", e.getName());
+ } else {
+ assertEquals(fellowship[i - 1], e.getName());
+ }
+ i++;
+ }
+ }
+
+ @Test
public void testRemoveOne() {
Iterator<Element> it = buildIterator();
assertTrue(it.hasNext());
@@ -12,6 +12,8 @@
import org.jdom2.Content;
import org.jdom2.Document;
import org.jdom2.Element;
+import org.jdom2.util.IteratorIterable;
+
import org.junit.Test;
@SuppressWarnings("javadoc")
@@ -21,7 +23,7 @@
"legolas", "aragorn", "gimli", "boromir", "gandalf"
};
- private static final Iterator<Content> buildIterator() {
+ private static final IteratorIterable<Content> buildIterator() {
Element root = new Element("root");
Document doc = new Document(root);
for (String c : fellowship) {
@@ -54,6 +56,22 @@ public void testIteration() {
}
}
+
+ @Test
+ public void testIterable() {
+ int i = 0;
+ for (Content c : buildIterator()) {
+ assertNotNull(c != null);
+ assertTrue(c instanceof Element);
+ Element e = (Element)c;
+ if (i == 0) {
+ assertEquals("root", e.getName());
+ } else {
+ assertEquals(fellowship[i - 1], e.getName());
+ }
+ i++;
+ }
+ }
@Test
public void testRemoveOne() {

0 comments on commit 27bb470

Please sign in to comment.