I want to iterate through a NodeList
using a for-each loop in Java. I have it working with a for loop and a do-while loop but not for-each.
Node
I know it is late to the party, but...
Since Java-8 you can write @RayHulha's solution even more concisely by using lambda expression (for creating a new Iterable) and default method (for Iterator.remove):
public static Iterable<Node> iterable(final NodeList nodeList) {
return () -> new Iterator<Node>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < nodeList.getLength();
}
@Override
public Node next() {
if (!hasNext())
throw new NoSuchElementException();
return nodeList.item(index++);
}
};
}
and then use it like this:
NodeList nodeList = ...;
for (Node node : iterable(nodeList)) {
// ....
}
or equivalently like this:
NodeList nodeList = ...;
iterable(nodeList).forEach(node -> {
// ....
});
The validated solution is very useful, but here I share an improved solution based on the valid one, this helps you iterate as well, but easy to use, and secure:
public class XMLHelper {
private XMLHelper() { }
public static List<Node> getChildNodes(NodeList l) {
List<Node> children = Collections.<Node>emptyList();
if (l != null && l.getLength() > 0) {
if (l.item(0) != null && l.item(0).hasChildNodes()) {
children = new NodeListWrapper(l.item(0).getChildNodes());
}
}
return children;
}
public static List<Node> getChildNodes(Node n) {
List<Node> children = Collections.<Node>emptyList();
if (n != null && n.hasChildNodes()) {
NodeList l = n.getChildNodes();
if (l != null && l.getLength() > 0) {
children = new NodeListWrapper(l);
}
}
return children;
}
private static final class NodeListWrapper extends AbstractList<Node> implements RandomAccess {
private final NodeList list;
NodeListWrapper(NodeList l) {
list = l;
}
public Node get(int index) {
return list.item(index);
}
public int size() {
return list.getLength();
}
}
}
Usage:
for (Node inner : XMLHelper.getChildNodes(node)) { ... }
Thanks @Holger.
There are ready to use or copypaste iterator implementations in org.apache.commons.collections4.iterators.NodeListIterator and com.sun.xml.internal.ws.util.xml.NodeListIterator
.
public static Iterable<Node> iterable(final NodeList n) {
return new Iterable<Node>() {
@Override
public Iterator<Node> iterator() {
return new Iterator<Node>() {
int index = 0;
@Override
public boolean hasNext() {
return index < n.getLength();
}
@Override
public Node next() {
if (hasNext()) {
return n.item(index++);
} else {
throw new NoSuchElementException();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
Adding the happy little kotlin version for sience:
fun NodeList.forEach(action: (Node) -> Unit) {
(0 until this.length)
.asSequence()
.map { this.item(it) }
.forEach { action(it) }
}
One can then use it with nodeList.forEach { do_something_awesome() }
As NodeList
is just an interface, you could create a class which would implement both NodeList
and Iterable
, in order to iterate through it.