XSLT 2.0で便利になった機能(47) xsl:value-ofのseparator属性

この前、次のようなデータから
 
<div>
  <span>りんご</span>
  <span>みかん</span>
  <span>バナナ</span>
</div>
 
次のような出力を得るのにposition()関数を使う例を紹介しました.
 
<fo:block>【りんご,みかん,バナナ】</fo:block>
 
もしspan以下に<i>や<b>などの要素がないか、あっても無視できる場合、もっと簡単にできます.それは<xsl:value-of>を使用する方法です.
 
<xsl:template match="div">
    <fo:block>
        <xsl:if test="span">
            <xsl:value-of select="'【'"/>
            <xsl:value-of select="span" separator=","/>
            <xsl:value-of select="'】'"/>
        </xsl:if>
    </fo:block>
</xsl:template>
 
結果はバッチリ次のようになります.
 
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">【りんご,みかん,ばなな】</fo:block>
 
ポイントはセパレータのseparator属性がxsl:value-ofに書けるようになったことです.xsl:value-ofはselectで作られたシーケンスを文字列群として評価して、それらを@separatorで指定した文字列で結合してくれます.ですから、上のxsl:value-ofは、
 
<xsl:value-of select="('りんご','みかん','ばなな')" separator=","/>
 
ということなのです.このxsl:value-ofの機能はstring-join()関数に似ています.string-joinもセパレータを指定できますが、こちらはテキストノードでなく、xs:stringを返します.xsl:value-ofに@separator属性が追加されたのはXSLT2.0からですが、注意も必要です.
 
<xsl:value-of select="span"/>
 
とすれば、"りんご みかん バナナ"がテキストノードして返ります.つまり@separarorの既定値は&#x20;なのです.あまり@select属性にシーケンスを生成するXPath式を書くことはないと思いますが、覚えておいたほうが良いでしょう.
 
<xsl:value-of select="('りんご','みかん','ばなな')" separator=""/>
 
と明示的にseparatorを空文字列にすれば、
 
"りんごみかんバナナ"
 
を得ることができます.