I am trying to remove nodes from an XML file. Using just one XSLT for each of my XML I need to make decisions in the XSLT based upon the number of children of the document element.
<root>
<branch>
<foo>bar</foo>
</branch>
<root>
should transform into
<branch>
</branch>
but
<root>
<branch>
<foo>bar</foo>
</branch>
<branch>
<foo>baz</foo>
<root>
into
<root>
<branch>
</branch>
<branch>
</branch>
<root>
That is, the root element should be removed if its (only) child can act as the new document root of the result XML after applying XSLT. The <foo>
nodes have to be removed in every occurence.
Is there a way to perform this operation with a single XSL?
Try
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root[*[2]]">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="root[* and not(*[2])]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="branch/foo"/>
A simpler, shorter and more generic (no element names hardcoded) solution :
<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()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*[not(*[2])]">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="/*/*/node()"/>
</xsl:stylesheet>
when this transformation is applied on the first provided XML document (corrected to be made well-formed):
<root>
<branch>
<foo>bar</foo>
</branch>
</root>
the wanted, correct result is produced :
<branch></branch>
When the same transformation is applied on the second provided XML document (again needed to be corrected for well-formedness):
<root>
<branch>
<foo>bar</foo>
</branch>
<branch>
<foo>baz</foo>
</branch>
</root>
again the wanted, correct output is produced :
<root>
<branch></branch>
<branch></branch>
</root>
Explanation :
The identity rule copies every node "as-is".
There are two templates that override the identity template for specific nodes and process these nodes in different ways.
The first overriding template matches a top element that doesn't have a second element child. It doesn't copy the element itself, but processes its children.
The second overriding template matches any element that is a grand-child of the top element. This template doesn't have a body, which means that all such matched element are ignored and not included in the output (in other words -- "deleted")
Do note :
This transformation can be applied to any XML document, regardless of the element names in it, and still produces the wanted, correct result.
For example , when applied on this XML document:
<t>
<b>
<f>brrr</f>
</b>
<b>
<f>bzzz</f>
</b>
</t>
the wanted, correct result is produced :
<t>
<b></b>
<b></b>
</t>
Contrast this to the result produced by the currently - accepted answer :
<t>
<b>
<f>brrr</f>
</b>
<b>
<f>bzzz</f>
</b>
</t>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.