今日の罠

下のような構造のXMLファイルがありました。

<root>
  <fields>
    <hoge />
    <fuga />
  </fields>
</root>

fields以下の要素を消そうと思い下のようなコードを書いてはまりました。

NodeList nl = doc.getElementsByTagName("fields");
Node fields = nl.item(0);

NodeList childs = fields.getChildNodes();
for(int i=0; i<childs.getLength(); i++) {
  fields.removeChild(childs.item(i));
}

上記コードを走らせると、エラーは特に出ません。でもfieldsの子ノードはうまく消えません。丸々残ったり、一つだけ残ったりします。

childsの構造を変えているのだからリアルタイムでgetChildsNodes()とgetLength()の結果が変わるという当たり前の仕様なのです。が、コレクションクラス等で同じことをやるとConcurrentModificationExceptionが発生しますし、他の状況でもたいがいArrayIndexOutOfBoundsException等が起きます。エラーが特に出なかったのでうまくいったと思い込んで発覚が遅れました。

エラー情報に頼る行き当たりばったりプログラミングは良くない習慣だということを再認識。

結局下のようにしました。

Node n;
while((n = fields.getFirstChild) != null) {
  fields.removeChild(n);
}