Как удалить элементы из xml с помощью xslt со списком стилей и xsltproc?

У меня есть много файлов XML, которые имеют что-то вроде формы:

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

Что я хочу удалить из файла.

С помощью таблицы стилей XSLT и утилиты командной строки Linux xsltproc, как я могу это сделать?

К этому моменту в script у меня уже есть список файлов, содержащих элемент, который я хочу удалить, поэтому один файл может использоваться как параметр.


РЕДАКТИРОВАТЬ: вопрос изначально отсутствовал в намерении.

То, что я пытаюсь достичь, - удалить весь элемент "Элемент", где (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" />

Ответ 1

Используя один из самых фундаментальных шаблонов проектирования 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>

Обратите внимание на, как второй шаблон переопределяет шаблон идентичности (1-й) только для элементов с именем "Элемент", которые имеют атрибут "фрукты" со значением "яблоко" и атрибут "животное" со значением "Кот". Этот шаблон имеет пустое тело, что означает, что согласованный элемент просто игнорируется (ничего не получается, когда оно сопоставляется).

Когда это преобразование применяется к следующему исходному XML-документу:

<doc>... 
    <Element name="same">foo</Element>...
    <Element fruit="apple" animal="cat" />
    <Element fruit="pear" animal="cat" />
    <Element name="same">baz</Element>...
    <Element name="same">foobar</Element>...
</doc>

получается желаемый результат:

<doc>... 
    <Element name="same">foo</Element>...
    <Element fruit="pear" animal="cat"/>
    <Element name="same">baz</Element>...
    <Element name="same">foobar</Element>...
</doc>

Дополнительные фрагменты кода использования и переопределения шаблона идентификации можно найти здесь.

Ответ 2

Ответ @Dimitre Novatchev, безусловно, правильный и элегантный, но есть обобщение (о котором ОП не спрашивал): что, если элемент, который вы хотите отфильтровать, также имеет дочерние элементы или текст, который вы хотите сохранить?

Я считаю, что этот незначительный вариант охватывает этот случай:

<?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 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 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.