如何实现 XSLT 标记化功能?
Posted
技术标签:
【中文标题】如何实现 XSLT 标记化功能?【英文标题】:How to implement XSLT tokenize function? 【发布时间】:2012-05-13 21:46:37 【问题描述】:似乎 EXSLT 标记化功能不适用于 php XSLTProcessor (XSLT 1.0)。
我尝试在纯 XSL 中实现它,但我无法让它工作:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:func="http://exslt.org/functions"
xmlns:exsl="http://exslt.org/common"
xmlns:my="http://mydomain.com/">
<func:function name="my:tokenize">
<xsl:param name="string"/>
<xsl:param name="separator" select="'|'"/>
<xsl:variable name="item" select="substring-before(concat($string,$separator),$separator)"/>
<xsl:variable name="remainder" select="substring-after($string,$separator)"/>
<xsl:variable name="tokens">
<token><xsl:value-of select="$item"/></token>
<xsl:if test="$remainder!=''">
<xsl:copy-of select="my:tokenize($remainder,$separator)"/>
</xsl:if>
</xsl:variable>
<func:result select="exsl:node-set($tokens)"/>
</func:function>
<xsl:template match="/">
<xsl:copy-of select="my:tokenize('a|b|c')"/>
</xsl:template>
</xsl:stylesheet>
预期结果:
<token>a</token><token>b</token><token>c</token>
实际结果:
abc
我知道这个问题已经发布了很多次,但我找不到简单的解决方案。
感谢您的帮助。
【问题讨论】:
【参考方案1】:您不必编写自己的实现 - 只需使用现有的 FXSL str-split-to-words
模板,它提供了更强大的功能。
这是一个使用str-split-to-words
的简短演示:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:import href="strSplit-to-Words.xsl"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:variable name="vwordNodes">
<xsl:call-template name="str-split-to-words">
<xsl:with-param name="pStr" select="/"/>
<xsl:with-param name="pDelimiters"
select="', 	 '"/>
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select="ext:node-set($vwordNodes)/*"/>
</xsl:template>
<xsl:template match="word">
<xsl:value-of select="concat(position(), ' ', ., ' ')"/>
</xsl:template>
</xsl:stylesheet>
当此转换应用于以下 XML 文档时:
<t>out, of
luck</t>
产生了想要的结果——所有单词及其位置的序列。
请注意pDelimiters
参数中提供的任何最大长度的相邻分隔符字符序列都用作分隔符:
1 out
2 of
3 luck
【讨论】:
【参考方案2】:我可能有点过时,因为我不使用函数,但我有以下tokenize
模板,无需任何特殊扩展即可满足您的需求:
<xsl:template name="tokenize">
<xsl:param name="string"/>
<xsl:param name="separator" select="'|'"/>
<xsl:choose>
<xsl:when test="contains($string,$separator)">
<token>
<xsl:value-of select="substring-before($string,$separator)"/>
</token>
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="substring-after($string,$separator)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<token><xsl:value-of select="$string"/></token>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
它的调用方式如下,应该会给你想要的输出:
<xsl:call-template name="tokenize">
<xsl:with-param name="string" select="'a|b|c'"/>
</xsl:call-template>
【讨论】:
【参考方案3】:引用http://www.exslt.org/str/functions/tokenize/index.html
以下 XSLT 处理器支持 str:tokenize:
4XSLT,来自 4Suite。 (版本 0.12.0a3) 来自 Daniel Veillard 等人的 libxslt。 (版本 1.0.19)
由于 PHP 使用 libxslt,这意味着 tokenize
可用,但您必须使用正确的扩展命名空间(您不这样做):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str"
…
然后你可以使用tokenize作为一个函数,例如构建一个带有数字1-12的选择框:
<select name="months">
<xsl:for-each select="str:tokenize('1,2,3,4,5,6,7,8,9,10,11,12', ',')">
<xsl:element name="option">
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</select>
【讨论】:
以上是关于如何实现 XSLT 标记化功能?的主要内容,如果未能解决你的问题,请参考以下文章