実例で学ぶEXSLT

コミュニティー標準XSLT拡張を動作させる方法

Comments

developerWorks の最近のコラム、「EXSLTによってXSLTの機能を拡張する」の中でKevin Williams氏は、XSLTに対する拡張のコミュニティー標準について詳しく紹介しています。その記事で述べられているように、EXSLT拡張を使用すればXSLTは、汎用データ操作処理の分野で各段に使いやすくなります。いくつか例を挙げましょう。

  • EXSLTのMath (数学) モジュールには三角関数が含まれているので、SVGにおいて円グラフを容易に作成できます。
  • EXSLTのRegular Expressions (正規表現) モジュールにより、ユーザー入力などの可変データ・ソースの解析と処理を容易に実行できます。
  • EXSLTのDates and Times (日付時刻) モジュールにより、日付情報に依存するコンテンツをWebページに表示したり、日付フィールドを含むデータを処理したりするのが容易になります。

このような実際の作業においてEXSLTを使用すれば、標準をサポートする多くのプロセッサーの間でポータブルな方法でXSLTを活用できるようになります。前回の記事では、最も基本的な処理においてさえ、exsl:node-setexsl:object-type などのEXSLT関数がいかに有用かについて説明しました。今回は、単純で実際的な2つの問題をEXSLTによって解決することにより、EXSLTの機能を一通りご紹介できればと思います。そして、EXSLTの便利な機能のうち、注意を向けるだけの価値があるのに言及できなかった多くの機能を紹介するため、既に言及した分野について再び説明することはしません。

EXSLTについてまったく知らない方は、まずKevin Williams氏の記事をお読みください。その記事の中に示されている参考文献には、EXSLTをサポートするXSLTプロセッサーへの参照が含まれています。EXSLTを自分で使用して、この記事で示すサンプルを実際に試してみるには、それをインストールする必要があります。EXSLT拡張の中には、EXSLTサイトからダウンロードできるXSLTスクリプトを使用することにより、任意のプロセッサーで使用できるものがあります。しかし、EXSLTモジュールの中には、そのような形ではサポートされないものもありますし、この方法はパフォーマンスの点でかなり不利です。IBMのdeveloperWorks のうち、EXSLTに関して私が書いた他のいくつかの記事をご覧になるのもよいでしょう。それらの記事については、参考文献をご覧ください。

ローカル日付情報の利用

問題: XSLTを使用することにより、ユーザーからの求めに応じてサーバー上にWebサイトを設置するとします。そのWebサイトでは、現在の日付と時刻、そして特定のイベントが発生するまでの残り日数を表示します。

EXSLTのDates and Times (日付時刻) モジュールには、日付を操作するための関数が数多く用意されています。その中には、現在の日付を取得する関数、日付に対する計算処理を実行する関数、また日付の書式設定、表示、および解釈のための関数が含まれます。さらに、カスタマイズされた日付の解析や書式設定のための<date:date-format/> という拡張要素もあります。

リスト1 は、これらの機能を利用することによって、現在の日付と時刻、および次の月が始まるまでの日数を表示する方法を示すものです。

リスト1. 日付に固有の詳細データを計算するサンプル・コード (listing1.xslt)
<?xml version="1.0" encoding="utf-8"?>
<!-- A -->
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:date="http://exslt.org/dates-and-times"
version="1.0"
>
<xsl:output method="html"/>
<!-- B -->
<xsl:variable name="now" select="date:date-time()"/>
<xsl:template match="/">
<!-- The rest of the Web site HTML material would go here -->
<xsl:call-template name="date-section"/>
</xsl:template>
<xsl:template name="date-section">
<p>This page was loaded at <xsl:text/>
<!-- C -->
<xsl:value-of select="concat(date:hour-in-day($now), ':',
 date:minute-in-hour($now), ':',
 date:second-in-minute($now))"/>
<xsl:text> on </xsl:text>
<xsl:value-of select="concat(date:day-in-month($now), ' ',
 date:month-name($now), ' ',
 date:year($now))"/>
</p>
<p>
<!-- D -->
<xsl:variable name="days-elapsed"
select="concat('-P',date:day-in-month($now),'D')"/>
<xsl:variable name="one-month-hence"
select="date:add($now, 'P1M')"/>
<xsl:variable name="next-month-start"
select="date:add($one-month-hence, $days-elapsed)"/>
<xsl:variable name="seconds"
select="date:seconds(
date:difference($now, $next-month-start)
)"/>
<xsl:text>The next month starts in </xsl:text>
<xsl:value-of select="$seconds div (3600*24)"/>
<xsl:text> days</xsl:text>
</p>
</xsl:template>
</xsl:transform>

以下、リスト中にアルファベットで示した各部分についてそれぞれ説明します。

