Ady211
Ady211

Reputation: 13

Remove parent node if child node is empty

I am trying to transform a given XML using xslt. The caveat is that I would have to delete a parent node if a given child node is not present. I did do some template matching, but I am stuck. Any help would be appreciated.

The input xml :

<?xml version="1.0" encoding="UTF-8"?>
<main>
     <item>
        <value>
           <item>
              <value>ABC</value>
              <key>test1</key>
           </item>
           <item>
              <value>XYZ</value>
              <key>test2</key>
           </item>
               <item>
              <value></value>
              <key>test3</key>
           </item>
        </value>
     </item>
     <item>
        <value />
        <key>test4</key>
     </item>
     <item>
        <value>PQR</value>
        <key>test5</key>
     </item>
</main>

Expected Output:

<?xml version="1.0" encoding="UTF-8"?>
<main>
     <item>
        <value>
           <item>
              <value>ABC</value>
              <key>test1</key>
           </item>
           <item>
              <value>XYZ</value>
              <key>test2</key>
           </item>
        </value>
     </item>
     <item>
        <value>PQR</value>
        <key>test5</key>
     </item>
</main>

The issue is if I use template matching e.g.

<xsl:template match="item[not(value)]"/> as mentioned in deleting the parent node if child node is not present in xml using xslt, then it completely removes everything as main/item/value is also empty.

What I need is remove if element is empty but only do if element has no child element.

Upvotes: 1

Views: 3708

Answers (3)

michael.hor257k
michael.hor257k

Reputation: 116993

If I read this correctly, you want to do:

XSLT 1.0

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

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

<xsl:template match="item[not(value[node()])]"/>

</xsl:stylesheet>

This will remove any item that does not have a value child with some content.

Upvotes: 0

Tim C
Tim C

Reputation: 70618

You should first start with the XSLT identity template

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

Then, all you need is a template that matches the item element where all descendent leaf value elements are empty.

 <xsl:template match="item[not(descendant::value[not(*)][normalize-space()])]" />

So, the template matches it, but doesn't output it.

Try this XSLT

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

    <xsl:template match="item[not(descendant::value[not(*)][normalize-space()])]" />

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

Upvotes: 1

jdk
jdk

Reputation: 159

I think you want to remove the element of it has no children at all (whether those children be elements or text nodes). Try inserting this template:

<xsl:template match="item">
    <xsl:if test="exists(value/node())">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

Upvotes: 0

Related Questions