0

基本上,我现在正在做的是运行 XSLT,然后在 Visual Studio 中打开结果并查找并替换一个单词 - 对于这个示例,我想将“bar”的所有实例更改为“myBar”。可以假定“bar”的所有实例都在文本元素中,如下所示:

<someElement>bar.whatever</someElement>

这将转换为:

<someElement>myBar.whatever</someElement>

但需要注意的是,我还在运行其他转换,例如重命名或移动元素。有什么方法可以将这两个操作(转换和查找和替换)组合到一个 XSLT 中?这可能用于多个查找和替换吗?

感谢所有帮助,并提前感谢!

编辑:来自评论

我应该指定我确实在使用 XSLT 2.0。我正在阅读那篇文章并试图弄清楚我将如何使用 replace()

4

3 回答 3

5

XSLT 1.0 没有强大的文本搜索和替换功能。您可以使用contains,substring-beforesubstring-after进行处理,但您必须使用递归模板来处理您尝试修复的字符串多次出现子字符串的情况。

这有效,假设您移动和重命名元素的变换是恒等变换的变体:

<xsl:template match="text()">
  <xsl:call-template name="replace">
    <xsl:with-param name="text" select="."/>
  </xsl:call-template>
</xsl:template>

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

请注意,在使用 复制元素值的任何地方value-of,都需要使用apply-templates; 改变这个:

<xsl:template match="someElement">
   <renamedElement>
      <xsl:value-of select="."/>
   <renamedElement>
</xsl:template>

进入这个:

<xsl:template match="someElement">
   <renamedElement>
      <xsl:apply-templates select="text()"/>
   <renamedElement>
</xsl:template>

进行多次替换有点棘手。您必须扩展replace模板以获取 asearchForreplaceWith参数,这很容易,然后在text()模板中执行此操作:

<xsl:variable name="pass1">
   <xsl:call-template name="replace">
      <xsl:with-param name="text" select="."/>
      <xsl:with-param name="searchFor">bar</xsl:with-param>
      <xsl:with-param name="replaceWith">myBar</xsl:with-param>
   </xsl:call-template>
</xsl:variable>

<xsl:variable name="pass2">
   <xsl:call-template name="replace">
      <xsl:with-param name="text" select="."/>
      <xsl:with-param name="searchFor">bar</xsl:with-param>
      <xsl:with-param name="replaceWith">myBar</xsl:with-param>
   </xsl:call-template>
</xsl:variable>

<xsl:value-of select="$pass2"/>

在支持在文本节点上使用正则表达式的 XSLT 2.0 中,这要容易得多。您仍然创建一个匹配的模板text(),但它只是调用了replace. 如果您有幸能够使用 XSLT 2.0,请参阅这篇文章以获取大量信息。

于 2010-08-27T20:44:23.300 回答
1

编辑:现在已经澄清,OP希望每次出现的“bar”都被“myBar”替换,这个 XSLT 1.0 样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="text()" name="text">
        <xsl:param name="pString" select="."/>
        <xsl:choose>
            <xsl:when test="contains($pString,'bar')">
                <xsl:value-of 
                select="concat(substring-before($pString,'bar'),'myBar')"/>
                <xsl:call-template name="text">
                    <xsl:with-param name="pString" 
                    select="substring-after($pString,'bar')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$pString"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

有输入:

<someElement>barbarian</someElement>

输出:

<someElement>myBarmyBarian</someElement>

现在,XSLT 2.0 样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="text()">
        <xsl:value-of select="replace(.,'bar','myBar')"/>
    </xsl:template>
</xsl:stylesheet>

注意:文本节点模式匹配。

于 2010-08-27T17:38:03.670 回答
0

您可以使用 alejandro 建议的身份转换模式,并使用 exslt str:replace进行替换

如果您的处理器不支持这一点,您可以在同一页面上找到作为 XSLT 模板的实现。

要启用 exslt,只需在样式表中使用适当的命名空间,如此处所述

一些额外的提示:您可以在此处阅读有关该模式的更多信息:和此处

仅使用第一个模板将原样复制源到目标。然后,您可以简单地为要进行更具体格式化的每个元素添加额外的模板,在您的情况下,匹配“text()”的模板,我猜这可以替换。

于 2010-08-29T12:48:39.717 回答