ChatGPT解决这个技术问题 Extra ChatGPT

XSLT 字符串替换

我不太了解 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)开始可用,并且支持正则表达式替换。

a
axel.michel

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 行不应该是 <xsl:with-param name="replace" select="'a'" /> 并在 a 周围加上引号吗?
j
j0k

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

该模板具有以下 3 个参数

text :- 你的主要字符串

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 没有。
M
Milan Aleksić

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

我解决了这个问题,这要归功于 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,您可以通过添加一个 <msxsl:script> 块将它与 .NET 一起使用,该块可以调用任何 .NET 方法、库等。虽然 .NET 也支持 EXSLT 扩展功能,所以您不需要。
exsltlibxslt 中也受支持,因此在所有后代 xsltproc 等中...
B
Berend de Boer

我一直在打这个答案。但是它们都没有列出 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)也没有。
P
Peter

当您的处理器在 .NET Framework (.NET Core 或 .NET 5 上不支持) 或使用 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,并且它具有不同的命名空间(我已经更新了 John 的答案)。
C
Community

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

  <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

谢谢!


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