0
votes

I have the following XML document:

<?xml version="1.0" encoding="utf-8"?>
<greatGrandParent>
    <grandParent>
        <parent>
            <sibling>Fred</sibling>
            <sibling>Max</sibling>
            <sibling>Katie</sibling>
        </parent>
        <parent>
            <sibling>Lindy</sibling>
            <sibling>Richard</sibling>
        </parent>
        <parent>
            <sibling />
        </parent>
    </grandParent>
    <grandParent>
        <parent>
            <sibling>Steve</sibling>
            <sibling>Abbas</sibling>
        </parent>
        <parent>
            <sibling>Kate</sibling>
            <sibling>James</sibling>
            <sibling>Ian</sibling>
        </parent>
    </grandParent>
    <grandParent>
        <parent>
            <sibling />
        </parent>
    </grandParent>
</greatGrandParent>

My requirement is - to remove an XML node if all of its child elements are empty. For instance, in the above shown XML,

  • the 3rd parent of the 1st grandParent has no siblings. Hence, the sibling should be removed. And since the parent has no siblings, the parent should be removed as well from the XML. But, the grandParent would still exist since it has other parents with siblings.

  • The only parent within the 3rd grandparent has no siblings. Hence, the sibling needs to be removed. And since the parent has no sibling, the parent should be removed as well. Since, the grandParent has no child elements(parent), the grandParent must also be removed from the XML.

Hence, the resulting XML must look like:

<?xml version="1.0" encoding="utf-8"?>
<greatGrandParent>
    <grandParent>
        <parent>
            <sibling>Fred</sibling>
            <sibling>Max</sibling>
            <sibling>Katie</sibling>
        </parent>
        <parent>
            <sibling>Lindy</sibling>
            <sibling>Richard</sibling>
        </parent>
    </grandParent>
    <grandParent>
        <parent>
            <sibling>Steve</sibling>
            <sibling>Abbas</sibling>
        </parent>
        <parent>
            <sibling>Kate</sibling>
            <sibling>James</sibling>
            <sibling>Ian</sibling>
        </parent>
    </grandParent>
</greatGrandParent>

I'd be glad if somebody can suggest me a solution to do this using any Java API or XSLT.

1

1 Answers

3
votes

You could use the following XSLT for this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="fn xs">
        <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
        <xsl:template match="node()|@*">
                <xsl:if test="normalize-space(string(.)) != ''">
                        <xsl:copy>
                                <xsl:apply-templates select="node()|@*"/>
                        </xsl:copy>
                </xsl:if>
        </xsl:template>
</xsl:stylesheet>

To get an idea of how it works, execute the next XSLT that gives you an extra element on grandParent node, also read this little tutorial: http://www.xmlplease.com/xsltidentity

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="grandParent">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <childValues><xsl:value-of select="normalize-space(.)" /></childValues>
            <xsl:apply-templates select="node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>