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
If the current DOM element is removed (via JavaScript) while iterating a NodeList (created from getElementsByTagName() and maybe others), the element will disappear from the NodeList. This makes correct iteration of the NodeList more tricky.
public class IteratableNodeList implements Iterable {
final NodeList nodeList;
public IteratableNodeList(final NodeList _nodeList) {
nodeList = _nodeList;
}
@Override
public Iterator iterator() {
return new Iterator() {
private int index = -1;
private Node lastNode = null;
private boolean isCurrentReplaced() {
return lastNode != null && index < nodeList.getLength() &&
lastNode != nodeList.item(index);
}
@Override
public boolean hasNext() {
return index + 1 < nodeList.getLength() || isCurrentReplaced();
}
@Override
public Node next() {
if (hasNext()) {
if (isCurrentReplaced()) {
// It got removed by a change in the DOM.
lastNode = nodeList.item(index);
} else {
lastNode = nodeList.item(++index);
}
return lastNode;
} else {
throw new NoSuchElementException();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public Stream stream() {
Spliterator spliterator =
Spliterators.spliterator(iterator(), nodeList.getLength(), 0);
return StreamSupport.stream(spliterator, false);
}
}
Then use it like this:
new IteratableNodeList(doc.getElementsByTagName(elementType)).
stream().filter(...)
Or:
new IteratableNodeList(doc.getElementsByTagName(elementType)).forEach(...)