The following does the job of removing unwanted elements and attributes by name ("removeMe" in this example) from an XML file:
<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>
The problems are it does not distinguish between elements and attributes, the name is hard-coded, and it can only take one name. How could this be rewritten to use a couple input parameters like below to remove one or more specific elements and/or attributes?
<xsl:param name="removeElementsNamed"/>
<xsl:param name="removeAttributesNamed"/>
The desired result is the ability to remove one or more elements and/or one or more attributes while still distinguishing between elements and attributes (in other words, it should be possible to remove all "time" elements without also removing all "time" attributes).
While I required XSLT 1.0 this round, XSLT 2.0 solutions in accepted and other answers may be useful to others.
This is somehwat hacky, but it might give you the general idea:
You need to specify the element names to remove as a comma separated list, starting with a comma and ending with a comma, e.g. the value ",foo,bar,baz," will remove all elements named foo bar or baz. If you don't have any elements that are partial names of other elements you can simplify this to:
However if you have an XML like
and use "bar" as parameter, this will delete both the bar and barbara tags, so the first approach is safer.
Here's an XSLT 2.0 option if you can use 2.0. The element names can be passed as comma, tab, pipe, or space separated.
This transformation:
when applied on any XML document, say this:
produces the wanted correct result -- a copy of the source XML document in which any occurence of element having the name that is the value of the
$removeElementsNamed
parameter, is deleted:Do note: In XSLT 1.0 it is syntactically illegal to have a variable or parameter reference inside a template match pattern. This is why the solutions by @Jan Thomä and @treeMonkey both raise an error with any XSLT 1.0 - compliant processor.
Update: Here is a more complicated solution, that allows a pipe-separated list of element names - to be deleted, to be passed to the transformation:
When applied to the same XML document (above), the transformation produces again the wanted, correct output -- the source XML document with all elements whose name are specified in the
$removeElementsNamed
parameter -- deleted:Update2: The same transformation as in Update1, but written in XSLT 2.0:
Update: The OP has added the requirement to also be able to delete all attributes that have some specific name.
Here is the slightly modified transformation to accomodate this new requirement:
When this transformation is applied on the XML document below (the one used before but with a few attributes added):
the wanted, correct result is produced (all elements named
x
and all attributes namedn
are deleted):UPDATE2: As again requested by the OP, we now implement the capability to pass pipe-separated list of names for the deletion of elements with these names and respectively a pipe-separated list of names for the deletion of attributes with these names:
When this transformation is applied on the following XML document:
the wanted, correct result is produced (elements with names
c
andx
and attributes with namesn
andp
are deleted):