DOM木でXPATHを評価する際、JavaScriptでは
result = document.evaluate(XPATH, 対象ノード, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
のよう記述します。
第三引数をSNAPSHOTやITERATORにすると、複数の結果を取得できます。
var node = result.iterateNext();
while (node) {
hoge(node);
node = iterator.iterateNext();
}
今回、上記hoge(node)の部分で以下のように別のDOM木(document2)にnodeをコピーする処理を以下のように書きました。
document2.firstChild.appendChild(node);
するとiterateNext()で例外(invalidstate)が発生。
この方法だと、元のDOM木から当該nodeがコピーではなく移動されます。当然元のDOM木は1つnodeを失います。
問題はなぜ例外が出るのか。
こちらによると
「反復処理中に文書が変異した (文書ツリーが改変された) 場合、反復処理は無効化され、XPathResult の invalidIteratorState プロパティが true に設定され、NS_ERROR_DOM_INVALID_STATE_ERR 例外が投げられます。」
とあります。
上記のように元のDOM木が変更される可能性がある場合は、イテレータではなくスナップショットを使うのがお作法のようです。
var nss= document.evaluate(XPATH, 対象ノード, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
for ( var i=0 ; i < nss.snapshotLength; i++ )
{
document2.firstChild.appendChild(nss.snapshotItem(i));
}
この記事の本筋とは外れますが、元のDOM木の内容を保持したままnodeをコピーしたい場合はcloneNode()を使用します。元のDOM木を再利用する必要がある場合はこのような方法で対応する必要があります。
while (node) {
document2.firstChild.appendChild(node.cloneNode(true));
node = iterator.iterateNext();
}