<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<ゴレンジャイ>
<member>アカレンジャイ</member>
<member>アオレンジャイ</member>
<member>キレンジャイ</member>
<member>モモレンジャイ</member>
<member>ミドレンジャイ</member>
</ゴレンジャイ>
こんな XML 文書があります。
これにこのような XSLT をあてます。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:for-each select="/ゴレンジャイ/member[4]">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:template>
すると当然 "モモレンジャイ" が表示されます。
では、このような XSLT をあててみましょう。(以下 template のみ)
インデックスの指定を変数化します。
<xsl:template match="/">
<xsl:variable name="index">4</xsl:variable>
<xsl:for-each select="/ゴレンジャイ/member[$index]">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
すると、意に反して "アカレンジャイアオレンジャイキレンジャイモモレンジャイミドレンジャイ" が表示されてしまいます。
キャピキャピのピンクを釣ろうとして、むさいのがわんさかついてきては大変です。
では、少し変更してこのような XSLT をあててみましょう。
<xsl:template match="/">
<xsl:variable name="index" select="4"/>
<xsl:for-each select="/ゴレンジャイ/member[$index]">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
すると、思ったとおり "モモレンジャイ" が表示されます。
これは、前者の場合は4は文字列として、後者では数値として扱われるからです。
述部に文字列が指定されると、空文字でなければ true と判断されます。
つまり、全ての member において述部が true なので全ての member が対象になってしまうからです。
逆に整数値が指定された場合は、position() 関数との比較が行われます。
また、select 属性を使わない(前者の場合)でも述部を下記のようにすれば、正しく"モモレンジャイ"が表示されます。
・number($index)
・positon() = $index
また、select 属性に文字列を指定したい場合は select="'hoge'" のようにコーテーションで囲まなければなりません。
select="hoge" とした場合、本来 select 属性にはロケーションパスを指定するので、カレントノードの子ノードの hoge ノードを変数にバインドしようとします。
数値を指定したときは、ロケーションパスとはみなされません。
なぜなら、XML において要素名は半角数字で始めることはできないので、子ノードでありえないからです。
たかが変数ですが、思わぬところではまる可能性がありますなぁ