Entry

CGI ベースの XSLT プログラムを作ってみた

2005年12月14日

この前実験していた CGI ベースの XSLT プロセッサです。もっぱら XML の feed を読むために作ったので,名前は(受身にして)「fed」にしてみました。我ながら,中途半端というかなんというか,微妙なもんを作ってしまいました……。

これ,どういうモノかというと,

<fedConfig>
  <item id="foo">
    <sourceUri>http://example.com/index.rdf</sourceUri>
    <stylePath>rss.xsl</stylePath>
  </item>
</fedConfig>

みたいな形で,あらかじめ URI(URL)の形で登録しておいた XML と XSLT を使って,XSLT で変換した結果をプラウザ(標準出力)に出力するフィルタです。http://qune.cside.com/fed.cgi?id=foo みたいにして GET リクエストで id を渡すと変換結果を表示します。このサイトのトップページに del.icio.us ブックマークを表示しているけれど,これは MT のプラグインに fed の変換結果を埋めこんで実現しています。

どこら辺が微妙なのかというと,libxml2 と libxslt を使って C で書いたということ……。実行するにはプログラムをコンパイルする必要があるし,動的にリンクした場合は,サーバに libxml2 と libxslt のライブラリがインストールされている必要があります。自分で作っといて言うのもなんなんですけど,PHP や Perl で作った方がはるかにお手軽です。

こんなもん使う人いるのかしらん。

概要

作ったのはいいけれど,今後はあまりいぢろうと思っていないので,他の方がいぢる時のために少し詳しめに説明しておきます。fed の動きを簡単に図示すると,以下のようになります。

fed の簡単な説明

input から矢印を通って result に出てくる,といった具合に読んでください。特徴は,事前に設定しておいた id を元にして変換することです。これは,知らない所から知らない変換作業をさせられないようにするために考えてみました。

また,この図にはないけれども,他にあるめぼしい機能としては,キャッシュ機能があります。変換した結果を一定時間(デフォルトは1時間)キャッシュしておいて,キャッシュ・タイム内はこれを表示します。

CGI を実行するには,おおむね以下のような手順を踏みます。

  1. ソースをコンパイルする
  2. 設定ファイル(.fed)を書く
  3. CGI を設置する
  4. (各種ディレクトリを用意する(.fed で設定した場合))

以下,順番に説明します。

ダウンロード

実行環境

Makefile がいかにも貧弱なので,環境によってはコンパイルするのも一苦労かもしれません。あまりアテにならないと思うんですけど,うちでは次の環境を使いました。

  • FreeBSD 5.4R + gcc 3.4.2 + libxml2 2.6.20 + libxslt 1.1.14 + Apache 1.3.33

Cside のサーバ(このサイトのサーバ)は Debian 3 が動いているんですけれど,ここで動いているのは少し前に作ったモノで,配布しているモノとは異なります。多分動くと思うけれど,Linux での動作検証はできていません。

コンパイル

コンパイルするには Makefile のあるディレクトリ(src/)で

% make

とします。無事に make が通ると,fed.cgi という実行ファイル(CGI の本体)ができるはずです。なお,Makefile で作られる実行ファイルは shared object を使うので,外部に libxml2 と libxslt のライブラリがインストールされていないと実行できません。

また,UTF-16 と UTF-8 以外の XML を扱う場合は,libxml2 と libxslt を iconv 付きでコンパイルする必要があります。

設定ファイルを書く

基本の書き方

fed の設定ファイルはプログラムと同じディレクトリにある .fed という XML ファイルです。基本はこんな感じで書きます。

<fedConfig>
  <item id="foo">
    <sourceUri>http://example.com/index.rdf</sourceUri>
    <stylePath>rss.xsl</stylePath>
  </item>
</fedConfig>

fedConfig の親要素に1つ以上の item 要素が必要です。item 要素の必須要素(属性)は,以下の通り。

id
属性(attribute)です。GET メソッドで呼び出すときの目印です。fed は % エンコーディングをデコードしないので,%XX 形式で指定しなくちゃいけない文字列(日本語等)は使えません。なお,SYSTEM という文字列(後述)は特別な id で予約されています。
sourceUri
子要素(child element)です。変換元 XML の URI を指定します。外部の URI はもちろん,相対 URI も受け付けます。
stylePath
子要素(child element)です。変換元の XML に適用するスタイルシートを指定します。ネット経由で取得することはできないので,ローカルの path を指定します。

なお,変換を一度実行すると,item 要素に accessTime という属性が新たに作られます。この値はキャッシュの間隔を計る際に使われるので,妙なもんができたといって消さないでください。

その他の設定要素

item の中には sourceUri と stylePath の他に以下の要素を含むことができます。

styleBase
stylePath の親ディレクトリを指定できます。これを使ってスタイルシートを特定の場所にまとめられます。ディレクトリを表わすために,必ず末尾にスラッシュ(/)をつけます。省略したときはカレントディレクトリ(./)内のスタイルシートが使われます。
cachePath
キャッシュファイルの path を指定します。省略したときは id が path として使われます。
cacheBase
cachePath の親ディレクトリを指定できます。これを使ってキャッシュファイルを特定の場所にまとめられます。styleBase と同じく末尾のスラッシュは消さないください。省略したときはカレントディレクトリ(./)にキャッシュが保存されます。
cacheTimeout
キャッシュを保持する時間を秒単位で指定します。デフォルトは 3600(1時間)です。0 を指定するとキャッシュしません。
contentType
HTTP ヘッダの Content-Type を指定します。fed は指定された Content-Type が妥当なものであるか検証しません。デフォルトは text/plain です。

