XSLT 1.0:迭代字符串中的字符

glm*_*ndr 16 xslt xpath

我需要迭代字符串中的字符来构建XML结构.

目前,我这样做:

<xsl:template name="verticalize">
    <xsl:param name="text">Some text</xsl:param>
    <xsl:for-each select="tokenize(replace(replace($text,'(.)','$1\\n'),'\\n$',''),'\\n')">
        <xsl:element name="para">
            <xsl:value-of select="."/>
        </xsl:element>
    </xsl:for-each>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

这会产生类似于:

<para>S</para>
<para>o</para>
<para>m</para>
<para>e</para>
<para> </para>
<para>t</para>
<para>e</para>
<para>x</para>
<para>t</para>
Run Code Online (Sandbox Code Playgroud)

这适用于Xpath 2.0.但我需要在XPath 1.0环境中应用相同的处理replace()方法,该方法不可用.

你知道实现这个目标的方法吗?

Tom*_*lak 17

<xsl:template name="letters">
  <xsl:param name="text" select="'Some text'" />
  <xsl:if test="$text != ''">
    <xsl:variable name="letter" select="substring($text, 1, 1)" />
    <para><xsl:value-of select="$letter" /></para>
    <xsl:call-template name="letters">
      <xsl:with-param name="text" select="substring-after($text, $letter)" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)


Luc*_*ero 8

如果字符串长度不是很大,则可以使用递归调用的模板来实现此目的,将要处理的字符的索引作为参数传递给模板.

像这样:

<xsl:template name="verticalize">
    <xsl:param name="text">Some text</xsl:param>
    <xsl:param name="index" select="1" />
    <xsl:if test="string-length($text) &gt;= $index">
        <xsl:element name="para">
            <xsl:value-of select="substring($text, $index, 1)"/>
        </xsl:element>
        <xsl:call-template name="verticalize">
            <xsl:with-param name="text" select="$text" />
            <xsl:with-param name="index" select="$index+1" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)

如果字符串比这长,你可以使用类似的方法,但使用分而治之的算法,这样你的最大递归深度为log2(字符串长度),如下所示:

<xsl:template name="verticalize">
    <xsl:param name="text">Some text</xsl:param>
    <xsl:param name="left" select="1" />
    <xsl:param name="right" select="string-length($text)" />
    <xsl:choose>
        <xsl:when test="$left = $right">
            <xsl:element name="para">
                <xsl:value-of select="substring($text, $left, 1)"/>
            </xsl:element>
        </xsl:when>
        <xsl:when test="$left &lt; $right">
            <xsl:variable name="middle" select="floor(($left+$right) div 2)" />
            <xsl:call-template name="verticalize">
                <xsl:with-param name="text" select="$text" />
                <xsl:with-param name="left" select="$left" />
                <xsl:with-param name="right" select="$middle" />
            </xsl:call-template>
            <xsl:call-template name="verticalize">
                <xsl:with-param name="text" select="$text" />
                <xsl:with-param name="left" select="$middle+1" />
                <xsl:with-param name="right" select="$right" />
            </xsl:call-template>
        </xsl:when>
    </xsl:choose>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)


Dim*_*hev 7

XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vText" select="'Some Text'"/>

 <xsl:template match="/">
    <xsl:for-each select="string-to-codepoints($vText)">
      <para><xsl:sequence select="codepoints-to-string(.)"/></para>
    </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

对于那些学习XSLT 2.0/XPath 2.0的人,请注意:

  1. 使用标准的XPath 2.0函数string-to-codepoints()codepoints-to-string().

  2. 在XSLT 2.0中,select属性的值<xsl:for-each>可以是任何项的序列,而不仅仅是节点.