0
votes

I am new in XSLT. I would like to change a root node in XML base on condition of other child node. but keep the child nodes always same. For example, I have following XML:

   <Root1>
    ................
    ................

    <Root2>
    ................
    ................

        <AnimalOrPlant>
             <Type>A</Type>
              <Food1>Something</Food1>
              <Food2>Somthing11</Food2>
              <Name>ant</Name>
              <Color>Black</GIIN>
              <Waterconsumption>5lt</Waterconsumption>
        </AnimalOrPlant>  
    ................
    ................

    </Root2>
    ................
    ................
</Root1>

I like to change XML to:

<Root1>
    ................
    ................
    <Root2>
    ................
    ................
        <Animal>
             <Type>A</Type>
              <Food1>Something</Food1>
              <Food2>Somthing11</Food2>
              <Name>ant</Name>
              <Color>Black</Color>
              <Waterconsumption>5lt</Waterconsumption>
        </Animal>
     ................
    ................ 
    </Root2>
    ................
    ................
</Root1>

That means depents on <type> = A, I have change node <AnimalOrPlant> to <Animal>. If the <Type> = P, I will change it to <Plant>.I have write the following XSLT:

<xsl:template match="Root1">
 <xsl:choose>
    <xsl:when test="Root2/AnimalOrPlant/Type='A'">
        <Animal>
            <xsl:element name ="Type">
              <xsl:value-of select="Root2/AnimalOrPlant/Type"/>
            </xsl:element>
            <xsl:element name ="Food1">
              <xsl:value-of select="Root2/AnimalOrPlant/Food1"/>          
            </xsl:element>
            <xsl:element name ="Food2">
              <xsl:value-of select="Root2/AnimalOrPlant/Food2"/>
            </xsl:element>
            <xsl:element name ="Name">
              <xsl:value-of select="<xsl:value-of select="Root2/AnimalOrPlant/Name"/>
            </xsl:element>
            <xsl:element name ="Color">
              <xsl:value-of select="<xsl:value-of select="Root2/AnimalOrPlant/Color"/>
            </xsl:element>
            <xsl:element name ="Waterconsumption">
              <xsl:value-of select="<xsl:value-of select="Root2/AnimalOrPlant/Waterconsumption"/>
            </xsl:element>
        </Animal>
    </xsl:when>
    <xsl:when test="Root2/AnimalOrPlant/Type='P'">
        <Plant>
            <xsl:element name ="Type">
              <xsl:value-of select="Root2/AnimalOrPlant/Type"/>
            </xsl:element>
            <xsl:element name ="Food1">
              <xsl:value-of select="Root2/AnimalOrPlant/Food1"/>          
            </xsl:element>
            <xsl:element name ="Food2">
              <xsl:value-of select="Root2/AnimalOrPlant/Food2"/>
            </xsl:element>
            <xsl:element name ="Name">
              <xsl:value-of select="<xsl:value-of select="Root2/AnimalOrPlant/Name"/>
            </xsl:element>
            <xsl:element name ="Color">
              <xsl:value-of select="<xsl:value-of select="Root2/AnimalOrPlant/Color"/>
            </xsl:element>
            <xsl:element name ="Waterconsumption">
              <xsl:value-of select="<xsl:value-of select="Root2/AnimalOrPlant/Waterconsumption"/>
            </xsl:element>
        </Plant>
    </xsl:when>
</xsl:choose>   
</xsl:template>

I don't want to repeat the child nodes in every <when> condition. Because there will be several different types. How can I achieve this?

2

2 Answers

0
votes

I would suggest you try it this way:

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="*"/>

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

<xsl:template match="AnimalOrPlant">
    <xsl:variable name="name">
        <xsl:choose>
            <xsl:when test="Type='A'">Animal</xsl:when>
            <xsl:when test="Type='P'">Plant</xsl:when>
            <xsl:otherwise>Unknown</xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:element name="{$name}">
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

Note: This has nothing to do with the root node or even with the root element.

0
votes

This is straight-forward, if you learn about the XSLT identity template

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

This copies all existing nodes in your XML, so you only have to worry about the nodes you want to change. You just write templates to match these ones. For example, to turn the AnimalOrPlant elements, with Type of A, into the Animal ones, do this:

<xsl:template match="AnimalOrPlant[Type='A']">
    <Animal>
        <xsl:apply-templates select="@*|node()"/>
    </Animal>
</xsl:template>

Try this XSLT

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

    <xsl:template match="AnimalOrPlant[Type='A']">
        <Animal>
            <xsl:apply-templates select="@*|node()"/>
        </Animal>
    </xsl:template>

    <xsl:template match="AnimalOrPlant[Type='P']">
        <Plant>
            <xsl:apply-templates select="@*|node()"/>
        </Plant>
    </xsl:template>

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