は一個ではありません...

こんなことを書くと「あったりまえじゃん!」と言われそうですが、それでもXSLT 1.0のスタイルシートを見ていると意外とそのまま動いてしまっている例があります.それはXPath式でのロケーションステップに対する述語(predicate)の"[1]"という記述です.

例えば入力のXML

<?xml version="1.0" encoding="UTF-8"?>
<doc>
    <chapter>
        <para no="1">para-1</para>
        <para no="2">para-2</para>
        <para no="3">para-3</para>
        <para no="4">para-4</para>
    </chapter>
    <chapter>
        <para no="5">para-5</para>
        <para no="6">para-6</para>
        <para no="7">para-7</para>
        <para no="8">para-8</para>
    </chapter>
</doc>

という単純なものであり、XSLT 1.0で"1番目のpara要素の中身を出力しよう"と次のように書いたとします.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:template match="/">
        <xsl:variable name="para1" select="//para[1]"/>
        <xsl:message>//para[1]=<xsl:value-of select="string($para1)"/></xsl:message>
    </xsl:template>
</xsl:stylesheet>

結果は、oXygenでやると、

//para[1]=para-1

となります.なんの問題もありません.でもここで、xsl:stylesheetのversion="2.0"に書き換えて実行すると、

XPTY0004: A sequence of more than one item is not allowed as the first argument of string() (<para/>, <para/>)

のエラーになってしまいます.何か変です.デバッグのために、

<xsl:message select="'//para[1]=',//para[1]"></xsl:message>

と書いてやると、

//para[1]=<para no="1">para-1</para><para no="5">para-5</para>

と出てきます.アレッ!?話が違うようです.//para[1]は<para no="1">para-1</para>だけでなく<para no="5">para-5</para>も選択しています.そうなのです.ここで知らなければならないことは次のようなことです.

1. 述語(predicate)に"[1]"と書くと、それはコンテキストポジション(context position)の意味になります."[1]"は実は"[position() = 1]"と等価です.ここでposition()は評価されている要素の順番を返します.つまり対象はpara要素ですから、position()は、そのpara要素の親に対して何番目の子かということです.すべてのpara要素のうちの1番目ということにはならないのです.

2. もし文書中のすべてのpara要素のドキュメントオーダーで1番目ということだったら、<xsl:message select="'(//para)[1]=',(//para)[1]"></xsl:message>と書かねばなりません.こうすれば、(//para)[1]=<para no="1">para-1</para>と表示されます.評価されるものは文書中のすべてのparaのシーケンスだからです.その中での1番目を選択することになります.

3. XSLT 1.0では、string関数のパラメータが複数ノードの場合、最初のノードが選択されてその文字列値が返されます.XSLT 2.0ではこのようにはならず、string関数のパラメータがノードの場合、その個数は一個でなければ上記のようにエラーとなります.これはXSLT 2.0プロセッサを使っていても、XSLTスタイルシートのversion="1.0"か"2.0"かで異なった動作となります.

という訳でたかだか"[1]"であっても結構いろいろ知らねばならないことはあったのでした.参考になれば幸いです.