JavaScriptでevaluate

基本はCSSでquerySelector派なのだけどXPathでevaluateも使う。しかしたまにしか使わないので毎回引数を必死に調べる羽目になるので覚え書きとしてIntroduction to using XPath in JavaScriptを参考にしてメモを残しておく。

var xpathResult = document.evaluate(xpathExpression, contextNode, namespaceResolver, resultType, result);

引数1:xpathExpression

XPathの基本的な書き方は省略。使い方がよく分からないのがXPathの関数群。このエントリを書くにあたってちょっと真面目に調べてみた。例えばclassにentryを含むdivノードを抽出する時はどうすればいいか。

//div[@class='entry']

これはclassがentryであるdivノードだ。含むではない。よく見ると関数群にcontainsというのがある。これを使えばいいのか。結論から先に書くとこうなる。

//div[contains(@class, 'entry')]

つまりだ。[ ]内には結果がbooleanとなる条件式を与えればいい訳だ。先に書いたのもclassがentryに等しいという条件式だ。よく考えれば当たり前の事なんだけどこれで関数群の使い方も理解できる。

引数2:contextNode

最後まで理解出来なかった地味に分かりづらい引数がこれ。どこの解説サイトでもdocumentを指定しておけばいいと書いてあるので余計。

var nodes = document.querySelectorAll("div#container>div");

で取得できるNodeListをforEachでループしてevaluateを使いたい時は一体どうすればいいか。例えばdivの中にあるaタグのhrefが欲しいとしよう。

Array.prototype.slice.call(nodes).forEach(function (node) {
	var link= document.evaluate("//a/@href", node, null, 2, null);
});

こんな感じだろうか。やってみれば分かるが全て1番目のdivノード内のaタグが返ってくる。要するにこのcontextNodeという引数は検索対象のノードを指定する訳ではない。単に検索の起点となるノードを指定するだけ。なのでこのXPathの書き方だと結局document内の全てのaタグが対象となる。なのでこの場合XPathはこう書く。

.//a/@href

違いは先頭に「.」が付いた事。self軸を指定してやらないといけない。Referenceにはっきりそう書いといてよMozillaさん。

namespaceResolver

HTMLの場合は必要ないので書く事なし。XMLでevaluateする場合は必要になるがその時にまた書こう。

resultType

理解し辛い事は全くないが毎回何だったか調べる引数。

定数 戻り値で使用するプロパティ及びメソッド
ANY_TYPE 0 単純型3種もしくはiterateNext()。snapshotItem(i)は使えない。
NUMBER_TYPE 1 numberValue
STRING_TYPE 2 stringValue
BOOLEAN_TYPE 3 booleanValue
UNORDERED_NODE_ITERATOR_TYPE 4 iterateNext()
ORDERED_NODE_ITERATOR_TYPE 5 iterateNext()
UNORDERED_NODE_SNAPSHOT_TYPE 6 snapshotItem(i), snapshotLength
ORDERED_NODE_SNAPSHOT_TYPE 7 snapshotItem(i), snapshotLength
ANY_UNORDERED_NODE_TYPE 8 singleNodeValue
FIRST_ORDERED_NODE_TYPE 9 singleNodeValue

result

既存のXPathResultオブジェクトを再利用する場合はそれを指定するらしいが通常そんな事しないのでnull。