まず、tokenize関数が使用しているのは実際には正しくありません。理論的には、タグ要素のリスト(厳密に言えば「結果ツリーフラグメント」)を次のように吐き出す必要があります。
<tag>a</tag>
<tag>b</tag>
<tag>c</tag>
<tag>d</tag>
しかし、実際には最後の要素が欠落しています
<tag>a</tag>
<tag>b</tag>
<tag>c</tag>
<tag></tag>
ここで別のトークン化関数を見つけたほうがよいでしょう(StackOverflowには確かに機能している関数が必要です)。
しかし、xsl:for-eachの使用に関する質問に答える際に、このようなことをしたくなるかもしれません...
<xsl:variable name="tags">
<xsl:call-template name="tokenize">
<xsl:with-param name="pText" select="@CommaSeparated"/>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="$tags/tag">
<xsl:copy-of select="." />
</xsl:for-each>
つまり、タグのリストを変数に格納してから、それらをループします。ただし、XSLT1.0でこれを試してみると、「式はノードセットに評価される必要があります。」というエラーが発生します。これを回避するには、拡張機能を使用する必要があります。EXSLTはおそらく最も一般的です。XSLTでこれを次のように宣言します
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
次のようにxsl:for-eachを変更するだけで済みます。
<xsl:for-each select="exsl:node-set($tags)/tag">
したがって、次のXMLが与えられます
<a CommaSeparated="a,b,c,d"></a>
そして次のXSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/a">
<xsl:variable name="tags">
<xsl:call-template name="tokenize">
<xsl:with-param name="pText" select="@CommaSeparated"/>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="exsl:node-set($tags)/tag">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="pText"/>
<xsl:if test="string-length($pText)">
<tag>
<xsl:value-of select="substring-before($pText, ',')"/>
</tag>
<xsl:call-template name="tokenize">
<xsl:with-param name="pText" select="substring-after($pText, ',')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
以下が出力されます(使用しているトークン化関数のバグのため、最後のタグは空白になっています)
<tag>a</tag>
<tag>b</tag>
<tag>c</tag>
<tag></tag>