A: まず、EXSLTの日付/時刻モジュールの名前空間 (http://exslt.org/dates-and-times) を宣言します。正しく指定してください。何人かの人がこのモジュールの仕様ページを、正しい名前空間ではなく間違ってhttp://www.exslt.org/date/index.html と指定しているのを見たことがあります。これはエラーになります。

B: 関数date:date-time は、現在の日付と時刻をISO-8601形式の文字列 (たとえば2003-01-20T03:16:36Z) として戻します。

C: ここで、EXSLTの関数をいくつか使用することによって、日付と時刻の情報を理解しやすい形式にしています。それらの関数は、日付/時刻文字列の中からさまざまな部分を抽出するために使用しています。これには、複数の方法が考えられます。たとえば、date:date-format 要素を使用すれば、書式設定文字列を使用することによって、表示される日付の形式を指定できます。

D: ここでは、いくつかの計算処理を実行することにより、次の月が始まるまでの日数を計算しています。それには無数の 方法があり、ここで使用した方法より簡単な方法も考えられます。しかしここでは、EXSLT関数の使い方をよりよく示す方法を採用しました。まず、今月既に経過した日数を、EXSLTの経過期間文字列として計算しています。EXSLTの経過期間は、単なる期間ではなく時間の経過を示します。たとえば、-P19D は19日の負の期間を表します。経過期間には、算術演算のための符号が付随しています。たとえば、2003年1月15日午前0時を表す日付/時刻に、経過期間P1D12H を加算すると、1月15日の正午になります。また、経過期間-P1D12H を加算すると、今度は1月14日の正午になります。このような計算は、日付/時刻と期間を引き数とするdate:add 関数を使用して実行できます。

このリストでは、次にdate:add を使用することによって、現時点から1か月後の時点を計算しています。たとえば$now2003-01-20T03:16:36Z なら、結果は2003-02-20T03:16:36Z になります。次にその日付から、先ほど計算した経過日数だけ戻った時点を求めます。その結果は、次の月の最初の日 (たとえば2003-02-01T03:16:36Z) です。関数date:difference は、2つの日付/時刻点を引き数とし、その間の経過期間を戻します。この関数を使用することによって、次の月が始まるまでの経過期間を秒数として計算します (たとえば1036800)。最後に、(3600*24) による整数除算を使用することによって、次の月までの日数を計算します。

このスクリプトの出力は、次のようになります。

<p xmlns:date="http://exslt.org/dates-and-times">This page was loaded 
at 21:16:36 on 19 January 2003</p>
<p xmlns:date="http://exslt.org/dates-and-times">The next month starts 
in 12 days</p>

上記の出力は、本来1行として出力されますが、表示用に改行しています。

高速かつダーティーなデータベース操作

問題: あるXMLファイルの中に一群のレコードが含まれており、それに対してユーザーが一般的な照会を使用することによって、そのデータの特定の部分を取り出せるようにしたいとします。つまり、他のXMLデータの処理中に、このXMLを高速かつダーティーなデータベースとして利用する、というわけです。

例として、リスト2 に示すデータ・ファイルを使用しましょう。これは、ある会社の部署と社員のデータです。

リスト2. 社員情報のデータ・ファイル (employees.xml)
<?xml version="1.0" encoding="utf-8"?>
<employees>
<department title="Research">
<employee title="Coordinator">
<name>
<given>Rene</given>
<family>Descartes</family>
</name>
</employee>
<employee title="Project Manager">
<name>
<given>Abu</given>
<family>Al Kwarizmi</family>
</name>
</employee>
</department>
<department title="Executive">
<employee title="Chief Executive Officer">
<name>
<given>Genghis</given>
<family>Khan</family>
</name>
</employee>
</department>
<department title="Wellness">
<employee title="Manager of Transcendence">
<name>
<given>Shakyamuni</given>
<family>Buddha</family>
</name>
</employee>
</department>
</employees>

さて、ユーザーが、このデータ・ファイルに対する照会結果に応じた相手に宛てて、メモを作成できるようにしたいとします。たとえば、リスト3 に示すようなメモを作成するとします。

リスト3. employees.xmlデータ・ファイルの照会結果に応じた相手に宛てたメモ (memo.xml)
<?xml version='1.0' encoding='utf-8'?>
<memo>
<title>With Usura Hath no Man a House of Good Stone</title>
<date>2003-01-14</date>
<to>
<employee-query
query="/employees/department[@title='Executive']/employee"/>
</to>
<body>
It appears the art world requires a reminder of the fact that the best 
art is created for the enjoyment of the first buyer, and not as as a 
mere investment.  As I've said before, none of the work of Duccio, Piero 
Della Francesca, Pietro Lombardo, Fra Angelico, Zuan Bellini or such 
others would have been of any value if guided by usurious motives.
--EP
</body>
</memo>

to 要素の内容は、employee-query 要素になっています。これは、employees.xmlデータ・ファイルに対して指定する照会の結果で置き換えられることになります。リスト4 は、実際にメモの宛先となる人の名前を表示することによりその処理の動作方法を示す、小さなXSLTファイルです。

リスト4. メモの宛先を表示するXSLTファイル (listing4.xslt)
<?xml version="1.0" encoding="utf-8"?>
<!-- A -->
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
version="1.0"
>
<xsl:output method="text"/>
<xsl:template match="/">
<!-- Jump right to the to element -->
<xsl:apply-templates select="/memo/to"/>
</xsl:template>
<xsl:template match="to">
<xsl:apply-templates/>
</xsl:template>
<!-- B -->
<xsl:template match="employee-query">
<xsl:variable name="db" select="document('employees.xml')"/>
<xsl:variable name="query" select="@query"/>
<xsl:for-each select="$db">
<xsl:variable name="recipients" select="dyn:evaluate($query)"/>
<xsl:apply-templates select="$recipients"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="employee">
<xsl:value-of select="name/given"/>
<xsl:text> </xsl:text>
<xsl:value-of select="name/family"/>
<xsl:if test="not(position()=last())">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
</xsl:transform>

A: EXSLTモジュールのセットアップにおいて前とは違う名前空間 (http://exslt.org/dynamic) を使用していることに注意してください。このモジュールには、文字列をリアルタイムでXPathとして処理し、場合によってはそのような文字列に基づいて集計計算を実行するための関数がいくつか含まれています。

B: このテンプレートは、実際のアクションが実行されるところです。まず、2次入力としてデータ・ファイルを読み込みます。次に、照会文字列を変数に格納します。そのようにするのは、まもなくコンテキストをシフトさせなければならなくなり、この文字列の出現する属性が使用できなくなってしまうためです。データ・ファイルに対するそのようなコンテキストのシフトは、実際にはxsl:for-each 要素によってなされます。次に、dyn:evaluate 関数により、このコンテキストに対して照会文字列が動的に評価されます。結果として得られるノード・セットは、正規のXPath式の評価結果であるかのようにして戻されます。XSLT 1.0には、文字列をXPath式として動的に評価する手段が用意されていませんが、EXSLTを使用すれば、そのような機能を実現できます。リストの残りの部分では、標準的なXSLT操作を使用することにより、照会結果に基づく名前を出力しています。

まとめ

EXSLTには、処理をより簡単にするためのツールに加えて、処理をそもそも可能にするためのツールが含まれています。たとえば、date:date-time 関数はXSLTにおいて置き換えることは不可能ですが、dyn:evaluate() は、通常、システムによって置き換え可能です。一方、目的の結果を得るために実際に実行することになる別のXSLTスクリプトを生成するには、XSLTを使用します。EXSLTには、今後の記事でもカバーしきれないほどの多くの機能が含まれていますが、EXSLTに関して1つの優れた点は、そのドキュメントが充実しているということです。Webサイトを見て、このコミュニティー標準を活用することによって、XSLT開発作業を改善するのに役立つ豊富な情報を得られることでしょう。


ダウンロード可能なリソース


関連トピック

  • XSLTについてよく知らない方は、それを紹介する記事として "Investigating XSLT: The XML transformation language" (LindaMay Patterson、developerWorks、2001年8月) をご覧ください。
  • EXSLTのホーム・ページは、このプロジェクトに関する公式の情報源です。このサイトでは、モジュール、要素、および関数が1つずつ詳しく説明されています。さらに、EXSLTに対する独自の機能追加を投稿することもできます。EXSLTのメーリング・リストに参加することによって、EXSLTに関するディスカッションに加わることができます。
  • Kevin Williams氏の「EXSLTによってXSLTの機能を拡張する」(developerWorks、2002年12月) では、EXSLTの概要が示されています。Leigh Dodds氏による "Extensions to XSLT" は、EXSLTへの入門となる記事です。
  • 私は、developerWorks XML zoneの他の記事でも、EXSLTについて書いています。「マルチパスXSLT」(2002年9月) では、exsl:node-set について紹介しています。"Debug XSLT" の "Introspector Gadget" の部分 (2002年11月) では、exsl:object-typedyn:evaluate について紹介しています。
  • W3CのXSL のページには、XSLT関連の参考文献への有用なリンクが数多く載せられています。その中には、XSLTの仕様、チュートリアル、記事、実装が含まれています。
  • この記事に含まれるサンプルで使用したスタイル・シート・プロセッサーは4XSLTです。これは、4Suite の一部であり、著者もその共同開発者として参加しています。
  • developerWorks のXMLゾーン には、XMLに関するさらに多くの資料があります。
  • IBM WebSphere Studio日本語サイト) は、Javaと他の言語の両方でXML開発を自動化するツールのスイートを提供します。WebSphere Application Server と密接に統合されていますが、他のJ2EEサーバーと一緒に使用することもできます。
static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML
ArticleID=240119
ArticleTitle=実例で学ぶEXSLT
publish-date=02012003