Sai Sooraj
Sai Sooraj

Reputation: 13

Adding elements to tag when conditions match in a loop using XSLT

I'm trying to achieve this in XSLT 1.0 and below are the conditions At any point of time occurrences of ADT are more than occurrences of INF One ADT should have only one surname,firstname and DOB details of INF tag If ADT tags are more than INF tags then first ADT tags should be tagged to INF and rest should ADT tags should not have any INF attached to it. No change to child tag is required but it should be present in the output.

I'm trying to achieve below output using XSLT but couldn't exactly fix it, any help in this will be much appreciated.

Need help in below XSLT for transformation

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <travelerGroup>
            <xsl:for-each select="/travelerGroup/traveler">
                <xsl:if test="travelerInfo/travelerTypeCode != 'INF' ">
                    <traveler>
                        <travelerInfo>
                            <elementNumber>
                                <xsl:value-of select="travelerInfo/elementNumber" />
                            </elementNumber>
                            <travelerTypeCode>
                                <xsl:value-of select="travelerInfo/travelerTypeCode" />
                            </travelerTypeCode>
                            <travelerDetails>
                                <firstName>
                                    <xsl:value-of select="concat(travelerInfo/travelerDetails/firstName" />
                                </firstName>
                                <surname>
                                    <xsl:value-of select="travelerInfo/travelerDetails/surname" />
                                </surname>
                                <xsl:if test="travelerInfo/travelerTypeCode = 'CHD' ">
                                    <dateOfBirth>
                                        <xsl:value-of select="travelerInfo/travelerDetails/dateOfBirth" />
                                    </dateOfBirth>
                                </xsl:if>
                            </travelerDetails>
                            <xsl:if test="travelerInfo/travelerTypeCode != 'CHD' ">
                                <xsl:variable name="i" select="position()" />
                                <xsl:for-each select="/traveler[travelerInfo/travelerTypeCode = 'INF'][$i]">
                                    <xsl:if test="travelerInfo/travelerTypeCode = 'INF' ">
                                        <infant>
                                            <surname>
                                                <xsl:value-of select="travelerInfo/travelerDetails/surname" />
                                            </surname>
                                            <firstName>
                                                <xsl:value-of select="travelerInfo/travelerDetails/firstName" />
                                            </firstName>
                                            <dateOfBirth>
                                                <xsl:value-of select="travelerInfo/travelerDetails/dateOfBirth" />
                                            </dateOfBirth>
                                        </infant>
                                    </xsl:if>
                                </xsl:for-each>
                            </xsl:if>
                        </travelerInfo>
                    </traveler>
                </xsl:if>
            </xsl:for-each>
        </travelerGroup>
    </xsl:template>
</xsl:stylesheet>

Input XML :

<travelerGroup>
<traveler>
    <travelerInfo>
        <elementNumber>1</elementNumber>
        <travelerTypeCode>ADT</travelerTypeCode>
        <travelerDetails>
            <firstName>Adult One</firstName>
            <surname>Surname</surname>
        </travelerDetails>
    </travelerInfo>
</traveler>
<traveler>
    <travelerInfo>
        <elementNumber>2</elementNumber>
        <travelerTypeCode>ADT</travelerTypeCode>
        <travelerDetails>
            <firstName>Adult Two</firstName>
            <surname>Surname</surname>
        </travelerDetails>
    </travelerInfo>
</traveler>
<traveler>
    <travelerInfo>
        <travelerTypeCode>INF</travelerTypeCode>
        <elementNumber>3</elementNumber>
        <travelerDetails>
            <firstName>Infant One</firstName>
            <surname>Surname</surname>
            <dateOfBirth>2016-01-06</dateOfBirth>
        </travelerDetails>
    </travelerInfo>
</traveler>
<traveler>
    <travelerInfo>
        <travelerTypeCode>INF</travelerTypeCode>
        <elementNumber>4</elementNumber>
        <travelerDetails>
            <firstName>Infant Two</firstName>
            <surname>Surname</surname>
            <dateOfBirth>2017-01-06</dateOfBirth>
        </travelerDetails>
    </travelerInfo>
</traveler>
<traveler>
    <travelerInfo>
        <elementNumber>5</elementNumber>
        <travelerTypeCode>ADT</travelerTypeCode>
        <travelerDetails>
            <firstName>Adult Three</firstName>
            <surname>Surname</surname>
        </travelerDetails>
    </travelerInfo>
</traveler>
<traveler>
    <travelerInfo>
        <elementNumber>6</elementNumber>
        <travelerTypeCode>CHD</travelerTypeCode>
        <travelerDetails>
            <firstName>Child One</firstName>
            <surname>Surname</surname>
            <dateOfBirth>2013-01-06</dateOfBirth>
        </travelerDetails>
    </travelerInfo>
