Sri-nidhi
Sri-nidhi

Reputation: 25

XSLT for nested parent elements

I'm new to XSLT and I have an XML file that I'm trying to convert as a '|' delimited CSV using XSLT. There is a single cell value in CSV that needs to be computed by looping through the current and parent nodes under TPFC and concatenate all the names as the single name (Note: The parent nesting can be one or more, Here I have 2 parents in my example)

For example, the name for the below XML will be AM_Mob1_Mob2

<?xml version="1.0" encoding="UTF-8"?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Package ID="1122" BusinessID="001233" Version="19.0.2" xsi:type="Doms">
    <Name>ABC</Name>
    <Description> Desc sample</Description>
    <Category>54</Category>
    <Business_ID>001233</Business_ID>

    <TPFC ID="76" xsi:type="TPFC" Pattern="Th_Branch">
        <Name>AM</Name>
        <Parent ID="11d" xsi:type="TPFC" Pattern="Th_Branch">
            <Description>Mob1</Description>
            <Name>Mob1</Name>
            <Parent ID="12F" xsi:type="TPFC" Pattern="Th_Branch">
            <Description>Mob2</Description>
            <Name>Mob2</Name>
            </Parent>
        </Parent>
    </TPFC>
</Package>

I tried out the params method, I'm not sure if that is the right approach but anyway I did not get the output when I tried the below snippet

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" >
<xsl:output method="text" encoding="utf-8"/>
<!--  Delimiter  -->
<xsl:variable name="separator" select="'|'"/>
<xsl:template match="/">
<xsl:for-each select="//TPFC ">
           <!--Nesting logic ends here-->
           <xsl:param name="Concatvar">
           <xsl:for-each select="Parent/Name">
           <xsl:if test="Parent/Name">
           <xsl:value-of select="concat($Concatvar,Parent/Name/text())"/>
           </xsl:if>
           </xsl:for-each>
           </xsl:param>
            <xsl:value-of select="$Concatvar"/>
            <xsl:value-of select="$separator"/>
            <--Nesting logic ends here--!>
            <xsl:value-of select="normalize-space(Name)"/>
            <xsl:value-of select="$separator"/>
            <xsl:value-of select="normalize-space(Description)"/>
            <xsl:value-of select="$separator"/>
            <xsl:value-of select="normalize-space(Parent/Name)"/>
</xsl:template>

</xsl:stylesheet>

Can anyone tell me what would be the right way to write XSLT for this expected result

  | id           | name | description | parent_name | parent_id   | level | total_level | product_offering_id | 
  | AM_Mob1_Mob2 | AM   | Desc Sample | Mob1        | Mob1_Mob2_ | 2     | 3           | 001233              | 

id - Concatenation of all names to its root parent in the below example it will be AM_Mob1_Mob2

level - if there are two levels, child is level 2 and parent is level 1

total_level - depth of the tree from TPFC + 1 i.e. no.of levels in product family hierarchy

Upvotes: 0

Views: 430

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116959

I am afraid the logic that needs to be applied here is not clear enough.

See if this can get you started:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>

<xsl:template match="/Root">
    <!-- header -->
    <xsl:text>id|name|description|parent_name|parent_id|... &#10;</xsl:text>
    <!-- data -->
    <xsl:for-each select="Package">
        <xsl:variable name="pkg-desc" select="Description" />
        <xsl:variable name="b-id" select="Business_ID" />
        <!-- TPFC data -->
        <xsl:for-each select="TPFC">
            <xsl:value-of select="Name, .//Parent/Name" separator="_"/>
            <xsl:text>|</xsl:text>
            <xsl:value-of select="Name"/>
            <xsl:text>|</xsl:text>
            <xsl:value-of select="$pkg-desc"/>
            <xsl:text>|</xsl:text>
            <!-- parent data -->
            <xsl:value-of select="Parent/Name"/>
            <xsl:text>|</xsl:text>
            <xsl:value-of select=".//Parent/Name" separator="_"/>
            <xsl:text>|</xsl:text>
            <!-- ??? -->

        </xsl:for-each>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each> 
</xsl:template>

</xsl:stylesheet>

Applied to the supplied input example, the result will be:

id|name|description|parent_name|parent_id|... 
AM_Mob1_Mob2|AM| Desc sample|Mob1|Mob1_Mob2|

Upvotes: 2

Michael Kay
Michael Kay

Reputation: 163262

This kind of thing is very much easier in XSLT 2.0 or 3.0 (but older XSLT processors only support 1.0). Your stylesheet specifies version="2.0", but you haven't tagged the question xslt-2, so I'm assuming XSLT 2.0 is available to you.

In 2.0 you can achieve the required output by writing

<xsl:value-of select="Name, Parent/Name" separator="_"/>

In 1.0 you'll need something like your current logic, but note that (a) you should be using xsl:variable rather than xsl:param, and (b) within xsl:for-each, the context item changes, so within <xsl:for-each select="Parent/Name"> you should select ., not Parent/Name.

Upvotes: 1

Related Questions