Search code examples
xmlxsltxslt-2.0

Optimal method to handle nesting nodes (Different name, same content)


I have to transform an xml message that looks like similar to below. The source content of each node is effectively the same, with a different node name (parentitem, childitem, subchild).

I have inherited an XSLT that addresses the solution by hardcoding each case with little template use, which has significant duplicated XSLT.

I would like to know what options I have to optimise the XSLT to reduce duplicate of XSLT.

I tried to use setup a single template for a generic "node"; then tried to use call-template; However I wasn't able to figure out how to nest objects within the generic

Any help appreciated, Thank you.

<item>
    <itemdetail>
        <parentitem>
            <item>001</item>
            <code1>1</code1>
            <code2>2</code2>
            <itemattribute>
                <item_desc>ParentItem</item_desc>
            </itemattribute>
        </parentitem>
        <childitem>
            <item>002</item>
            <code1>2</code1>
            <code2>2</code2>
            <itemattribute>
                <item_desc>ChildItemLevel1</item_desc>
            </itemattribute>
        </childitem>
        <subchildren>
            <subchild>
                <item>003</item>
                <code1>2</code1>
                <code2>1</code2>
                <itemattribute>
                    <item_desc>SubChild003</item_desc>
                </itemattribute>
            </subchild>
            <subchild>
                <item>004</item>
                <code1>2</code1>
                <code2>1</code2>
                <itemattribute>
                    <item_desc>SubChild004</item_desc>
                </itemattribute>
            </subchild>
        </subchildren>
    </itemdetail>
</item>

There are a few variations of the message The required transformation is required to look similar to below.

  • Parent and Child will only have 0 or 1 instances
  • Child is nested under the Parent
  • SubChild(ren) are nested under the Child
Case parentitem Node ChildItem Present SubChildren Present
Case 1 Y Y Y
Case 2 Y N N
Case 3 Y Y N
Case 4 N Y N
Case 5 N Y Y
Case 6 N N Y

Case 1

<Products>
        <Product type="parentitem">
            <item>001</item>
            <code1>1</code1>
            <code2>2</code2>
            <itemattribute>
                <item_desc>parentitem</item_desc>
            </itemattribute>
            <Product type="childitem">
                <item>002</item>
                <code1>2</code1>
                <code2>2</code2>
                <itemattribute>
                    <item_desc>childitem</item_desc>
                </itemattribute>
                <Product type="subchild">
                    <item>003</item>
                    <code1>2</code1>
                    <code2>1</code2>
                    <itemattribute>
                        <item_desc>SubChild003</item_desc>
                    </itemattribute>
                </Product>
                <Product type="subchild">
                    <item>004</item>
                    <code1>2</code1>
                    <code2>1</code2>
                    <itemattribute>
                        <item_desc>SubChild004</item_desc>
                    </itemattribute>
                </Product>
            </Product>
        </Product>
</Products>

Case 2

<Products>
        <Product type="parentitem">
            <item>001</item>
            <code1>1</code1>
            <code2>2</code2>
            <itemattribute>
                <item_desc>parentitem</item_desc>
            </itemattribute>
        </Product>
</Products>

Case 3

<Products>
        <Product type="parentitem">
            <item>001</item>
            <code1>1</code1>
            <code2>2</code2>
            <itemattribute>
                <item_desc>parentitem</item_desc>
            </itemattribute>
            <Product type="childitem">
                <item>002</item>
                <code1>2</code1>
                <code2>2</code2>
                <itemattribute>
                    <item_desc>childitem</item_desc>
                </itemattribute>
                </Product>
            </Product>
        </Product>
</Products>

Solution

  • Would something like this work for you? I believe it covers even more cases than the 6 you have elaborated.

    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="*"/>
    
    <xsl:template match="itemdetail">
        <Products>
            <xsl:apply-templates select="parentitem"/>
            <xsl:apply-templates select="childitem[not(../parentitem)]"/>
            <xsl:apply-templates select="subchildren[not(../parentitem | ../childitem)]"/>
        </Products>
    </xsl:template>
    
    <xsl:template match="parentitem">
        <Product type="parentitem">
            <xsl:copy-of select="*"/>
            <xsl:apply-templates select="../childitem"/>
            <xsl:apply-templates select="../subchildren[not(../childitem)]"/>
        </Product>
    </xsl:template>
    
    <xsl:template match="childitem">
        <Product type="childitem">
            <xsl:copy-of select="*"/>
            <xsl:apply-templates select="../subchildren"/>
        </Product>
    </xsl:template>
    
    <xsl:template match="subchild">
        <Product type="subchild">
            <xsl:copy-of select="*"/>
        </Product>
    </xsl:template>
    
    </xsl:stylesheet>