Search code examples
xslt-2.0

Block XML elements if underneath item is missing or blank


I have an xml file which is generated by a process. This xml may have many products and Items under each product. However, there are scenarios when product can have no items underneath as shown in the example below. In this situation, I want xml not to generate products where there is not item. I want xsl script which should be able to do this. Can anyone please help? The input xml file is

    <?xml version="1.0" encoding="UTF-8"?>
    <products>
        <product>
            <prod id>P16754</prod id>
            <product-status>CREATED</product-status>
            <validation-status>Valid</validation-status>
            <duplication-status>Unique</duplication-status>
            <content-status>New</content-status>
    <items/>

            <created-on>2016-08-12T11:30:00</created-on>
            <created-by>Administrator</created-by>
            <last-changed-on>2016-08-04T17:34:00</last-changed-on>
            <last-changed-by>ap0712</last-changed-by>
            <delete>false</delete>
        </product>
    <product>

        <prod id>P16754</prod id>
        <product-status>CREATED</product-status>
        <validation-status>Valid</validation-status>
        <duplication-status>Unique</duplication-status>
        <content-status>New</content-status>
<items>
     <item>
            <item id>i16754</item id>
            <item-status>CREATED</item-status>
            <validation-status>Valid</validation-status>
            <duplication-status>Unique</duplication-status>
            <content-status>New</content-status>
    </item>
<items/>

        <created-on>2016-08-12T11:30:00</created-on>
        <created-by>Administrator</created-by>
        <last-changed-on>2016-08-04T17:34:00</last-changed-on>
        <last-changed-by>ap0712</last-changed-by>
        <delete>false</delete>
    </product>
</products>

Since the first product does not have item so this product as well as item should be removed from the output xml. The output should be

<products>
    <product>
        <prod id>P16754</prod id>
        <product-status>CREATED</product-status>
        <validation-status>Valid</validation-status>
        <duplication-status>Unique</duplication-status>
        <content-status>New</content-status>
<items>
     <item>
            <item id>i16754</item id>
            <item-status>CREATED</item-status>
            <validation-status>Valid</validation-status>
            <duplication-status>Unique</duplication-status>
            <content-status>New</content-status>
    </item>
<items/>

        <created-on>2016-08-12T11:30:00</created-on>
        <created-by>Administrator</created-by>
        <last-changed-on>2016-08-04T17:34:00</last-changed-on>
        <last-changed-by>ap0712</last-changed-by>
        <delete>false</delete>
    </product>
</products>

The code I am using to achieve based upon suggestions here is

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

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

 <xsl:template match="Prod ID[not(items/item)]"/> 

</xsl:stylesheet>

I see that it deletes the product and item if it is blank but I am getting the following in the output for example xslt code is coming in the output

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
        <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="Prod ID[not(items/item)]"/>
    </xsl:stylesheet>

Solution

  • Any time you want to transform a document and only make some changes you start with the identity transformation template

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

    and then you add templates for those elements you want to transform. If you want to delete an element then you add an empty template matching that element, as you want to remove all product elements not having item elements you use

    <xsl:template match="product[not(items/item)]"/>
    

    So all you need is

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="product[not(items/item)]"/>
    
    </xsl:transform>
    

    which transforms the corrected input

    <?xml version="1.0" encoding="UTF-8"?>
    <products>
        <product>
            <prod-id>P16754</prod-id>
            <product-status>CREATED</product-status>
            <validation-status>Valid</validation-status>
            <duplication-status>Unique</duplication-status>
            <content-status>New</content-status>
            <items/>
    
            <created-on>2016-08-12T11:30:00</created-on>
            <created-by>Administrator</created-by>
            <last-changed-on>2016-08-04T17:34:00</last-changed-on>
            <last-changed-by>ap0712</last-changed-by>
            <delete>false</delete>
        </product>
        <product>
    
            <prod-id>P16754</prod-id>
            <product-status>CREATED</product-status>
            <validation-status>Valid</validation-status>
            <duplication-status>Unique</duplication-status>
            <content-status>New</content-status>
            <items>
                <item>
                    <item-id>i16754</item-id>
                    <item-status>CREATED</item-status>
                    <validation-status>Valid</validation-status>
                    <duplication-status>Unique</duplication-status>
                    <content-status>New</content-status>
                </item>
            </items>
    
            <created-on>2016-08-12T11:30:00</created-on>
            <created-by>Administrator</created-by>
            <last-changed-on>2016-08-04T17:34:00</last-changed-on>
            <last-changed-by>ap0712</last-changed-by>
            <delete>false</delete>
        </product>
    </products>
    

    into the output

    <?xml version="1.0" encoding="UTF-8"?><products>
    
        <product>
    
            <prod-id>P16754</prod-id>
            <product-status>CREATED</product-status>
            <validation-status>Valid</validation-status>
            <duplication-status>Unique</duplication-status>
            <content-status>New</content-status>
            <items>
                <item>
                    <item-id>i16754</item-id>
                    <item-status>CREATED</item-status>
                    <validation-status>Valid</validation-status>
                    <duplication-status>Unique</duplication-status>
                    <content-status>New</content-status>
                </item>
            </items>
    
            <created-on>2016-08-12T11:30:00</created-on>
            <created-by>Administrator</created-by>
            <last-changed-on>2016-08-04T17:34:00</last-changed-on>
            <last-changed-by>ap0712</last-changed-by>
            <delete>false</delete>
        </product>
    </products>
    

    online at http://xsltransform.net/bFWR5DD.