Cocoonを使って、XML文書をWebブラウザの要求によって自動的にHTML文書(など)
に変換しながら配信する簡単なシステムを作ってみます。
まずは対象となるXML文書やXSLスタイルシートやその置き場所ですが、
ここではCocoonのディレクトリ(先の例だとc:/usr/javadeploy/cocoon、
以後、$COCOON_HOMEと呼ぶことにします)
以外の場所に自分のアプリケーションを構築することにします。
その場所をここではc:/usr/javadeploy/common/xmlと決め、
このディレクトリにお題として次の2つのファイル、
shiten.xmlと
shiten.xslを置きます。
このディレクトリを、以後 $DOC_HOME と書くことがあります。
サイトマップファイル sitemap.xmapの編集 |
次に、
Cocoonではsitemap.xmapというファイルをこのようなディレクトリごとに作ります。
.xmapという拡張子を見るとなにやらふがふがですが、
中身はXML文書で、普通にテキストエディタなどで編集できます。
この中身は、最初ですから$COCOON_HOME/samplesにあるsitemap.xmapをぱくって、
これを編集します。それがこれです。
と料理番組のようにできたものを出してくるわけですが…
<map:match pattern="shiten.html">
<map:generate src="shiten.xml"/>
<map:transform src="shiten.xsl"/>
<map:serialize/>
</map:match>
|
書き加える部分はここです。これすなわち、
shiten.htmlというURLが要求された場合、
このディレクトリにあるshiten.xmlをshiten.xslによって変換したものを出力するように、
という指令が出ているわけです。
…わけですが、ここがCocoonの面白くて、とても役立つところです。
つまり要求されるURLに対応するHTML文書は、最初から存在する必要はなく、
要求されるURLによって、様々なXML+XSLの組み合わせでXSLT変換をかけることができるのです。
例えば、同じXML文書を題名だけサマリー表示したり、全部表示したり、
と異なる表示方法で提供したい場合には、
それぞれ異なるURLに異なるXSLスタイルシートでマッピングを書いておけばいいのです。
ちなみに上記では、
generator、transformer、serializerのタイプがそれぞれ省略されていますが、
冗長に書けば
<map:match pattern="shiten.html">
<map:generate src="shiten.xml" type="file"/>
<map:transform src="shiten.xsl" type="xslt"/>
<map:serialize type="html"/>
</map:match>
|
となります。つまり上のsitemap.xmapで
<map:generators default="file"/>
<map:transformers default="xslt"/>
<map:serializers default="html"/>
|
となっている部分で、それぞれのデフォルトのタイプを事前に書いているので、
個々のパターンの記述に対しては省略できるのです。
ちょっと注意ですが、XSLT transformerのsrc=属性は省略できないようです。
つまり、XML文書内のxml-stylesheetタグによって、
XSLスタイルシートを指定する方法は、Cocoon2では使えないみたいです。
逆に、複数のXML文書を同一のXSLスタイルシートで整形表示したい場合には、
ワイルドカードを使うことができます。
<map:match pattern="**.html">
<map:generate src="{1}.xml"/>
<map:transform src="shiten.xsl"/>
<map:serialize/>
</map:match>
|
ここで使っているmatcherのタイプはwildcardです。
(type属性で指定していませんが、sitemap.xmapの冒頭のデフォルト設定を確認して下さいね)
wildcard URI matcherがサポートしているワイルドカードには
*と**があります。
*は通常のパスにおけるそれと同じく、
ディレクトリ階層を越えない任意数の任意の文字にマッチします。
**はさらに、ディレクトリ階層を越えた任意の文字にマッチします。
例えば、**.xml というと、abc.xmlにも、 def/abc.xml にも、
ghi/def/abc.xml にもマッチします。
{1}というのは、matcherのパターン中のワイルドカード(*か**)
に一致した部分の文字列に置き換えられます。
1つのパターンにワイルドカードは複数指定でき、
左から最初のワイルドカード文字に一致する部分が{1}、
2番目のそれに一致するそれが{2}、以下も同様、という具合です。
$COCOON_HOME/sitemap.xmapの編集 |
ここまで準備ができたら、
次に、Cocoonにこのディレクトリの存在を知らせる必要があります。
これは、sitemap.xmapの中で親玉にあたる、
$COCOON_HOME/sitemap.xmap というファイルを編集します。
このファイル、たいへんに巨大でどこをどうしていいやら、
という感じですが、とりあえず、上から5分の2のあたりにある、
「==== Pipelines ====」
という行を探します。その次に、
<map:pipelines>というタグがあるので、その中に次のように書き加えます。
<map:pipelines>
<map:pipeline>
<map:match pattern="mysamples/**">
<map:mount uri-prefix="mysamples"
src="file:/c:/usr/javadeploy/common/xml/sitemap.xmap"
check-reload="yes" />
</map:match>
</map:pipeline>
... (map:pipeline設定が続く)
|
途中にmountという文字が見えますか。これまた面白いところで、
Cocoonでは、UNIXファイルシステムのマウントと同じように、
要求されたURLのパターンによって、そこから下のパスを特定のディレクトリに割り付ける指定が可能です。
上記の場合、mysamplesというパスが指定されると、
その部分以下はC:/usr/javadeploy/common/xml/sitemap.xmap
というサイトマップファイルの設定を読み、
C:/usr/javadeploy/common/xml
以下のディレクトリからコンテンツを読み出す「マウント」をかけています。
このサイトマップファイル名が
「sitemap.xmap」の場合には、sitemap.xmapは省略できるようです。
また、check-reload="yes" にしておくと、
サーブレットコンテナが稼動中の状態でサイトマップファイルを変更した際に、
次回アクセス時に自動的にサイトマップファイルを読み直してくれるので、
サイトマップを変更するたびにサーブレットコンテナを再起動させる必要はありません。
これはとても便利なので開発中はゼヒ指定しておきましょう。
$COCOON_HOME/sitemap.xmap の編集が済んだら、
実際に「http://localhost:8080/cocoon/mysamples/shiten.html」
にアクセスしてみます。
shiten.xmlとshiten.xslが合成されて、HTML文書がテーブル形式で出てくれば大成功です。
さて、上記のマウント機能を使うと、$COCOON_HOMEとは別のディレクトリを、
あたかも$COCOON_HOMEのサブディレクトリのように(Web上では)
見せることができるわけですが、そのまま何もしないと、
この機能は一階層限りであります。
つまりマウントされたディレクトリ
(あんまり聞こえはよくないですが、このページでは便宜的に隔離ディレクトリと呼びます
(-_-;) )
のサブディレクトリは、Cocoonからは見えません。
そこで、隔離ディレクトリのサブディレクトリも隔離ディレクトリの下にあるように見せるためには、
隔離ディレクトリのsitemap.xmapに次のようなブロックを追加します。
<map:match pattern="*/**">
<map:mount uri-prefix="{1}" src="{1}/" check-reload="yes"/>
</map:match>
|
追加というか、Cocoonのsamplesディレクトリのsitemap.xmap
には末尾のあたりを注意深く見ているとこの記述が見つかるはずです。
既にあればそれでOKです。
よく使われる基本的なテクニックとして、ディレクトリにアクセスされたときに、
自動的にindex.htmlの内容を要求するように(生成して)返すようにしてみます。
これはCocoonでは「リダイレクト」の概念で行います。
<map:match pattern="">
<map:redirect-to uri="index.html"/>
</map:match>
<map:match pattern="index.html">
<map:generate src="index.xml"/>
<map:transform src="index.xsl"/>
<map:serialize/>
</map:match>
|
このようにすると、ディレクトリ(/)にアクセスされたときに、
自動的に要求URLがindex.htmlにリダイレクトされ、
これはindex.xmlとindex.xslから合成された内容が返信される、という動作になります。
(first uploaded 2002/12/23 last updated 2003/02/02, URANO398)
|