<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解决方案在接受和其他答案可能对他人有用.
<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文档的副本,其中具有名称为$removeElementsNamed参数的值的元素的任何出现被删除:
<t> <a> <b/> </a> <c/> <d/> </t>
请注意:In XSLT 1.0 it is syntactically illegal to have a variable or parameter reference inside a template match pattern.这就是为什么@JanThomä和@treeMonkey的解决方案都会引发任何与XSLT 1.0兼容的处理器的错误.
更新:这是一个更复杂的解决方案,允许将元素名称的管道分隔列表删除,以传递给转换:
<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:param name="removeElementsNamed" select="'|x|c|'"/> <xsl:template match="node()|@*" name="identity"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*"> <xsl:if test= "not(contains($removeElementsNamed,concat('|',name(),'|' ) ) ) "> <xsl:call-template name="identity"/> </xsl:if> </xsl:template> </xsl:stylesheet>
当应用于同一XML文档(上图)时,转换再次产生所需的正确输出 – 源XML文档中所有元素的名称在$removeElementsNamed参数中指定 – 已删除:
<t> <a> <b/> </a> <d/> </t>
Update2:与Update1相同的转换,但是用XSLT 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="'|x|c|'"/> <xsl:template match="node()|@*" name="identity"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match= "*[name() = tokenize($removeElementsNamed,'\|')]"/> </xsl:stylesheet>
更新:OP已经添加了要求,也可以删除所有具有特定名称的属性.
这是一个略微修改的转换,以适应这个新的要求:
<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:param name="removeElementsNamed" select="'x'"/> <xsl:param name="removeAttributesNamed" select="'n'"/> <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:template match="@*"> <xsl:if test="not(name() = $removeAttributesNamed)"> <xsl:call-template name="identity"/> </xsl:if> </xsl:template> </xsl:stylesheet>
当这个转换被应用在下面的XML文档(以前使用但添加了几个属性的时候):
<t> <a> <b m="1" n="2"/> <x/> </a> <c/> <x/> <d n="3"/> </t>
产生所需的正确结果(所有名为x的元素和名为n的所有属性都被删除):
<t> <a> <b m="1"/> </a> <c/> <d/> </t>
UPDATE2:再次要求OP,我们现在实现了通过管道分隔的名称列表的功能,以删除具有这些名称的元素,并分别使用以管道分隔的名称列表,以删除具有以下名称的属性:
<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:param name="removeElementsNamed" select="'|c|x|'"/> <xsl:param name="removeAttributesNamed" select="'|n|p|'"/> <xsl:template match="node()|@*" name="identity"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="*"> <xsl:if test= "not(contains($removeElementsNamed,'|') ) ) "> <xsl:call-template name="identity"/> </xsl:if> </xsl:template> <xsl:template match="@*"> <xsl:if test= "not(contains($removeAttributesNamed,'|') ) ) "> <xsl:call-template name="identity"/> </xsl:if> </xsl:template> </xsl:stylesheet>
当将此转换应用于以下XML文档时:
<t> <a p="0"> <b m="1" n="2"/> <x/> </a> <c/> <x/> <d n="3"/> </t>
产生所需的正确结果(名称为c和x的元素以及名称为n和p的属性被删除):
<t> <a> <b m="1"/> </a> <d/> </t>