前回はxsl:attribute-setの悪口を書いてしまいましたが、本当はいいやつです.何が良いかといえば、use-attribute-sets属性が使えるからです.これにより階層的なスタイル構造を作ることが出ます.
Microsoft Wordをご存知でしょうか?これを書いているPCはWord2003しか入っていませんが、XMLで出力してみると、Word文書の前半はほとんど階層的なスタイル定義の山で出来ていることがわかります.Wordを単純に起動したときに使えるスタイルは、(すみません私のWordが英語版なので)Normal、Heading1、Heading2、Heading3です.ここでHeading1~Heading3はすべてNormalから派生したスタイルです.
xsl:attribute-setはこのようなWordのスタイルを表すことが出来ます.Wordを(WordMLを)真似て書いてみました.(書いてる属性はWordでなくXSL-FOのものですが...)
<xsl:attribute-set name="Normal">
<xsl:attribute name="text-align" select="'justify'"/>
<xsl:attribute name="font-family" select="'Century'"/>
<xsl:attribute name="font-size" select="'10.5pt'"/>
</xsl:attribute-set>
<xsl:attribute name="text-align" select="'justify'"/>
<xsl:attribute name="font-family" select="'Century'"/>
<xsl:attribute name="font-size" select="'10.5pt'"/>
</xsl:attribute-set>
<xsl:attribute-set name="Heading1" use-attribute-sets="Normal">
<xsl:attribute name="keep-with-next" select="'always'"/>
<xsl:attribute name="font-family" select="'Arial'"/>
<xsl:attribute name="font-size" select="'12pt'"/>
</xsl:attribute-set>
<xsl:attribute name="keep-with-next" select="'always'"/>
<xsl:attribute name="font-family" select="'Arial'"/>
<xsl:attribute name="font-size" select="'12pt'"/>
</xsl:attribute-set>
ところでこのuse-attribute-setsは、スタイルをxsl:variableを使った場合でも実現できます.上を書き換えると次のようになります.
<xsl:variable name="Normal" as="element()">
<dummy>
<xsl:attribute name="text-align" select="'justify'"/>
<xsl:attribute name="font-family" select="'Century'"/>
<xsl:attribute name="font-size" select="'10.5pt'"/>
</dummy>
</xsl:variable>
<dummy>
<xsl:attribute name="text-align" select="'justify'"/>
<xsl:attribute name="font-family" select="'Century'"/>
<xsl:attribute name="font-size" select="'10.5pt'"/>
</dummy>
</xsl:variable>
<xsl:variable name="Heading1" as="element()">
<dummy>
<xsl:copy-of select="$Normal/@*"/>
<xsl:attribute name="keep-with-next" select="'always'"/>
<xsl:attribute name="font-family" select="'Arial'"/>
<xsl:attribute name="font-size" select="'12pt'"/>
</dummy>
</xsl:variable>
<dummy>
<xsl:copy-of select="$Normal/@*"/>
<xsl:attribute name="keep-with-next" select="'always'"/>
<xsl:attribute name="font-family" select="'Arial'"/>
<xsl:attribute name="font-size" select="'12pt'"/>
</dummy>
</xsl:variable>
変数の型をelement()にしたのは、属性ノードのマージをやらせるためです.attribute()*では、こういうわけには行きません.
見た目はあまりカッコよくありませんが、こういう表現方法を取ることにより、言語毎のスタイルの選択も可能になります.例えばxsl:use-attribute-setsでは不可能な以下のような事もできます.
<fo:block>
<xsl:choose>
<xsl:when test="@xml:lang='ja'">
<xsl:copy-of select="$NormalJa/@*"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$NormalEn/@*"/>
</xsl:otherwise>
</xsl:choose>
...
</fo:block>
<xsl:choose>
<xsl:when test="@xml:lang='ja'">
<xsl:copy-of select="$NormalJa/@*"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$NormalEn/@*"/>
</xsl:otherwise>
</xsl:choose>
...
</fo:block>
あまり実用にはならないかもしれませんが、前回言及したスタイルを外部ファイル化することは、言ってみれば上記のようなカッコ悪さを解消することにあります.さらにxml:langをパラメータとしてトンネル化すれば、見た目は一切言語情報が出てこないのに、言語別の出力を得るスタイルシートを書くことも可能です.
xsl:attribute-setがXSLT2.0で変わっていないのは、言語情報などを盛り込むと仕様策定が大変になるのを察知してのことかもしれません.よく解釈すれば、XSLT2.0の機能を使ってスタイルの外部化をしろというのが本当のところなのでしょう.