对所有XML(XSLT)的一般替换

时间:2010-08-27 16:46:09

标签: xml xslt replace xslt-2.0

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

<someElement>bar.whatever</someElement>

这将转变为:

<someElement>myBar.whatever</someElement>

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

所有帮助都表示赞赏,并提前致谢!

修改:来自评论

  

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

3 个答案:

答案 0 :(得分:5)

XSLT 1.0没有强大的文本搜索和替换功能。您可以使用containssubstring-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模板以获取searchForreplaceWith参数,这很容易,然后在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,请参阅this article以获取大量信息。

答案 1 :(得分: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>

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

答案 2 :(得分:0)

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

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

要启用exslt,只需在样式表中使用相应的命名空间,如here所述

一些额外的指示: 您可以详细了解模式here:和here

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