XSLT 2.0で便利になった機能(39) ","演算子

今回は","演算子を紹介します.","演算子は両辺のアイテムかシーケンスを結合して新たにシーケンスを作成してくれます.今までの例の中では、
 
<xsl:variable name="dayOfWeek" select="'Sunday','Monday','Tuesday','Wednesday',Thurseday','Friday','Saturday'" as="xs:string*"/>
<xsl:if test="$day = $dayOfWeek">
  ...
<xsl:if>
 
というような形で","演算子でシーケンスを作って利用してきました.また、実務上では私はもっぱらxsl:messageのselect属性に","演算子を使っています.1行で書けてデバッグに楽だからです.
 
<xsl:message select="'Element=',name(),'Title=',string(title)"/>
 
さて以前次のような和集合をつかった例を紹介しました.
 
<xsl:apply-templates select="frontmatter | chapter | part | appendix | backmatter"/>
 
入力を
 
<?xml version="1.0" encoding="UTF-8" ?>
<document>
    <frontmatter>
        <title>Introduction</title>
    </frontmatter>
    <chapter>
        <title>Beggining XSLT</title>
    </chapter>
    <part>
        <title>1. XPath basic</title>
    </part>
    <part>
        <title>2. XSLT instructions</title>
    </part>
    <part>
        <title>3. Making template</title>
    </part>
    <appendix>
        <title>Glossary</title>
    </appendix>
    <backmatter>
        <title>Index</title>
    </backmatter>
</document>
 
としてスタイルシートでxsl:apply-templateのselect属性を変えてみます.
 
<xsl:template match="document">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <!-- 逆順にしてみる -->
        <xsl:apply-templates select="backmatter | appendix | part | chapter | frontmatter"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="frontmatter | chapter | part | appendix | backmatter">
    <xsl:message select="'Element=',name(),'Title=',string(title)"/>
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
 
ところが結果は以下のようになります.unionオペレータ("|")から生成されるシーケンスは、ドキュメントオーダーを保証してくれるからです.
 
Element= frontmatter Title= Introduction
Element= chapter Title= Beggining XSLT
Element= part Title= 1. XPath basic
Element= part Title= 2. XSLT instructions
Element= part Title= 3. Making template
Element= appendix Title= Glossary
Element= backmatter Title= Index
 
では","オペレータを使った場合はどうなるでしょうか?
 
<xsl:apply-templates select="backmatter , appendix, part , chapter , frontmatter"/>
 
この場合結果は、
 
Element= backmatter Title= Index
Element= appendix Title= Glossary
Element= part Title= 1. XPath basic
Element= part Title= 2. XSLT instructions
Element= part Title= 3. Making template
Element= chapter Title= Beggining XSLT
Element= frontmatter Title= Introduction
 
となります.partだけがドキュメントオーダーで、あとは","演算子で並べたように入力とは逆順に処理されます.通常文書はドキュメントオーダーで処理しますが、意図的に処理順を変更する場合があれば使えるでしょう.
 
でもこれもxsl:apply-templatesをちょっと変えると元に戻ります.
 
<xsl:apply-templates select="current()/(backmatter , appendix, part , chapter , frontmatter)"/>
 
とすると結果は
 
Element= frontmatter Title= Introduction
Element= chapter Title= Beggining XSLT
Element= part Title= 1. XPath basic
Element= part Title= 2. XSLT instructions
Element= part Title= 3. Making template
Element= appendix Title= Glossary
Element= backmatter Title= Index
 
とドキュメントオーダーになります.これは"/"がドキュメントオーダーを強制するからです.
 
あと次のようなコーディングをする場合はないでしょうか?
<xsl:choose>
    <xsl:when test="@xml:lang">
        <xsl:copy-of select="@xml:lang"/>
    </xsl:when>
    <xsl:otherwise>
        <xsl:attribute name="xml:lang" select="'en-US'"/>
    </xsl:otherwise>
</xsl:choose>
 
これはもちろん次のように簡略化することもできます.
 
<xsl:attribute name="xml:lang" select="if (@xml:lang) then @xml:lang else 'en-US'"/>
 
しかし","演算子を使えば、もっと簡単に出来ます.
 
<xsl:attribute name="xml:lang" select="(@xml:lang,'en-US')[1]"/>
 
これは、xml:lang属性が存在するときはそれが採用され、存在しなければ"en-US"がxml:langの値となるからです.","演算子は使い方によっては、非常に便利になりますね.