【问题标题】:how to search for a text in xml file and delete that line using xslt如何在 xml 文件中搜索文本并使用 xslt 删除该行
【发布时间】:2013-08-06 13:43:34
【问题描述】:

我想学习如何在 xml 文件中搜索一个单词并使用 xslt 删除整行

示例: abc.xml

<server>
  <mbean code="org.jboss.varia.property.SystemPropertiesService" 
     name="abc.props:type=Service,name=abcprop">
  <attribute name="Properties">
         abc.def.ghi=123
         ghi.klm.nop=123
         qrst.tuv.wxy=123
         zab.cde.fgh=123
         ijk.lmn.opq=remove
         rst.uvw.xyz=123
         abc.tuv.nop=123
         ajc.dzf.goi=123
   </attribute>
 </mbean>
</server>

从上面的例子中我想搜索一个单词“remove”并删除整行:ijk.lmn.opq=remove

预期输出是:

<server>
      <mbean code="org.jboss.varia.property.SystemPropertiesService" 
         name="abc.props:type=Service,name=abcprop">
      <attribute name="Properties">
             abc.def.ghi=123
             ghi.klm.nop=123
             qrst.tuv.wxy=123
             zab.cde.fgh=123
             rst.uvw.xyz=123
             abc.tuv.nop=123
             ajc.dzf.goi=123
       </attribute>
     </mbean>
    </server>

更新:

我尝试了以下代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[(@* != 'DELETE')]"/>
</xsl:stylesheet>

它是如何不工作的,它会删除 xml 文件中的所有内容并显示一个空文件。

【问题讨论】:

  • 在 XML 文件中,行是由换行符分隔的,还是每行都在一个元素中?
  • 我不确定换行符是什么,但每一行都是独立的,如果我删除一行,就不会有任何空行。
  • 这里的问题是您的 xml 文件实际上不是 xml 文件。您确定文件实际上是您向我们展示的那样,还是包含在元素中的文本,例如&lt;text&gt;...&lt;/text&gt;
  • 对不起,我更新了完整的文件。

标签: xml xslt xslt-1.0 xslt-2.0 saxon


【解决方案1】:

如果你被 XSLT 1.0 卡住了,你可以使用这个:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <!--String replace template-->
 <xsl:template name="removeline">
    <xsl:param name="string" />
    <xsl:choose>
    <xsl:when test="contains($string,'remove')">
        <xsl:variable name="before">
        <xsl:value-of select="substring-before($string,'remove')"/>
        </xsl:variable>
        <xsl:variable name="after">
        <xsl:value-of select="substring-after($string,'remove')"/>
        </xsl:variable>
        <xsl:value-of select="substring($before,1, string-length($before) - 12)"/>
        <xsl:call-template name="removeline">
            <xsl:with-param name="string" select="$after" />
        </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
        <xsl:value-of select="$string" />
    </xsl:otherwise>
    </xsl:choose>
 </xsl:template>

  <!-- copy all nodes -->
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <!-- copy text nodes, and apply removeline template  -->
  <xsl:template match="text()" >

     <!-- create empty string for match -->
     <xsl:variable name="empty_string"/>

     <xsl:if test="normalize-space(.) != $empty_string">
            <xsl:call-template name="removeline">
        <xsl:with-param name="string" select="normalize-space(.)"/>
        </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

您可以在此处看到三个模板。第一个是 XSLT 1.0 的字符串函数替换,它没有。它基于在网络的几个地方发现的一个。您可以在 https://stackoverflow.com/a/7523245/2657945 中找到更通用的实现。

第二个和第三个模板在获取文档时输出文档中的所有节点和属性,形成文本节点的特殊情况,使用第一个模板进行处理。 这部分基于https://stackoverflow.com/a/427983/2657945 中的内容。

输出是这样的(在linux中使用xsltproc):

<server>
  <mbean code="org.jboss.varia.property.SystemPropertiesService" name="abc.props:type=Service,name=abcprop">
    <attribute name="Properties">abc.def.ghi=123 ghi.klm.nop=123 qrst.tuv.wxy=123 zab.cde.fgh=123  rst.uvw.xyz=123 abc.tuv.nop=123 ajc.dzf.goi=123</attribute>
  </mbean>
</server>

这是我能够用您的 xml 示例生成的最近似结果,因此根据您的文件和格式,您可能需要对其进行更多调整。

【讨论】:

  • 感谢 xslt 1.0 版本,因为我没有使用 2.0 的任何约束,我会更好地使用 Martin 的解决方案。
【解决方案2】:

使用 XSLT 2.0,您可以在要操作的文本节点上使用 replace 函数:

<xsl:stylesheet version="2.0" exclude-result-prefixes="xs"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="node() | @*" mode="#all">
        <xsl:copy>
            <xsl:apply-templates select="@* |node()" mode="#current"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="attribute[@name = 'Properties']/text()">
      <xsl:value-of select="replace(., '^.*remove.*$\n*', '', 'm')"/>
    </xsl:template>

</xsl:stylesheet>

【讨论】:

    【解决方案3】:

    XSLT 1.0 只有非常有限的字符串处理功能,所以没有简单的方法可以用纯 XSLT 完成您所要求的工作。

    最好的方法是使用一些用不同语言编写的扩展函数——大多数 XSLT 处理器可以定义和调用这样的扩展函数:Xalan-JavaSaxon.NET

    作为替代方案,考虑根本不使用 XSLT - 考虑到您的问题基本上是字符串匹配而不是与 XML 相关:只需加载 XML 并使用您最喜欢的编程语言处理字符串。

    【讨论】:

    • hmmm 这就是限制,因为我使用 xslt 来使用我的大多数其他功能,我不得不使用一些 bash 或 awk 来处理这个功能及其一个 maven 项目。
    • @phani:你确定它是 XSLT 1.0 吗?我遇到了使用 2.0 的 Maven XSLT 示例
    • 我相信maven也支持1.0,这就是我一直在做的。
    • 知道如何用 SAXON 做到这一点吗?
    • 我添加了一个指向相关 Saxon 文档的链接 - 但如果您可以使用 XSLT 2.0,您可能不需要扩展 - XSLT 2.0 支持正则表达式并且通常具有更好的字符串处理能力。跨度>
    猜你喜欢
    • 1970-01-01
    • 2013-09-29
    • 2015-08-30
    • 1970-01-01
    • 2013-04-12
    • 1970-01-01
    • 2021-10-15
    • 2014-08-30
    • 1970-01-01
    相关资源
    最近更新 更多