Firefox拡張機能のJavaScript内でXPathを使用する

Firefox拡張機能を作成する上でXPathを使いたくなった。少し調べたので、以下メモ。

サンプルコード

Wikipediaの日本語版から英語版に移動するサンプルコードは以下。英語版のURLを取ってくるのにXPathを使用している。

var switchWikipedia = function() {
    var targetHost =  "ja.wikipedia.org";
    var xpath = '//li[@class="interwiki-en"]/a';

    // 現在のタブのnsIURI, documentオブジェクト (FUELを使用している)
    var currentUri = Application.activeWindow.activeTab.uri;
    var currentDocument = Application.activeWindow.activeTab.document;

    if (currentUri.host == targetHost) {
        // ここでXPathを使っている
        var nodes = currentDocument.evaluate(
            xpath, currentDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);

        var nextUri = nodes.snapshotItem(0).getAttribute("href");
        if (nextUri) {
            // 新しいnsIURIオブジェクトを作成する
            var newNsIURI = Components.classes["@mozilla.org/network/io-service;1"]
                .getService(Components.interfaces.nsIIOService)
                .newURI(nextUri, null, null);

            // 現在のタブに新しいページを読み込む
            Application.activeWindow.activeTab.load(newNsIURI);
        }
    }
};

解説

まずポイントは、documentオブジェクトを取得するところ(7行目)。タブブラウザなので開いているページはたくさんあって、どのdocumentなのか指定しないとうまく動かない*1

もう一つのポイントは、document.evaluateメソッドの戻り値だ(このコードで言うとnodes)。

この戻り値は、第4引数によってどんな型にするか指定できる。やたら種類があるが、とりあえずXPathResult.ORDERED_NODE_SNAPSHOT_TYPEを指定しておけば問題ないだろう。

これで戻り値としてXPathにマッチするノードが全部取得できる。この例の様にsnapshotItemメソッドで各ノードを参照できるし、snapshotLengthプロパティでノード数を取得できる。

この戻り値に関してはMDCのXPathResultページが参考になる、はずなのだが、今のところ各プロパティ、メソッドの説明はほとんどない(ので、あんまり役に立たない)。

ノードが取得できたら、後はやりたい放題だ。element - DOM | MDNに書いてあることはだいたいできる(と思う)ので、いろいろ試してみよう。

*1:2008/11/28 追記: FUELを使用しない場合、content.documentで現在開いているタブのdocumentオブジェクトを取得できる。こちらの方が簡単で良いだろう。