带递归的 XSLT 多字符串替换 [英] XSLT multiple string replacement with recursion

查看:56
本文介绍了带递归的 XSLT 多字符串替换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试使用递归执行多个(不同的)字符串替换,但遇到了障碍.我已经成功地让第一个替代品工作,但随后的替代品永远不会触发.我知道这与递归以及 with-param 字符串如何传递回调用模板有关.我看到了我的错误以及为什么下一个 xsl:when 永远不会触发,但我似乎无法确切地弄清楚如何将完整的修改字符串从第一个 xsl:when 传递到第二个 xsl:when.非常感谢任何帮助.

I have been attempting to perform multiple (different) string replacement with recursion and I have hit a roadblock. I have sucessfully gotten the first replacement to work, but the subsequent replacements never fire. I know this has to do with the recursion and how the with-param string is passed back into the call-template. I see my error and why the next xsl:when never fires, but I just cant seem to figure out exactly how to pass the complete modified string from the first xsl:when to the second xsl:when. Any help is greatly appreciated.

<xsl:template name="replace">
    <xsl:param name="string" select="." />
    <xsl:choose>
        <xsl:when test="contains($string, '&#13;&#10;')">
            <xsl:value-of select="substring-before($string, '&#13;&#10;')" />
            <br/>
            <xsl:call-template name="replace">
                <xsl:with-param name="string" select="substring-after($string, '&#13;&#10;')"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:when test="contains($string, 'TXT')">
            <xsl:value-of select="substring-before($string, '&#13;TXT')" />
            <xsl:call-template name="replace">
                <xsl:with-param name="string" select="substring-after($string, '&#13;')" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$string"/>
        </xsl:otherwise>

    </xsl:choose>
</xsl:template>

推荐答案

这个转换是完全参数化的,不需要任何使用默认命名空间的技巧:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:params xml:space="preserve">
  <pattern>
   <old>&#xA;</old>
   <new><br/></new>
  </pattern>
  <pattern>
   <old>quick</old>
   <new>slow</new>
  </pattern>
  <pattern>
   <old>fox</old>
   <new>elephant</new>
  </pattern>
  <pattern>
   <old>brown</old>
   <new>white</new>
  </pattern>
 </my:params>

 <xsl:variable name="vPats"
      select="document('')/*/my:params/*"/>

 <xsl:template match="text()" name="multiReplace">
  <xsl:param name="pText" select="."/>
  <xsl:param name="pPatterns" select="$vPats"/>

  <xsl:if test=
   "string-length($pText) >0">

    <xsl:variable name="vPat" select=
     "$vPats[starts-with($pText, old)][1]"/>
    <xsl:choose>
     <xsl:when test="not($vPat)">
       <xsl:copy-of select="substring($pText,1,1)"/>
     </xsl:when>
     <xsl:otherwise>
       <xsl:copy-of select="$vPat/new/node()"/>
     </xsl:otherwise>
    </xsl:choose>

    <xsl:call-template name="multiReplace">
      <xsl:with-param name="pText" select=
       "substring($pText, 1 + not($vPat) + string-length($vPat/old/node()))"/>
    </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

应用于此 XML 文档时:

<t>The quick
brown fox</t>

产生了想要的、正确的结果:

The slow<br/>white elephant

说明:

从左到右任意位置扫描文本,如果剩余字符串以指定模式之一开头,则起始子字符串将替换为为 firat 匹配模式指定的替换.

The text is scanned from left to right and at any position, if the remaining string starts with one of the specified patterns, then the starting substring is replaced by the replacement specified for the firat matching patterns.

请注意:如果我们有搜索模式:

Do note: If we have search patterns:

   "relation"   --> "mapping" 
   "corelation" --> "similarity"

按照上面的顺序,和文字:

in the above order, and text:

   "corelation"

那么这个解决方案会产生更正确的结果:

then this solution produces the more correct result:

"similarity"

以及@Alejandro目前接受的解决方案)产生:

and the currently accepted solution by @Alejandro) produces:

"comapping"

编辑:通过一个小更新,我们得到了另一项改进:如果在给定位置可以进行多次替换,我们将执行最长的替换.

Edit: With a small update we get another improvement: If at a given location more than one replace is possible, we perform the longest replace.

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 xmlns:my="my:my">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>

    <my:params xml:space="preserve">
        <pattern>
            <old>&#xA;</old>
            <new><br/></new>
        </pattern>
        <pattern>
            <old>quick</old>
            <new>slow</new>
        </pattern>
        <pattern>
            <old>fox</old>
            <new>elephant</new>
        </pattern>
        <pattern>
            <old>brown</old>
            <new>white</new>
        </pattern>
    </my:params>

    <xsl:variable name="vrtfPats">
     <xsl:for-each select="document('')/*/my:params/*">
      <xsl:sort select="string-length(old)"
           data-type="number" order="descending"/>
       <xsl:copy-of select="."/>
     </xsl:for-each>
    </xsl:variable>

    <xsl:variable name="vPats" select=
     "ext:node-set($vrtfPats)/*"/>

    <xsl:template match="text()" name="multiReplace">
        <xsl:param name="pText" select="."/>
        <xsl:param name="pPatterns" select="$vPats"/>
        <xsl:if test=    "string-length($pText) >0">      
            <xsl:variable name="vPat" select=
            "$vPats[starts-with($pText, old)][1]"/>

            <xsl:choose>
                <xsl:when test="not($vPat)">
                    <xsl:copy-of select="substring($pText,1,1)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$vPat/new/node()"/>
                </xsl:otherwise>
            </xsl:choose>

            <xsl:call-template name="multiReplace">
                <xsl:with-param name="pText" select=
                "substring($pText,
                          1 + not($vPat) + string-length($vPat/old/node())
                          )"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>

因此,如果我们有两个代表,例如core"-->kernel"和corelation"-->similarity",第二个将用于包含corelation"一词的文本,无论如何代表已下令.

Thus, if we have two reps such as "core" --> "kernel" and "corelation" --> "similarity", The second would be used for a text containing the word "corelation", regardless of how the reps are ordered.

这篇关于带递归的 XSLT 多字符串替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