如何实现XSLT tokenize函数?

时间:2012-05-04 10:43:05

标签: php xml xslt tokenize

似乎EXSLT tokenize函数不适用于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

我知道这个问题已多次发布,但我找不到简单的解决方案。

感谢您的帮助。

3 个答案:

答案 0 :(得分:7)

引用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>

答案 1 :(得分:1)

我可能有点老式,因为我不使用函数,但我有以下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>

答案 2 :(得分:0)

您不必编写自己的实现 - 只需使用现有的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="', &#9;&#10;&#13;'"/>
        </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(), ' ', ., '&#10;')"/>
    </xsl:template>
</xsl:stylesheet>

将此转换应用于以下XML文档时:

<t>out, of
 luck</t>

生成想要的结果 - 所有单词的位置的序列。

请注意 pDelimiters参数中提供的任何最大长度的相邻分隔符字符序列用作分隔符:

1 out
2 of
3 luck