如何使用带有样式表和xsltproc的xslt从xml中删除元素?


68

我有很多具有以下形式的XML文件:

<Element fruit="apple" animal="cat" />

我要从文件中删除。

使用XSLT样式表和Linux命令行实用程序xsltproc,我该怎么做?

至此,脚本中已经有了包含要删除的元素的文件列表,因此可以将单个文件用作参数。


编辑:问题最初是没有意图。

我试图实现的是删除整个元素“ Element”,其中(fruit ==“ apple” && animal ==“ cat”)。在同一文档中,有许多名为“元素”的元素,我希望这些元素保留下来。所以

<Element fruit="orange" animal="dog" />
<Element fruit="apple"  animal="cat" />
<Element fruit="pear"   animal="wild three eyed mongoose of kentucky" />

会成为:

<Element fruit="orange" animal="dog" />
<Element fruit="pear"   animal="wild three eyed mongoose of kentucky" />

Answers:


134

使用最基本的XSLT设计模式之一:“覆盖身份转换”将仅编写以下内容:

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

 <xsl:output omit-xml-declaration =“ yes” />

    <xsl:template match =“ node()| @ *”>
      <xsl:copy>
         <xsl:apply-templates select =“ node()| @ *” />
      </ xsl:copy>
    </ xsl:template>

    <xsl:template match =“ Element [@ fruit ='apple'and @ animal ='cat']” />
</ xsl:stylesheet>

请注意,第二个模板如何仅对具有属性“水果”,值“苹果”和属性“动物”,值“ cat”的名为“元素”的元素覆盖身份(第一个)模板。该模板的主体为空,这意味着匹配的元素将被忽略(匹配时不会产生任何结果)。

在以下源XML文档上应用此转换时:

<doc> ... 
    <Element name =“ same”> foo </ Element> ...
    <Element fruit =“ apple” animal =“ cat” />
    <Element fruit =“ pear” animal =“ cat” />
    <Element name =“ same”>巴兹</ Element> ...
    <Element name =“ same”> foobar </ Element> ...
</ doc>

所需的结果产生:

<doc> ... 
    <Element name =“ same”> foo </ Element> ...
    <Element fruit =“ pear” animal =“ cat” />
    <Element name =“ same”>巴兹</ Element> ...
    <Element name =“ same”> foobar </ Element> ...
</ doc>

此处可以找到更多使用和覆盖身份模板的代码片段。


13
尽管我什至没有提出正确的问题,但您已经完全回答了我应该问的问题!:)
Grundlefleck

3
那你为什么不把这个帖子标记为正确答案呢?然后它将从未解决的问题列表中消失。
Dirk Vollmar

2
不得不等到我验证它可以正常工作,并且今天没有机会上班。现在完成了,谢谢Dimitre。
Grundlefleck

您能告诉我此xpath表达式的缩写形式/bookstore/book[position() = 1 or position() = 3]/@*吗?
奥雅纳(Arup Rakshit)

2
@Babai ,/*/book[position() = 1 or position() = 3]/@*。在XPath 2.0中:/*/book[position() = (1,3)]/@*
Dimitre Novatchev

3

@Dimitre Novatchev的回答当然既正确又优雅,但是有一个概括(OP并没有问过):如果要过滤的元素还具有要保留的子元素或文本该怎么办?

我相信这种微小的变化可以解决这种情况:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    version="2.0">

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

    <!-- drop DropMe elements, keeping child text and elements -->
    <xsl:template match="DropMe">
        <xsl:apply-templates/>
    </xsl:template>

</xsl:stylesheet>

要指定其他属性等,匹配条件可能很复杂,如果要删除其他内容,则可以使用多个此类模板。

所以这个输入:

<?xml version="1.0" encoding="UTF-8"?>
<mydocument>
    <p>Here's text to keep</p>
    <p><DropMe>Keep this text but not the element</DropMe>; and keep what follows.</p>
    <p><DropMe>Also keep this text and <b>this child element</b> too</DropMe>, along with what follows.</p>
</mydocument>

产生以下输出:

<?xml version="1.0" encoding="UTF-8"?><mydocument>
    <p>Here's text to keep</p>
    <p>Keep this text but not the element; and keep what follows.</p>
    <p>Also keep this text and <b>this child element</b> too, along with what follows.</p>
</mydocument>

感谢XSLT Cookbook

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.