XSLT 字符串替换

Posted

技术标签:

【中文标题】XSLT 字符串替换【英文标题】:XSLT string replace 【发布时间】:2011-03-05 06:31:24 【问题描述】:

我不太了解 XSL,但我需要修复此代码,我已对其进行了简化以使其更简单。 我收到此错误

无效的 XSLT/XPath 函数

在这条线上

<xsl:variable name="text" select="replace($text,'a','b')"/>

这是 XSL

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:inm="http://www.inmagic.com/webpublisher/query" version="1.0">
    <xsl:output method="text" encoding="UTF-8" />

    <xsl:preserve-space elements="*" />
    <xsl:template match="text()" />

    <xsl:template match="mos">
        <xsl:apply-templates />

        <xsl:for-each select="mosObj">
          'Notes or subject' 
           <xsl:call-template
                name="rem-html">
                <xsl:with-param name="text" select="SBS_ABSTRACT" />
            </xsl:call-template>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="rem-html">
        <xsl:param name="text" />
        <xsl:variable name="text" select="replace($text, 'a', 'b')" />
    </xsl:template>
</xsl:stylesheet>

谁能告诉我这是怎么回事?

【问题讨论】:

请注意,replace() 函数从 XPath 2.0(以及 XSLT 2.0)开始可用,并且支持正则表达式替换。 【参考方案1】:

我一直在回答这个问题。但它们都没有列出 xsltproc(可能还有大多数 XSLT 1.0 处理器)最简单的解决方案:

    将 exslt 字符串名称添加到样式表中,即:
<xsl:stylesheet
  version="1.0"
  xmlns:str="http://exslt.org/strings"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    然后像这样使用它:
<xsl:value-of select="str:replace(., ' ', '')"/>

【讨论】:

我的电脑 (macOS 10.13) 上的 xsltproc 不支持 str:replace() 函数。其他任何主要的 XSLT 1.0 处理器(Xalan、Saxon 6.5 和 Microsoft)也没有。【参考方案2】:

replace 不适用于 XSLT 1.0。

Codesling 有一个template for string-replace 可以用作函数的替代:

<xsl:template name="string-replace-all">
    <xsl:param name="text" />
    <xsl:param name="replace" />
    <xsl:param name="by" />
    <xsl:choose>
        <xsl:when test="$text = '' or $replace = ''or not($replace)" >
            <!-- Prevent this routine from hanging -->
            <xsl:value-of select="$text" />
        </xsl:when>
        <xsl:when test="contains($text, $replace)">
            <xsl:value-of select="substring-before($text,$replace)" />
            <xsl:value-of select="$by" />
            <xsl:call-template name="string-replace-all">
                <xsl:with-param name="text" select="substring-after($text,$replace)" />
                <xsl:with-param name="replace" select="$replace" />
                <xsl:with-param name="by" select="$by" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$text" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

调用为:

<xsl:variable name="newtext">
    <xsl:call-template name="string-replace-all">
        <xsl:with-param name="text" select="$text" />
        <xsl:with-param name="replace" select="a" />
        <xsl:with-param name="by" select="b" />
    </xsl:call-template>
</xsl:variable>

另一方面,如果您实际上只需要用另一个字符替换一个字符,您可以调用具有相似签名的translate。这样的事情应该可以正常工作:

<xsl:variable name="newtext" select="translate($text,'a','b')"/>

另外,请注意,在此示例中,我将变量名称更改为“newtext”,在 XSLT 中变量是不可变的,因此您不能像在原始代码中那样执行 $foo = $foo 的等效操作。

【讨论】:

谢谢马克,但现在我收到此错误:调用了未知的 XPath 扩展函数 @aximili,抱歉,让 XSLT 1.0 和 2.0 混淆,编辑...现在应该可以开始了。 这个答案是错误的! XSLT 中的替换函数替换相应的 SINGLE CHARACTERS,而不是整个字符串!例如,请参见此处:w3schools.com/xpath/xpath_functions.asp @Jakub 你想到的是translate,而不是replace。 XPath 2.0 中的replace 函数将其第二个参数视为正则表达式,并用指定的替换字符串替换该表达式的所有匹配项(可能包括$n 对正则表达式中捕获组的引用) . translate 函数(在 1.0 和 2.0 中)是用于单字符替换单字符的函数。 示例用法中的第 4 行不应该是 &lt;xsl:with-param name="replace" select="'a'" /&gt; 并在 a 周围加上引号吗?【参考方案3】:

