1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

xmlDocument.Evaluate()におけるSnapshotとIteratorの動作の違い(Javascript)

Last updated at Posted at 2018-10-17

DOM木でXPATHを評価する際、JavaScriptでは

evaluateメソッドを使う
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木を再利用する必要がある場合はこのような方法で対応する必要があります。

元のDOM木を保持
while (node) {
    document2.firstChild.appendChild(node.cloneNode(true));
    node = iterator.iterateNext();
}	
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?