X-0016 テンプレートで独自の RDF ファイルを使う

はじめに

RDF データソースとテンプレートを使ってメニューなどの XUL 要素を自動生成する方法については、 XUL Tutorials邦訳)に解説があります。ただ、 Mozilla が使っている search.rdf や downloads.rdf などのようなユーザープロファイルディレクトリ内の RDF ファイルを自分で用意して使う場合には、少し面倒な手順を踏む必要があります。

コンテキストメニュー拡張でも、 extensions.rdf というファイルを使っています。ここでは、コンテキストメニュー拡張で実際に使用している処理を紹介しようと思います。

データソースの動的設定

ユーザープロファイル内に置いたファイルの URIURL は、 Mozilla がインストールされた環境によって変わります。テンプレートのデータソースとしてそういったファイルを使う場合、アプリ起動時にファイルの URIURL を調べて、要素が持つデータソースのリストに新しいデータソースとして登録する必要があります。

テンプレートを使う際には、テンプレートを含める XUL 要素の datasources 属性にデータソースの URIURL を書いておくことになります。しかし、この方法ではデータソースの位置をあらかじめ決めておかなければなりません。ユーザープロファイルディレクトリのように環境によって URIURL が変わるディレクトリに RDF ファイルを置く場合、決め打ちの datasources 属性では対処できないのです。

かといって、 DOM を使って datasources 属性を書き換えても駄目です。 datasources の記述は XUL ファイルが読み込まれた段階で解釈され、その後はもう参照されないため、 DOM で属性値をいじっても意味がないのです。

それでは、以下のようなテンプレートに対して、ユーザープロファイルディレクトリに置いた original.rdf というファイルをデータソースとして登録するケースを例に取ってみましょう。

<menupopup id="originalMenu"
    datasources="rdf:null"
    ref="urn:original:root">
    <template>
        <rule>
            <menuitem uri="rdf:*"
                label="rdf:http://white.sakura.ne.jp/~piro/rdf#Name"/>
        </rule>
    </template>
</menupopup>

rdf:null とは、データソースを動的に変更する場合に使うダミーの組み込みデータソースです。

RDF ファイルの位置を調べる

まず、 original.rdf の URIURL を得ます。内部名「 ProfD 」を使ってプロファイルディレクトリの URIURL を取得し、その末尾に「 original.rdf 」と付け加えましょう。

なお、初回起動時などで RDF ファイルが存在しない場合だと、 RDF データソースの内容を変更しても、ファイルとして自動保存されないことがあります。パッケージ内にあらかじめ RDF ファイルの雛型を用意しておき、初回起動時にファイルの保存を使ってプロファイルディレクトリにコピーしておくなどの対策をとることで、この問題を回避することができます。

データソースを登録する

URIURL がわかったら、 nsIRDFService の GetDataSource メソッドで URI からデータソースオブジェクトを取得し、要素のデータベースにデータソースを登録します。

const RDF = Components.classes['@mozilla.org/rdf/rdf-service;1']
                      .getService(Components.interfaces.nsIRDFService);
var dsource = RDF.GetDataSource(dsource_uri);

var node    = document.getElementById('originalMenu');
node.database.AddDataSource(dsource);

あとは、テンプレートから要素を再生成すれば OK です。

node.builder.rebuild();

余談。 RDF ファイルの動的な変更を XUL に反映させたい場合にも、 rebuild() メソッドを使います。

コンテキストメニュー拡張では、この一連の処理を関数としてまとめておき、 onload イベントで自動処理しています。