Reputation: 11
I am new to using xsl and I am not sure how to remove specific parent nodes and all their children, if all are empty. I think the answer shown in this link is what I need, but I am not sure how to apply this to a specific node instead of the whole stylesheet.
Using what is in that question, I have expanded it ...
<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz></buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds>
</sounds>
</farm>
How can I just eliminate <sounds>
and all of its children (if they are all empty) while leaving empty nodes like foo, bar, and baz. The requirements for the xml I am producing needs to have certain tags present even if they are blank, but some need to be removed if they are blank.
To go even further, if what I had is ...
<farm>
<foo>
<bar>
<baz/>
</bar>
<quux> </quux>
<quuux>Actual content</quuux>
</foo>
<sounds>
<moo>
<meow>
<buzz>"zzzz"</buzz>
</meow>
</moo>
<birds>
<cluck> </cluck>
<quack></quack>
</birds> <!-- Fixed by edit -->
</sounds>
</farm>
In this example,<sounds>, <moo>, <meow>
, and <buzz>
would need to stay since <buzz>
has a value, but <birds>
and its children would need to be removed.
This seems so complicated to me, I am not sure what the simplest way to do this would be.
Thank you so much for your guidance, as I feel dizzy from going in so many circles!
Upvotes: 1
Views: 479
Reputation: 52858
If your processor doesn't support XSLT 3.0, here's an XSLT 1.0 option...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[ancestor-or-self::sounds][not(string())]"/>
</xsl:stylesheet>
Fiddle for example #1: http://xsltfiddle.liberty-development.net/jyH9rNp
Fiddle for example #2: http://xsltfiddle.liberty-development.net/jyH9rNp/1
Upvotes: 2
Reputation: 167446
Assuming XSLT 3 (supported for the Java platform with Saxon 9.8 and 9.9 and for the .NET platform with Saxon 9.8, also by Altova 2017/2018/2019) you could use xsl:where-populated
together with xsl:next-match
for sounds
and any descendant elements and the identity transformation for the rest; additionally you would need to strip white space, otherwise <cluck> </cluck>
would not be removed:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="sounds | sounds//*">
<xsl:where-populated>
<xsl:next-match/>
</xsl:where-populated>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/gWmuiKn/0 has your first input and https://xsltfiddle.liberty-development.net/gWmuiKn/1 your second.
Upvotes: 0