XSLT2.0で便利になった機能(51) xsl:template

いまさらですが、xsl:templateについて考え直してみました.XSLT2.0でテンプレートはどのように変わったのでしょうか?これは仕様でどのようにテンプレートが定義されているかを見ればわかります.

[XSLT1.0]
<!-- Category: top-level-element -->
<xsl:template
  match = pattern 
  name = qname 
  priority = number 
  mode = qname>
  <!-- Content: (xsl:param*, template) -->
</xsl:template>

5.3 Defining Template Rules

[XSLT2.0]
<!-- Category: declaration -->
<xsl:template
  match? = pattern
  name? = qname
  priority? = number
  mode? = tokens
  as? = sequence-type>
  <!-- Content: (xsl:param*, sequence-constructor) -->
</xsl:template>

6.1 Defining Templates

違いは、テンプレートの中身が"template"から"sequence-constructor"に変わり、従ってXSLT2.0ではxsl:template/@as属性で"sequence-type"が指定できるようになっていることです.

実際にはどのように違うのでしょうか?XSLT1.0の"template"というのは、実は結果ツリー(result tree)に書き込む命令群でした.つまり結果として得られるものは端的に言えばノードです.XSLT2.0は違います.もちうろんノードも返せますが、sequence of itemsを返せます.つまりテンプレートのボディ部分は"sequence constructor"であるのです.

非常に簡単な例です.XSLT1.0で要素を渡して、その@xml:langが"en"であるかを判定して返すテンプレートは例えば次のようにしか作れませんでした.

<!--XSLT1.0-->
<xsl:variable name="cTrue" select="'true'"/>
<xsl:variable name="cFalse" select="'false'"/>

<xsl:template name="isEn">
  <xsl:param name="prmElem">
  <xsl:choose>
    <xsl:when test="string($prmElem/@xml:lang) = 'en')">
      <xsl:value-of select="$cTrue"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$cFalse"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!--呼び出し側-->
<xsl:variable name="isEn">
  <xsl:call-template name="isEn">
    <xsl:with-param name="prmElem" select="[調べる対象の要素]"/>
  </xsl:call-template>
</xsl:variable>

<xsl:choose>
  <xsl:when test="$isEn=$cTrue">
    <!--英語の場合の処理-->
  </xsl:when>
  <xsl:otherwise>
    <!--英語以外の場合の処理-->
  </xsl:otherwise>
</xsl:choose>

つまり、"isEn"テンプレートからはxsl:value-ofでテキストノードを返し、それを文字列として評価して$cTrueか否かを判定しています.

XSLT2.0ならもちろんxsl:functionを使うでしょうか、xsl:templateを使えば次のようになるでしょう.

<!--XSLT2.0-->
<xsl:template name="isEn" as="xs:boolean">
  <xsl:param name="prmElem" required="yes" as="element()">
  <xsl:sequenece select="string($prmElem/@xml:lang) eq 'en'">
</xsl:template>

<!--呼び出し側-->
<xsl:variable name="isEn" as="xs:boolean">
  <xsl:call-template name="isEn">
    <xsl:with-param name="prmElem" select="[調べる対象の要素]"/>
  </xsl:call-template>
</xsl:variable>

<xsl:choose>
  <xsl:when test="$isEn">
    <!--英語の場合の処理-->
  </xsl:when>
  <xsl:otherwise>
    <!--英語以外の場合の処理-->
  </xsl:otherwise>
</xsl:choose>

この例では、"isEn"テンプレートはxs:booleanを返します.こんなことが当たり前でできるのです.(ちょっと単純すぎるかもしれませんが)

もしあなたがxsl:templateを単に結果ツリーへ書き出すだけに使っていたらそれはちょっともったいないです.xsl:templateはもっと複雑な問題解決に役立つことができます.

xsl:template/@asはこのテンプレートの生成するsequence-typeを表しますが、既定値はitem()*です.itemというのは、XPath2.0のデータモデルで、最上位に位置する型です.つまり例えばnode()やxs:integerを包含する型です.

XQuery 1.0 and XPath 2.0 Data Model (XDM) (Second Edition)
2.6.3 Type Hierarchy

xsl:template/@as="item()*"ならば、どのようなことができるのでしょうか?それは例えばテンプレートから、要素も整数も一連のシーケンスで返せちゃうと言うことです.これがどう実践的に使えるかは次回紹介したいと思います.