</traveler>
</travelerGroup>

Expected Output :

<travelerGroup>
<traveler>
    <elementNumber>1</elementNumber>
    <travelerTypeCode>ADT</travelerTypeCode>
    <travelerDetails>
        <firstName>Adult One</firstName>
        <surname>Surname</surname>
        <middleName />
    </travelerDetails>
    <infant>
        <surname>Infant One</surname>
        <firstName>Surname</firstName>
        <dateOfBirth>2016-01-06</dateOfBirth>
    </infant>
</traveler>
<traveler>
    <elementNumber>2</elementNumber>
    <travelerTypeCode>ADT</travelerTypeCode>
    <travelerDetails>
        <firstName>Adult Two</firstName>
        <surname>Surname</surname>
        <middleName />
    </travelerDetails>
    <infant>
        <surname>Infant Two</surname>
        <firstName>Surname</firstName>
        <dateOfBirth>2017-01-06</dateOfBirth>
    </infant>
</traveler>
<traveler>
    <elementNumber>5</elementNumber>
    <travelerTypeCode>ADT</travelerTypeCode>
    <travelerDetails>
        <firstName>Adult Three</firstName>
        <surname>Surname</surname>
        <middleName />
    </travelerDetails>
</traveler>
 <traveler>
    <elementNumber>6</elementNumber>
    <travelerTypeCode>CHD</travelerTypeCode>
    <travelerDetails>
        <firstName>Child One</firstName>
        <surname>Surname</surname>
        <dateOfBirth>2013-01-06</dateOfBirth>
    </travelerDetails>
</traveler>  
</travelerGroup>   

Upvotes: 0

Views: 634

Answers (1)

Aniket V
Aniket V

Reputation: 3247

There are couple of minor glitches in the output. The values of <firstName> and <surname> for INF are interchanged. Also <middleName> for adult is not present in input but is shown in output. If you need <middleName> in output, you can make necessary changes to the below XSL.

XSLT

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

    <xsl:template match="travelerGroup">
        <xsl:copy>
            <!-- loop through all the adults -->
            <xsl:for-each select="traveler/travelerInfo[travelerTypeCode = 'ADT']">
                <traveler>
                    <xsl:variable name="adtIndex" select="position()" />
                    <!-- copy nodes for adult -->
                    <xsl:copy-of select="@* | node()" />

                    <!-- loop through all infants -->
                    <xsl:for-each select="//traveler/travelerInfo[travelerTypeCode = 'INF']">
                        <xsl:variable name="infIndex" select="position()" />

                        <!-- compare adult node index with infant node index -->
                        <xsl:if test="$adtIndex = $infIndex">
                            <infant>
                                <!-- copy infant nodes within adult -->
                                <xsl:copy-of select="travelerDetails/firstName" />
                                <xsl:copy-of select="travelerDetails/surname" />
                                <xsl:copy-of select="travelerDetails/dateOfBirth" />
                            </infant>
                        </xsl:if>
                    </xsl:for-each>
                </traveler>
            </xsl:for-each>
            <!-- loop through child and copy them as is -->
            <xsl:for-each select="//traveler/travelerInfo[travelerTypeCode = 'CHD']" >
                <traveler>
                    <xsl:copy-of select="@* | node()" />
                </traveler>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Output

<travelerGroup>
    <traveler>
        <elementNumber>1</elementNumber>
        <travelerTypeCode>ADT</travelerTypeCode>
        <travelerDetails>
            <firstName>Adult One</firstName>
            <surname>Surname</surname>
        </travelerDetails>
        <infant>
            <firstName>Infant One</firstName>
            <surname>Surname</surname>
            <dateOfBirth>2016-01-06</dateOfBirth>
        </infant>
    </traveler>
    <traveler>
        <elementNumber>2</elementNumber>
        <travelerTypeCode>ADT</travelerTypeCode>
        <travelerDetails>
            <firstName>Adult Two</firstName>
            <surname>Surname</surname>
        </travelerDetails>
        <infant>
            <firstName>Infant Two</firstName>
            <surname>Surname</surname>
            <dateOfBirth>2017-01-06</dateOfBirth>
        </infant>
    </traveler>
    <traveler>
        <elementNumber>5</elementNumber>
        <travelerTypeCode>ADT</travelerTypeCode>
        <travelerDetails>
            <firstName>Adult Three</firstName>
            <surname>Surname</surname>
        </travelerDetails>
    </traveler>
    <traveler>
        <elementNumber>6</elementNumber>
        <travelerTypeCode>CHD</travelerTypeCode>
        <travelerDetails>
            <firstName>Child One</firstName>
            <surname>Surname</surname>
            <dateOfBirth>2013-01-06</dateOfBirth>
        </travelerDetails>
    </traveler>
</travelerGroup>

Upvotes: 1

Related Questions