Sowmiya
Sowmiya

Reputation: 25

moving repeating elements into a copy of its parent

If <animal>has more than 1 <xxx> then i need to duplicate <animal> (duplicate count = count of repeating <xxx> within the corresponding<animal> ) and move the repeating <xxx> into another copy.

In my xml <xxx> is repeating twice for the first instance of <animal>, so in output i need to have two <animals>. The first <animal> should contain first instance of <xxx> and second <animal> should contain second instance of <xxx>

Input xml

<?xml version="1.0" encoding="UTF-8"?>
<header>
    <animal>
        <element1>element1</element1>
        <element2>element2</element2>
        <element3 lang="en">element3</element3>
        <xxx>
            <code>YY</code>
            <description>code yy</description>
        </xxx>
        <xxx>
            <code>ZZ</code>
            <description>code zz</description>
        </xxx>
    </animal>
    <animal>
        <xxx>
            <code>AA</code>
            <description>code aa</description>
        </xxx>
    </animal>
</header>

Required required transformation

<?xml version="1.0" encoding="UTF-8"?>
<header>
    <animal>
        <element1>element1</element1>
        <element2>element2</element2>
        <element3 lang="en">element3</element3>
        <xxx>
            <code>YY</code>
            <description>code yy</description>
        </xxx>        
    </animal>
    <animal>
        <element1>element1</element1>
        <element2>element2</element2>
        <element3 lang="en">element3</element3>        
        <xxx>
            <code>ZZ</code>
            <description>code zz</description>
        </xxx>
    </animal>
    <animal>
        <xxx>
            <code>AA</code>
            <description>code aa</description>
        </xxx>
    </animal>
</header>

Any help is much appriciated. Thanks in advance

Upvotes: 0

Views: 197

Answers (1)

Stefan Hegny
Stefan Hegny

Reputation: 2187

My solutions typically are not the most elegant, but this would produce the desired output - have a look...

<?xml version="1.0" encoding="utf-8" standalone="yes"?>

<xsl:transform 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="*|@*">
    <xsl:copy>
        <xsl:apply-templates select="*|@*|text()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="animal">
    <xsl:param name="i" select="xxx[1]"/>
    <xsl:variable name="thisanimal" select="."/>
    <xsl:choose>
        <xsl:when test="count(xxx) = 1">
            <!-- only one here -->
            <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:when test="$i = xxx[1]">
            <!-- more than one here, use the first -->
            <xsl:copy>
                <xsl:apply-templates select="*[name() != 'xxx']"/>
                <xsl:apply-templates select="$i"/>
            </xsl:copy>
            <xsl:for-each select="xxx[position() &gt; 1]">
                <xsl:apply-templates select="$thisanimal">
                    <xsl:with-param name="i" select="."/>
                </xsl:apply-templates>
            </xsl:for-each>
        </xsl:when>
        <xsl:otherwise>
            <!-- more than one here -->
            <xsl:copy>
                <xsl:apply-templates select="*[name() != 'xxx']"/>
                <xsl:apply-templates select="$i"/>
            </xsl:copy>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:transform>

Upvotes: 2

Related Questions