代码之家  ›  专栏  ›  技术社区  ›  glmxndr Amir Raminfar

xslt 1.0:遍历字符串中的字符

  •  16
  • glmxndr Amir Raminfar  · 技术社区  · 14 年前

    我需要遍历字符串中的字符来构建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>
    

    这会产生如下结果:

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

    这对xpath 2.0很好。但我需要在xpath 1.0环境中应用相同的处理方法,其中 replace() 方法不可用。

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

    4 回复  |  直到 14 年前
        1
  •  17
  •   Tomalak    14 年前
    <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>
    
        2
  •  8
  •   Lucero    14 年前

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

    像这样:

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

    如果字符串长于此长度,可以使用类似的方法,但使用分而治之算法,以便最大递归深度为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>
    
        3
  •  7
  •   Dimitre Novatchev    14 年前

    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>
    

    对于学习xslt 2.0/xpath2.0的人,请注意 :

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

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

        4
  •  2
  •   Dimitre Novatchev    14 年前

    使用fxsl的xslt 1.0解决方案

    这个 FXSL library 为列表处理提供了许多通用函数。几乎所有的字符串都有一个操作字符串的模拟(将字符串视为字符列表)。

    下面是一个使用 str-foldl 功能/模板:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:dvc-foldl-func="dvc-foldl-func"
    exclude-result-prefixes="xsl dvc-foldl-func"
    >
    
       <xsl:import href="dvc-str-foldl.xsl"/>
    
       <dvc-foldl-func:dvc-foldl-func/>
       <xsl:variable name="vFoldlFun" select="document('')/*/dvc-foldl-func:*[1]"/>
        <xsl:output  encoding="UTF-8" omit-xml-declaration="yes"/>
    
        <xsl:template match="/">
    
          <xsl:call-template name="dvc-str-foldl">
            <xsl:with-param name="pFunc" select="$vFoldlFun"/>
            <xsl:with-param name="pStr" select="123456789"/>
            <xsl:with-param name="pA0" select="0"/>
          </xsl:call-template>
        </xsl:template>
    
        <xsl:template match="dvc-foldl-func:*">
             <xsl:param name="arg1" select="0"/>
             <xsl:param name="arg2" select="0"/>
    
             <xsl:value-of select="$arg1 + $arg2"/>
        </xsl:template>
    
    </xsl:stylesheet>
    

    此转换计算字符串中字符的总和 作为 $pStr 参数并生成正确的结果:

    四十五

    使用 str-map 模板/功能我们有以下简单的解决方案:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:testmap="testmap"
    exclude-result-prefixes="xsl testmap"
    >
       <xsl:import href="str-dvc-map.xsl"/>
    
       <!-- to be applied on any xml source -->
    
       <testmap:testmap/>
    
       <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
       <xsl:template match="/">
         <xsl:variable name="vTestMap" select="document('')/*/testmap:*[1]"/>
         <xsl:call-template name="str-map">
           <xsl:with-param name="pFun" select="$vTestMap"/>
           <xsl:with-param name="pStr" select="'Some Text'"/>
         </xsl:call-template>
       </xsl:template>
    
        <xsl:template name="split" match="*[namespace-uri() = 'testmap']">
          <xsl:param name="arg1"/>
    
          <para><xsl:value-of select="$arg1"/></para>
        </xsl:template>
    
    </xsl:stylesheet>
    

    当应用于任何XML文件(未使用)时,将生成所需的正确结果 :

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