KM6895
KM6895

Reputation: 89

How to Insert an XML tag after a particular tag using XSLT?

Hi – I would your help to transform following input XML using XSLT

<?xml version="1.0" encoding="UTF-8"?>
<Employee>
    <Summary>
        <Employee_ID>12345</Employee_ID>
        <Name>Mel Gibson</Name>
    </Summary>
    <Personal>
        <First_Name>Mel</First_Name>
        <Middle_Name>Samuel</Middle_Name>
        <Gender>Male</Gender>
    </Personal>
    <Status>
        <Active>Yes</Active>
        <Base_Location>Boston</Base_Location>
    </Status>
    <Summary_Information>
        <Location>California</Location>
        <Last_Formatted_Name>Samuel Gibson</Last_Formatted_Name>
    </Summary_Information>
</Employee>

Requirements for transforming above XML is:

If Last_Name doesn’t exist in input XML, a node Last_Name should be created right after First_Name node and should hold the value of Last_Formatted_Name

Output should look like below. Please note Last_Name node is created right after First_Name and Last_Formatted_Name node is removed.

<?xml version="1.0" encoding="UTF-8"?>
<Employee>
    <Summary>
        <Employee_ID>12345</Employee_ID>
        <Name>Mel Gibson</Name>
    </Summary>
    <Personal>
        <First_Name>Mel</First_Name>
        <Last_Name>Samuel Gibson</Last_Name>
        <Middle_Name>Samuel</Middle_Name>
        <Gender>Male</Gender>
    </Personal>
    <Status>
        <Active>Yes</Active>
        <Base_Location>Boston</Base_Location>
    </Status>
    <Summary_Information>
        <Location>California</Location>
    </Summary_Information>
</Employee>

I have written following XSLT (with the help of another stackoverflow post). However, Last_Name is being inserted as last tag under ‘Personal’ where as ‘Last_Name’ should be inserted right after ‘First_Name’ tag.

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

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

    <!-- modifies the value of <Last_Name> if it exists -->
    <xsl:template match="Last_Name">
        <xsl:copy>
            <xsl:value-of select="../../Summary_Information/Last_Formatted_Name" />
        </xsl:copy>
    </xsl:template>

    <!-- if <Last_Name> does not exist, creates a last name with the appropriate value -->
    <xsl:template match="Personal[not(Last_Name)]">
        <xsl:copy>
            <xsl:apply-templates />
            <Last_Name>
                <xsl:value-of select="../Summary_Information/Last_Formatted_Name" />
            </Last_Name>
        </xsl:copy>
    </xsl:template>

    <!-- removes the node -->
    <xsl:template match="Last_Formatted_Name" />
</xsl:stylesheet>

With above XSLT, I’m getting following result. How should I change my XSLT to insert Last_Name just after First_Name tag.

<?xml version="1.0" encoding="UTF-8"?>
<Employee>
    <Summary>
        <Employee_ID>12345</Employee_ID>
        <Name>Mel Gibson</Name>
    </Summary>
    <Personal>
        <First_Name>Mel</First_Name>
        <Middle_Name>Samuel</Middle_Name>
        <Gender>Male</Gender>
        <Last_Name>Samuel Gibson</Last_Name>
    </Personal>
    <Status>
        <Active>Yes</Active>
        <Base_Location>Boston</Base_Location>
    </Status>
    <Summary_Information>
        <Location>California</Location>
    </Summary_Information>
</Employee>

Upvotes: 2

Views: 2839

Answers (1)

Daniel Haley
Daniel Haley

Reputation: 52858

You can apply-templates to First_Name, create the new Last_Name, and then apply-templates to everything else.

Example...

<xsl:template match="Personal[not(Last_Name)]">
  <xsl:copy>
    <xsl:apply-templates select="First_Name"/>
    <Last_Name>
      <xsl:value-of select="../Summary_Information/Last_Formatted_Name" />
    </Last_Name>
    <xsl:apply-templates select="*[not(self::First_Name)]"/>
  </xsl:copy>
</xsl:template>

Upvotes: 1

Related Questions