Как удалить элементы из 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.