reflux flow > Javaのfor-eachループでNodeListを処理する
NodeListをfor-eachループで扱えるようにする。
Java 1.5(J2SE 5.0)では、コレクションの反復処理の記述を補助するためにfor-eachループが追加されました。for-eachループを用いるとjava.util.Iteratorによる繰り返し処理の記述が簡潔になります。
/* for-eachループを使用しない場合 */
void printListItem(List<String> list) {
for (Iterator<String> i = list.iterator(); i.hasNext(); ) {
String item = i.next();
System.out.println(item);
}
}
/* for-eachループを使用した場合 */
void printListItem(List<String> list) {
for (String item : list) {
System.out.println(item);
}
}
for-eachループの対象になるのは、java.lang.Iterableインタフェースを実装したクラスです(Iteratorインタフェースを実装したクラスも必要です)。残念なことに、org.w3c.dom.NodeListインタフェースはIterableインタフェースを実装していません。そこで、IterableインタフェースとIteratorインタフェースを実装したクラスを自作して、NodeListをfor-eachループで扱えるようにします。
まずはIterableインタフェースを実装したIterableNodeListクラスです。NodeListインタフェースも実装していますが、for-eachループを利用するだけなら実装する必要はありません(IterableNodeListという名前しか思いつかなかったのでNodeListも実装してしまいました)。
/* IterableNodeList.java */
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class IterableNodeList implements Iterable<Node>, NodeList {
private NodeList nodeList;
public IterableNodeList(NodeList nodeList) {
this.nodeList = nodeList;
}
public java.util.Iterator<Node> iterator() {
return new NodeListIterator(nodeList);
}
public Node item(int index) {
return nodeList.item(index);
}
public int getLength() {
return nodeList.getLength();
}
}
次にIteratorインタフェースを実装したNodeListIteratorクラスです。
/* NodeListIterator.java */
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class NodeListIterator implements Iterator<Node> {
private NodeList nodeList;
private int index = 0;
private Node cache = null;
public NodeListIterator(NodeList nodeList) {
this.nodeList = nodeList;
}
public boolean hasNext() {
return index < nodeList.getLength();
}
public Node next() {
cache = nodeList.item(index++);
if (cache == null) throw new NoSuchElementException();
return cache;
}
public void remove() {
if (cache == null) throw new IllegalStateException();
cache.getParentNode().removeChild(cache);
cache = null;
index--;
}
}
removeメソッドにはノードを削除する処理を書きましたが、for-eachループではremoveメソッドを利用しないのでUnsupportedOperationExceptionを投げるだけにすることもできます。
下の例のようにNodeListオブジェクトをIterableNodeListコンストラクタに渡します。
/* 例: 子ノードを出力する */
void printChildNodes(Node parent) {
for (Node child : new IterableNodeList(parent.getChildNodes())) {
System.out.println(child);
}
}