SYSTEM ID

SYSTEM という id は設定ファイルを解釈する際に必ず読まれる ID です。例えば,

<fedConfig>
  <item id="SYSTEM">
    <styleBase>style/</styleBase>
    <cacheBase>cache/</cacheBase>
  </item>
  <item id="foo">
    <sourceUri>http://example.com/index.rdf</sourceUri>
    <stylePath>rss.xsl</stylePath>
  </item>
</fedConfig>

とすると,foo の stylePath である rss.xsl は style/rss.xsl を指すことになります。同様に,foo の cachePath も(./foo ではなく)cache/foo を指します。これを利用して,設定ファイルに共通の設定をあらかじめまとめておくことができます。

設定ファイルのその他もろもろ

設定ファイルは XML なので特殊な文字はエンティティで表現する必要があります。URL でよく使う & も &amp;と書く必要があるので注意が必要です。面倒なんですけど,どうしようもないです,はい。

また,ひとつの item に同一の子要素があったり,SYSTEM な item と通常の item とで異なる設定をしている場合は,後で指定された設定が前の設定を上書きします。また SYSTEM な id を付けた item は設定ファイルを解釈する際に必ず読まれるけれども,優先関係は他の item と同じです。したがって,SYSTEM な item に設定した内容であっても,後に他の item で書かれた設定と衝突すれば上書きされます。

もうひとつ。sourceUri は中の空白を除去して連結します。これを利用すれば長い URI を複数の行に分割したり,インデントを付けたりすることができます。具体的にはこんな感じ。

<sourceUri>
      http://webservices.amazon.co.jp/onca/xml?
        Service=AWSECommerceService&amp;
        SubscriptionId=xxxxxxxxxxxxxxxxxxxx&amp;                       
        ResponseGroup=Medium&amp;
        ItemPage=1&amp;
        AssociateTag=xxxx&amp;
        Operation=ListLookup&amp;
        ListType=WishList&amp;
        ListId=xxxxxxxxxxxx&amp;
        Version=2005-07-26
</sourceUri>

使い方

コマンドラインから使う

fed はオプション引数を渡して起動すると,コマンドラインのプログラムとして動きます。

-c <id>
コマンドラインから XSLT 変換します。
-i <id>
設定ファイル(.fed)から id の設定を読み出して表示します。設定ファイルが well-formed な XML かどうかはもちろん,表示内容から正しく設定されているかどうかもチェックできます。

CGI で使う

fed.cgi と .fed を同じ場所に置いて,.fed で指定した場所にスタイルシートを置けば設置完了です。キャッシュファイルのディレクトリにデフォルトとは別の場所を指定した場合は,あらかじめディレクトリを作っておいてください。

設置したら URL に GET メソッドでアクセスできます。例えば CGI を http://example.com/fed.cgi に設置した場合は,

http://example.com/fed.cgi?id=foo

のようにします。設定ファイルで設定した id から XML ソースと XSLT スタイルシートを読み出して変換した結果を出力します。なお,GET メソッドに使われる文字列は %XX 形式の URL エンコーディングをデコードしません。したがって id に日本語等の文字を使うことはできません。

Movable Type のプラグインに組み込む

CGI の変換結果を MT に組み込むためのプラグインも作ってみました。PHP ベースの Movable Type(ダイナミック・パブリッシング)で使えます。

プラグインは配布物に添付してある function.MTFed.php です。設置する前に少しだけ準備が必要です。

  1. function.MTFed.php の $uri 変数を CGI 設置した場所(URL)に書き換える
  2. 書き換えたら,このファイルを ${MTDIR}/php/plugins 以下にコピーする

ここまでできたら,次のようにして呼び出すことができます。

<$MTFed id="foo"$>

エラーの処理

エラーが起きた場合,fed はブラウザ(標準出力)に [FATAL ERROR] とだけ表示します。エラーメッセージは,CGI のある場所と同一のディレクトリに error.log として保存されるので,これを読んでエラーを特定してください。あたりまえだけれども,fed が捕捉できなかったエラーはサーバ任せです。今のところ経験していないけれど,場合によっては core を吐くかもしれません。

ライセンス

BSD ライセンス(無保証・配布自由・要著作権者表示)で配布します。詳しくは添付のライセンス条項をご覧ください。

作ってみて思ったこといろいろ

ここから先は戯れ言。

  • C で書いたのは,単に libxml2 と libxslt を生で使ってみたかっただけだったからです。多分 Perl や PHP で書いたら数百行で済んじゃうようなプログラムなんだろうなぁ……。
  • もともと RSS feed のような XML 文書を変換すること考えていたんですけど,AWS のように REST なウェブサービスとは案外相性がいい感じです。
  • 設定ファイルの解析は XSLT の document() や id() に任せた方がシンプルなのかもなぁー……とか思ったけれど,手は付けないことにします。
  • エラーはまだ拾いきれていないかもしれません。こういう時に try のありがたみが分かるってもんです。
Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN