カレントノードが、例えば次のようなh2要素であった場合を考える。
<h2 class="foo bar baz">heading text</h2>
このとき、class名である「foo」、「bar」、「baz」それぞれについて、これらをspan要素として生成したいとする。
まずこのように、名前付きテンプレート(forEachNMTOKENS)にclass属性値をパラメータとして渡しつつ呼び出す。名前付きテンプレート「forEachNMTOKENS」は後述。
<xsl:call-template name="forEachNMTOKENS">
<xsl:with-param name="NMTOKENS" select="normalize-space(@class)" />
</xsl:call-template>
各class属性値が、一つ以上の空白記号で区切られている場合考慮に入れ、最初にこのテンプレートを呼び出す際に、class属性値を正規化(normalize-space(@class))している点に注意。
<xsl:template name="forEachNMTOKENS">
<xsl:param name="NMTOKENS">arbitrarySTRING</xsl:param>
<xsl:variable name="dividedNMTOKENS" select="substring-after($NMTOKENS, ' ')" />
<xsl:if test="$dividedNMTOKENS = ''">
<!-- 属性値が一つしかない場合は空文字列が返却される -->
<!-- ここに属性値($NMTOKENS)に関するリテラル結果要素等 -->
<span><xsl:value-of select="$NMTOKENS" /></span>
</xsl:if>
<xsl:if test="$dividedNMTOKENS != ''">
<!-- 複数存在した場合 -->
<xsl:variable name="ATTRVALUE" select="substring-before($NMTOKENS, ' ')" />
<!-- ここに属性値($ATTRVALUE)に関するリテラル結果要素等 -->
<span><xsl:value-of select="$ATTRVALUE" /></span>
<xsl:call-template name="forEachNMTOKENS">
<xsl:with-param name="NMTOKENS" select="$dividedNMTOKENS" />
</xsl:call-template>
</xsl:if>
</xsl:template>
これで、「foo」、「bar」、「baz」それぞれを内容に持ったspan要素が3つ生成されることになる。
汎用性を持たせるなら、リテラル結果要素の部分をテンプレート呼び出しにしてしまえば良い(筈)。何のテンプレートを呼び出すかは、もう一つ別のパラメータを作り、それで判別。
XPathで、NMTOKENS型属性の値それぞれをノードとして指定できれば、このようなことをする必要は無いのだけど。というわけで、もしそのようなことが出来るなら、このテンプレートは無価値。
例えばこのWeblogのXMLソースにて各記事に「topic="XSLT XPath"」 というような属性を設けておいて:
こういうことしよういうのが狙い。前者はDOMで、後者はXSLTで。