25
Mar 12
Java DOM’s Iteration Irritation


The last time I had to interact with Java’s DOM API I noticed that it had not been updated to make use of any recent Java 5 enhancements. Specifically, the org.w3c.dom.NodeList interface does not implement java.lang.Iterable. The unfortunate side effect is ugly and error prone code.

// iteration sadness :(
final NodeList nodes = document.getChildNodes();
for(int i = 0; i < nodes.getLength(); i++) {
  final Node node = nodes.item(i);
  // use node
}

Ideally, the code could have been written utilizing Java 5′s foreach loop.

// iteration happiness which is currently impossible
for(final Node node : document.getChildNodes()) {
  // use node
}

As a workaround, I’ve written a simple wrapper class for org.w3c.dom.NodeList that makes it iterable. Hopefully, it’s useful for others.

Download: IterableNodeList.java

package com.trevorpounds.dom.util;
 
import java.util.Iterator;
import java.util.NoSuchElementException;
 
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
 
/**
 * Simple org.w3c.dom.NodeList iterable wrapper
 * that can be used with Java's foreach loop.
 *
 * @author Trevor Pounds
 */
public class IterableNodeList implements Iterable<Node>, Iterator<Node> {
   /** List of nodes */
   private final NodeList nodeList;
 
   /** List of nodes current index. */
   private int index = 0;
 
   /** Constructs iterable node list. */
   public IterableNodeList(final NodeList nodeList) {
      this.nodeList = nodeList;
   }
 
   /** {@inheritDoc} */
   public boolean hasNext() {
      return index < nodeList.getLength();
   }
 
   /** {@inheritDoc} */
   public Iterator<Node> iterator() {
      return this;
   }
 
   /** {@inheritDoc} */
   public Node next() throws NoSuchElementException {
      if(!hasNext()) {
         throw new NoSuchElementException();
      }
      return nodeList.item(index++);
   }
 
   /** {@inheritDoc} */
   public void remove() throws IllegalStateException, UnsupportedOperationException {
      throw new UnsupportedOperationException();
   }
}

Utilizing the wrapper class we can rewrite the sad code above to the following.

for(final Node node : new IterableNodeList(document.getChildNodes())) {
  // use node
}

2 comments

  1. Perfect, thanks. Pity there isn’t an apache commons library for w3c dom (afaik), getting the feeling I’m re-inventing the wheel from time to time.

  2. @Nico: It is definitely disheartening that many collection-type objects have not been updated to take advantage of this. I guess this is the best we can do. :(

Leave a comment

*