JavaScript: document.evaluateの第2引数に特定のノードを指定したときは頭に/を使ってはいけない
XPath で "//" を使う時は気をつけようという話 « のっち大好きの会 分室
第2引数を指定しても、頭に/をつけると無関係にルートノードが選択される。
document.evaluate('/', document.getElementById("menu"), null, 7, null).snapshotItem(0).nodeName
// -> "#document"
document.evaluate('//*', document.getElementById("menu"), null, 7, null).snapshotItem(0).nodeName
// -> "HTML"
document.evaluate('//*', document.getElementById("menu"), null, 7, null).snapshotLength
// -> 619
第2引数は単にドキュメント中の初期位置を指定するだけで、サブグラフを与えたりするわけではない。
document.evaluate('../*', document.getElementById("menu"), null, 7, null).snapshotItem(0).nodeName
// -> "DIV"
とか普通にできる。
第2引数の指定を生かすには
- 頭に
.をつける - 頭に
/をつけずに、decendant::ほかを使う
などする。
document.evaluate('self::*', document.getElementById("menu"), null, 7, null).snapshotItem(0).nodeName
// -> "DL"
document.evaluate('descendant::*', document.getElementById("menu"), null, 7, null).snapshotItem(0).nodeName
// -> "DT"
document.evaluate('.//*', document.getElementById("menu"), null, 7, null).snapshotLength
// -> 146
今まで何となく自作$X関数とかで
document.evaluate(xexp, root || document, null, 7, null);
とかやってたけど、この辺も注意が必要。
$X('//a', node)はダメで、$X('.//a', node)ならOKとか、そんな感じ。
というか、頭に/をつけること自体に警戒すべきか。
*、node()、text()、comment()
XML Path Language (XPath) # 2.3 ノードテスト
*- 主ノード型のノードであればどのノードでも真
node()- どのような型のノードでも真
text()- どのテキストノードでも真
comment()- すべてのコメントノードで真
*のほうがnode()よりも限定的。*⊂node()。
document.evaluate('//*', document, null, 7, null).snapshotLength
// -> 655
document.evaluate('//node()', document, null, 7, null).snapshotLength
// -> 1521
探索対象をXHTML要素に限定できる場合は、node()よりも*を使ったほうが速そう。