程序很好,但是它导致我的应用程序挂起,所以我需要添加案例:

  <xsl:when test="$text = '' or $replace = ''or not($replace)" >
    <xsl:value-of select="$text" />
    <!-- Prevent thsi routine from hanging -->
  </xsl:when>

在函数被递归调用之前。

我从这里得到了答案: When test hanging in an infinite loop

谢谢!

【讨论】:

【参考方案4】:

当您的处理器在 .NET 上运行或使用 MSXML(相对于基于 Java 或其他本机处理器)时,您可以使用以下代码。它使用msxsl:script

确保将命名空间 xmlns:msxsl="urn:schemas-microsoft-com:xslt" 添加到您的根 xsl:stylesheetxsl:transform 元素中。

此外,将outlet 绑定到您喜欢的任何命名空间,例如xmlns:outlet = "http://my.functions"

<msxsl:script implements-prefix="outlet" language="javascript">
function replace_str(str_text,str_replace,str_by)

     return str_text.replace(str_replace,str_by);

</msxsl:script>


<xsl:variable name="newtext" select="outlet:replace_str(string(@oldstring),'me','you')" />

【讨论】:

对不起,如果我很笨,但是如果我将 msxsl 更改为我的前缀,我会得到 prefix outlet is not defined'xsl:script' cannot be a child of the 'xsl:stylesheet' element.。我猜这是微软特有的 XSLT 魔法? @IanGrainger,不是xsl:script,而是msxsl:script,而且它有不同的命名空间(我已经更新了约翰的答案)。【参考方案5】:

注意:如果您希望在需要替换源字符串中的大量实例(例如长文本中的新行)的情况下使用已经提到的算法,则 由于递归调用,您最终会得到***Exception的可能性。

感谢 Xalan(在 Saxon 中不知道如何做到这一点)内置 Java 类型嵌入,我解决了这个问题:

<xsl:stylesheet version="1.0" exclude-result-prefixes="xalan str"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xalan="http://xml.apache.org/xalan"
                xmlns:str="xalan://java.lang.String"
        >
...
<xsl:value-of select="str:replaceAll(
    str:new(text()),
    $search_string,
    $replace_string)"/>
...
</xsl:stylesheet>

【讨论】:

对不起,如果我很愚蠢,但我明白了:Cannot find a script or an extension object associated with namespace 'xalan://java.lang.String'. 你的 XSLT 引擎是什么? 我的评论是针对最流行的 Java XSLT 1.0 引擎 Xalan (xml.apache.org/xalan-j),它支持直接映射到可用 Java 类路径中的可用类型;您不能将我的解决方案应用于 .Net 堆栈 @IanGrainger,您可以通过添加&lt;msxsl:script&gt; 块将其与.NET 一起使用,该块可以调用任何.NET 方法、库等。虽然.NET 也支持EXSLT 扩展功能,所以您不会不需要。 exslt 在libxslt 中也受支持,因此在所有后代xsltproc 等中...【参考方案6】:

这是 XSLT 函数,其工作方式类似于 C# 的 String.Replace() 函数。

此模板具有以下 3 个参数

文本 :- 你的主要字符串

replace :- 要替换​​的字符串

by :- 将由新字符串回复的字符串

以下是模板

<xsl:template name="string-replace-all">
  <xsl:param name="text" />
  <xsl:param name="replace" />
  <xsl:param name="by" />
  <xsl:choose>
    <xsl:when test="contains($text, $replace)">
      <xsl:value-of select="substring-before($text,$replace)" />
      <xsl:value-of select="$by" />
      <xsl:call-template name="string-replace-all">
        <xsl:with-param name="text" select="substring-after($text,$replace)" />
        <xsl:with-param name="replace" select="$replace" />
        <xsl:with-param name="by" select="$by" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$text" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

以下示例显示了如何调用它

<xsl:variable name="myVariable ">
  <xsl:call-template name="string-replace-all">
    <xsl:with-param name="text" select="'This is a old text'" />
    <xsl:with-param name="replace" select="'old'" />
    <xsl:with-param name="by" select="'New'" />
  </xsl:call-template>
</xsl:variable>

您也可以参考below URL了解详情。

【讨论】:

使用 xslt 1.0 这个帖子/模板对我有用,而 Mark Elliot 没有。

以上是关于XSLT 字符串替换的主要内容,如果未能解决你的问题,请参考以下文章

XSLT 1.0 替换字符串

xslt 1.0 字符串替换功能

xslt 2.0 替换为 xml 结构

如何使用 XSLT 替换 XML 节点名称中的字符 - 更改根元素

XSLT 2.0 - 如何用字符串替换'('和')'来清空?

XSLT 替换属性值和文本节点中的文本