fo:block-containerとxsl:next-matchでランドスケープのテーブルを実現する.

DITA 1.3になって新たに加わった属性の一つとしてtable/@orient="land"があります.
  
  3.2.3.1 <table>

通常tableはブロックの進行方向に向けて行がだんだん配置されてゆくのですが、たまには列の項目が大きすぎて幅が収まってくれず、反時計方向に90°回転して配置したい場合が出てきます.このようなとき@orient="land"が指定できれば非常に便利です.

このような回転させたテーブルはどのように実現するのでしょうか?実はそれほど難しくはなく回転させたfo:block-containerでfo:tableを囲んでやれば良いのです.例えば次のような感じです.

<fo:block-container reference-orientation="90" break-before="page">
  <fo:table>
    <!--テーブルのコンテンツ-->
  </fo:table>
</fo:block-container>

問題はスタイルシートです.非常に素直に書くと以下のようになるでしょう.

<xsl:template match="*[contains(@class, ' topic/table ')][string(@orient) eq 'land']" priority="2">
  <xsl:choose>
    <xsl:when test="string(@orient) eq 'land'">
      <fo:block-container reference-orientation="90" break-before="page">
        <fo:table>
          <!--①テーブルの作成処理-->
        </fo:table>
      </fo:block-container>
    </xsl:when>
    <xsl:otherwise>
        <fo:table>
          <!--①テーブルの作成処理-->
        </fo:table>
    </xsl:otherwise>
</xsl:template>

ここで"①テーブルの作成処理"は中身は同じです.冗長なので別のテンプレートにくくりだしても良いかもしれません.しかし、このようなテンプレートの書き方は実は非常に「いまいち」なのです.XSLT 2.0のxsl:next-matchを使用すれば、今までのtableのコーディングを一切変えることなくたった数ステップのテンプレートを「追加」するだけで実現できます.それは次のようなコードです.

<xsl:template match="*[contains(@class, ' topic/table ')][string(@orient) eq 'land']" priority="2">
    <fo:block-container reference-orientation="90" break-before="page">
        <xsl:next-match/>
    </fo:block-container>
</xsl:template>

priority="2"とxsl:next-matchがミソですね.priority="2"で@orient="2"の指定されたtableはこのテンプレートの適用を優先させます.そしてfo:block-containerを作ったら、次にマッチングする(つまり通常のtableの)テンプレートを呼び出すのです.もちろんmatch="*[contains(@class, ' topic/table ')]"のテンプレートのpriorityは2より小さい必要があります.

しかし実にスマートです.一番良いのは「既存のコードに一切手を加えることなく実現できる」点です.これがXSLT 2.0の醍醐味とでもいうものでしょう.実装してみた例は以下の様なものです.(これは改ページさせていない例です)

イメージ 1


ちなみに、DITA 1.3ではセルの回転もあります.例えば列の見出しに条件を記述したくてかつ列数が多いような場合、これも90°回転させて表の見出し行を作りたい場合があります.特に機器のスペックなどを表す表の場合にたまたま見かけます.

3.2.3.7 <entry>

entry/@rotate="1"と指定するのですが、このスタイルシートの実装はそう簡単ではありません.同じようにfo:table-cellの中にfo:blcok-containerを入れて回転させてやれば良いのですが、こちらはセルの高さ(fo:block-container/@width)を明示的に指定してやる必要があります.この計算がXSLTでは困難なのです.という訳で同じtableのDITA 1.3での新機能ですが、こちらはまだ思案中です.