目次


XSLT 2.0で複数ファイルを作る

単一のXSLTテンプレートを使って複数ファイルを作る

Comments

XSLTの最初のバージョンは非常に厳密でした。1つの入力と、1つの出力しか無いのです(ただし、1つ以上のテンプレート・ファイルを持つことはできました)。XSLT 2.0では、入力は相変わらず1つに制限していますが、出力システムは、もっと柔軟になっています。XSLT 2.0では、xsl:result-documentディレクティブを使って、複数の出力ファイルを持つことができます。この新しいタグには2つ、重要な属性があります。これを表1に示します。

表1. xsl:result-documentの属性
属性説明
hrefファイル名、または完全修飾された出力ファイルのURL
format使うべきフォーマットの名前であり、対応するxsl:outputディレクティブで定義されます

私はこのディレクティブをテストするために、一連のテスト結果を含む1つのXMLファイルを用意しました(リスト1)。

リスト1. 入力XMLファイル
<?xml version="1.0" encoding="UTF-8"?>
<tests>
    <testrun run="test1">
        <test name="foo" pass="true" />
        <test name="bar" pass="true" />
        <test name="baz" pass="true" />
    </testrun>
    <testrun run="test2">
        <test name="foo" pass="true" />
        <test name="bar" pass="false" />
        <test name="baz" pass="false" />
    </testrun>
    <testrun run="test3">
        <test name="foo" pass="false" />
        <test name="bar" pass="true" />
        <test name="baz" pass="false" />
    </testrun>
</tests>

これは、ごく単純なものです。各テスト実行の中には名前の付いた一連のテストがあり、それぞれが、テストが成功したかどうかを示すパス・フラグを持っています。

各テスト用にファイルを作る

まず、最初にすべきことは、各テスト結果に対してファイルを作ることです。リスト2はXSLテンプレートを示しています。

リスト2. 各テストに対してファイルを作るコード
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text"/>
<xsl:output method="html" indent="yes" name="html"/>
<xsl:template match="/">
<xsl:for-each select="//testrun">
<xsl:variable name="filename"
  select="concat('output1/',@run,'.html')" />
<xsl:value-of select="$filename" />  <!-- Creating  -->
<xsl:result-document href="{$filename}" format="html">
    <html><body>
        <xsl:value-of select="@run"/>
    </body></html>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

まずファイルの先頭から、幾つか、注意すべき事があります。スタイルシート・タグのversion属性は、xsl:result-documentタグが使えるように、2.0に設定されます。その後を見ると、スタイルシート自体は、出力タイプとしてtextに設定されていることが分かります。これは、HTMLファイルがHTMLフォーマットを持つようにしたいのであれば、第2の名前付きフォーマットを、htmlタイプで定義する必要がある、ということを意味します。私はこのフォーマットをxsl:result-documentタグの中で使っています。

そこからは、xsl:for-eachループを使って、testrunタグまで繰り返します。こうしたタグのそれぞれに対し、variableタグを使って新しい$filename変数を作り、出力ディレクトリー名(output1)と実行名、そして .htmlファイルを1つのパスに連結させます。

こうした上で、$filename変数を持つvalue-ofタグを使って、私がどんなファイルを作っているのかをユーザーに対して伝えます。その後でxsl:result-documentタグを使って新しい文書を開き、HTMLを出力します。リスト3は、このエンジンをサンプル・データファイルに対して実行した場合の出力を示しています。

リスト3. Saxonをサンプル・データファイルに対して実行した場合の出力
Creating output1/test1.html
Creating output1/test2.html
Creating output1/test3.html

より良い出力を得る

xsl:result-documentタグの中身が、このテンプレートの他の部分と同じように評価されるのは、少し直感に反するように思えるかもしれませんが、実際、同じように評価されるのです。そして、テンプレート・コンテキスト内の変数が全て利用できるのです。

これを示すために、xsl:result-documentタグ内のコードをアップグレードし、テスト結果に関する情報を、より多く示すようにします(リスト4)。

リスト4. テンプレートからの、改善されたHTML出力
<xsl:result-document href="{$filename}" format="html">
    <html><head>
        <title>Test results - <xsl:value-of select="@run"/></title>
        </head><body>
        <xsl:value-of select="@run"/>  <!-- Run -->
        <table>
            <tr><td>Test</td><td>Pass</td></tr>
        <xsl:for-each select="test">
            <tr><td>
                <xsl:value-of select="@name" />
            </td><td>
                <xsl:value-of select="@pass" />
            </td></tr>
        </xsl:for-each>
        </table>
    </body></html>
</xsl:result-document>

この出力のHTML結果をリスト5に示します。

リスト5. アップグレードされたHTML出力
<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
   <title>Test results - test1</title>
   </head>
   <body>
      <!-- Run: test1-->
      <table>
         <tr>
            <td>Test</td>
            <td>Pass</td>
         </tr>
         <tr>
            <td>foo</td>
            <td>true</td>
         </tr>
         <tr>
            <td>bar</td>
            <td>true</td>
         </tr>
         <tr>
            <td>baz</td>
            <td>true</td>
         </tr>
      </table>
   </body>
</html>

インデックスを作る

最後に、出力テスト結果それぞれを指す、インデックス・ファイルを追加します。そのために、私は別のxsl:result-documentタグを使って出力をハードコード化し、インデックス・ファイルになるようにします(リスト6)。

リスト6. インデックス・ファイルを作るコード
<!-- Creating the index -->
<xsl:result-document href="output3/index.html" format="html">
 <html><head><title>Test Index</title></head>
  <body>
   <xsl:for-each select="//testrun">
   <a href="{@run}.html"><xsl:value-of select="@run" />
   </a><br/>
   </xsl:for-each>
  </body>
 </html>
</xsl:result-document>

このセクションは、各テスト・ケースに対してHTMLファイルを作るxsl:for-eachループの直後に置きます。リスト7は、サンプルのデータ・セットに対するインデックス・ファイルを示しています。

リスト7. インデックス・ファイル
<html>
   <head>
      <meta http-equiv="Content-Type"
        content="text/html; charset=UTF-8">
   <title>Test Index</title>
   </head>
   <body><a href="test1.html">test1</a><br>
<a href="test2.html">test2</a><br>
<a href="test3.html">test3</a><br></body>
</html>

まとめ

xsl:result-documentディレクティブを使うことにより、1つのデータ・ソースから複数のファイルを、1つのXSLテンプレートを使って出力できるようになります。この機能はXSLT 1.xの非標準的拡張でしたが、XSLTテンプレートを書く人達にとって、新たな世界を開くものです。


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


関連トピック

  • W3CのXSL標準のサイトを見てください。ここはXSL技術やXSL標準に関する手軽な情報源です。
  • W3CのXPathページを見てください。ここではXPathのバージョンと標準に関する情報を提供しています。
  • XSLプロセッサーとして一般的な、Saxonをダウンロードしてください。著者も、この記事を書くためにこれを使いました。
  • Michael Kay著によるXSLTのバイブル、XSLT 2.0 Programmer's Referenceを読んでください。素晴らしい入門書であり、貴重な参考書でもあります。
  • そこを見たら、Michael Kay著によるXPath 2.0 Programmer's Referenceも見てください。W3Cを書いた人による、究極的な参考書です。
  • Jack D. Herrington著によるCode Generation in Actionを読んでください。データベース・アクセスに限らず、幅広い種類の対象向けのコード生成に関して網羅しています。
  • XMLおよび関連技術においてIBM認証開発者になる方法については こちら を参照してください。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source
ArticleID=242463
ArticleTitle=XSLT 2.0で複数ファイルを作る
publish-date=03182005