evaluate

faviconize を書いてるときにいろいろ検証してみたんだけど JavaScript の evaluate はクセがありすぎるなぁというハナシ。かなり振り回された。っていうか振り回されてる最中。

まず document.evaluate がないとか言われる件。ハマってかなり時間くったんだけどググったらすぐに http://d.hatena.ne.jp/swdyh/20071219/1198061334 が出てきたのでおれ涙目。参考にして自分でも書いてみたんだけど以下のような横着な書き方でも動作するのは確認した。参考にしたっつーかまんまなんだけどね。写経すると理解度も違うんだよ。

// stuff functions ------------------------------------------------------
function $f(query, node) {
    node = node || document;
    var result = (node.ownerDocument || node).evaluate(
        query,
        node,
        null,
        XPathResult.FIRST_ORDERED_NODE_TYPE,
        null
    );
    return result.singleNodeValue ? result.singleNodeValue : null;
}

function $s(query, node) {
    node = node || document;
    var result = (node.ownerDocument || node).evaluate(
        query,
        node,
        null,
        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
        null
    );
    var nodes = [];
    for(var i=0 ; i<result.snapshotLength ; ++i)
        nodes.push(result.snapshotItem(i));
    return nodes;
}

次。 evaluate の第一引数に指定する xpathExpression と第二引数に指定する contextNode の関係について ( via: http://developer.mozilla.org/Ja/Introduction_to_using_XPath_in_JavaScript ) 。結論は http://mayokara.info/note/view/228 に書いてあるとおり contextNode が指定するのはファイルシステムでいう current であって評価対象は document 全体ということらしい。 contextNode 以下が評価対象だと思い込んでいてヒットするノードが多すぎて混乱していた時期がありました。

いやでも

contextNode: xpathExpression を評価する対象となる文書内のノードを指定します。指定されたノードの全ての子ノードに対しても評価が行われます。もっともよく指定される値は document です。

Introduction to using XPath in JavaScript | MDN

と書かれてたら普通「 contextNode に指定したノード以下が評価対象になる」って思うよな…。いやまて「全ての子ノードに対して『も』評価が行われます。」ってそういうことなのか… ? 英語は

contextNode: A node in the document against which the xpathExpression should be evaluated, including any and all of its child nodes. The document node is the most commonly used.

Introduction to using XPath in JavaScript - JavaScript | MDN

だからやっぱり「 contextNode に指定したノード以下が評価対象になる」って書いてあんじゃねぇか ( 逆ギレ乙 ) !! サイ本にもろくな記述がなかったのでホント勘弁してくださいよ的な感じ。あーでも XPath 的には context と言ったら current node のことなのかな。

とかなんとか。