Удаление элементов и / или атрибутов по имени для параметров XSL
следующая задача удаления нежелательных элементов и атрибутов по имени ("removeMe" в этом примере) из XML-файла:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node() | @*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="removeMe"/>
</xsl:stylesheet>
проблемы в том, что он не различает элементы и атрибуты, имя жестко закодировано, и оно может принимать только одно имя. как это можно переписать, чтобы использовать пару входных параметров, как показано ниже, для удаления одного или нескольких конкретных элементов и/или атрибутов?
<xsl:param name="removeElementsNamed"/>
<xsl:param name="removeAttributesNamed"/>
желаемый результат возможность удаления один или несколько элементы и/или один или несколько атрибуты, все еще различая элементы и атрибуты (другими словами, должна быть возможность удалить все "время"элементов без удалить все "время" атрибуты).
хотя я требовал XSLT 1.0 в этом раунде, решения XSLT 2.0 в принятых и других ответах могут быть полезны для другие.
4 ответов
трансформация:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="removeElementsNamed" select="'x'"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:if test="not(name() = $removeElementsNamed)">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
при применении к любому XML-документу, скажите это:
<t>
<a>
<b/>
<x/>
</a>
<c/>
<x/>
<d/>
</t>
производит требуемый правильный результат-копию исходного XML-документа, в котором любое появление элемента, имеющего имя, которое является значением
вот опция XSLT 2.0, Если вы можете использовать 2.0. Имена элементов могут передаваться через запятую, вкладку,канал или пробел.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="removeElementsNamed" select="'bar,baz'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[name()=tokenize($removeElementsNamed,'[\|, \t]')]"/>
</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="removeMe"/>
<xsl:template match="node() | @*">
<xsl:if test="not(name(.)=$removeMe)">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Это somehwat hacky, но это может дать вам общее представление:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="removeElementsNamed"/>
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[contains($removeElementsNamed, concat(',',name(),','))]"/>
вам нужно указать имена элементов для удаления в виде списка, разделенного запятыми, начиная с запятой и заканчивая запятой, например,значение", foo,bar, baz" удалит все элементы с именем foo bar или baz. Если у вас нет каких-либо элементов, которые являются частичными именами других элементов, вы можете упростить это до:
<xsl:template match="*[contains($removeElementsNamed,name())]"/>
однако, если у вас есть XML, как
<foo>
<bar>..<bar>
<barbara>..</barbara>
<foo>
и используйте " bar " в качестве параметра, это удалит теги bar и barbara, поэтому первый подход безопаснее.