This conversion is :
<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:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match= "attributes[not(node())] | attribute[not(attributeName/text())] "/> </xsl:stylesheet>
when applied to this XML document (note the empty <attributes> and attribute/attributeName at the end):
<attributes> <attribute> <attributeName>agenda-group</attributeName> <value>generic</value> </attribute> <attribute> <attributeName>auto-focus</attributeName> <value>true</value> </attribute> <attribute> <attributeName>no-loop</attributeName> <value>true</value> </attribute> <attribute> <attributeName>salience</attributeName> <value>73</value> </attribute> <attribute> <attributeName></attributeName> <value></value> </attribute> <attributes/> </attributes>
creates the desired result (empty elements are ignored - not copied):
<attributes> <attribute> <attributeName>agenda-group</attributeName> <value>generic</value> </attribute> <attribute> <attributeName>auto-focus</attributeName> <value>true</value> </attribute> <attribute> <attributeName>no-loop</attributeName> <value>true</value> </attribute> <attribute> <attributeName>salience</attributeName> <value>73</value> </attribute> </attributes>
Explanation : The identity rule (which each node copies as is) is overridden by a single template that matches the desired "empty" elements and does not have a body, so they are simply skipped / ignored.
source share