Dennis van den Brom
Dennis van den Brom

Reputation: 107

Identity transformation in XSLT

I have this source XML:

<?xml version="1.0"?>
<root>
   <item1>
      <name>test</name>
      <price>160</price>
      <stock>4</stock>
      <country>Belgium</country>
   </item1>
   <item2>
      <name>Alfa</name>

      <price>140</price>

      <stock>3</stock>

      <country>Turkey</country>
   </item2>
   <item3>
      <name>Beta</name>

      <price>110</price>

      <stock>48</stock>

      <country>Holland</country>
   </item3>
   <product id="p1">
      <name>Delta</name>

      <price>800</price>

      <stock>4</stock>

      <country>Denmark</country>
   </product>
   <product id="p2">
      <name>Golf</name>

      <price>1000</price>

      <stock>5</stock>

      <country>Germany</country>
   </product>
   <product id="p3">
      <name>Alfa</name>

      <price>1200</price>

      <stock>19</stock>

      <country>Germany</country>
   </product>
   <product id="p4">
      <name>Foxtrot</name>

      <price>1500</price>

      <stock>5</stock>

      <country>Australia</country>
   </product>
   <product id="p5">
      <name>Tango</name>

      <price>1225</price>

      <stock>3</stock>

      <country>Japan</country>
   </product>
</root>

And I want it to look like this:

<?xml version="1.0"?>
<root>
   <action>
      <name>test</name>

      <price>160</price>

      <stock>4</stock>

      <country>Belgium</country>
   </action>
   <action>
      <name>Alfa</name>

      <price>140</price>

      <stock>3</stock>

      <country>Turkey</country>
   </action>
   <action>
      <name>Beta</name>

      <price>110</price>

      <stock>48</stock>

      <country>Holland</country>
   </action>
   <action>
      <name>Delta</name>

      <price>800</price>

      <stock>4</stock>

      <country>Denmark</country>
   </action>
   <action>
      <name>Golf</name>

      <price>1000</price>

      <stock>5</stock>

      <country>Germany</country>
   </action>
   <action>
      <name>Alfa</name>

      <price>1200</price>

      <stock>19</stock>

      <country>Germany</country>
   </action>
   <action>
      <name>Foxtrot</name>

      <price>1500</price>

      <stock>5</stock>

      <country>Australia</country>
   </action>
   <action>
      <name>Tango</name>

      <price>1225</price>

      <stock>3</stock>

      <country>Japan</country>
   </action>
</root>

So the <item1> to <item3> turn into

<action>

And the <product> loses its attribute, and also turns into

<action>

Can somebody show me how to do this with XSLT? Because I have 2 different XSL's now. And I want to combine them to create just one XSL.

Thanks in advance

Upvotes: 6

Views: 13488

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

This transformation:

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

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

 <xsl:template match="product|*[starts-with(name(), 'item')]">
  <action>
   <xsl:apply-templates select="node()|@*"/>
  </action>
 </xsl:template>

 <xsl:template match="product/@id"/>
</xsl:stylesheet>

when applied on the provided XML document:

<root>
    <item1>
        <name>test</name>
        <price>160</price>
        <stock>4</stock>
        <country>Belgium</country>
    </item1>
    <item2>
        <name>Alfa</name>
        <price>140</price>
        <stock>3</stock>
        <country>Turkey</country>
    </item2>
    <item3>
        <name>Beta</name>
        <price>110</price>
        <stock>48</stock>
        <country>Holland</country>
    </item3>
    <product id="p1">
        <name>Delta</name>
        <price>800</price>
        <stock>4</stock>
        <country>Denmark</country>
    </product>
    <product id="p2">
        <name>Golf</name>
        <price>1000</price>
        <stock>5</stock>
        <country>Germany</country>
    </product>
    <product id="p3">
        <name>Alfa</name>
        <price>1200</price>
        <stock>19</stock>
        <country>Germany</country>
    </product>
    <product id="p4">
        <name>Foxtrot</name>
        <price>1500</price>
        <stock>5</stock>
        <country>Australia</country>
    </product>
    <product id="p5">
        <name>Tango</name>
        <price>1225</price>
        <stock>3</stock>
        <country>Japan</country>
    </product>
</root>

produces the wanted, correct result:

<root>
   <action>
      <name>test</name>
      <price>160</price>
      <stock>4</stock>
      <country>Belgium</country>
   </action>
   <action>
      <name>Alfa</name>
      <price>140</price>
      <stock>3</stock>
      <country>Turkey</country>
   </action>
   <action>
      <name>Beta</name>
      <price>110</price>
      <stock>48</stock>
      <country>Holland</country>
   </action>
   <action>
      <name>Delta</name>
      <price>800</price>
      <stock>4</stock>
      <country>Denmark</country>
   </action>
   <action>
      <name>Golf</name>
      <price>1000</price>
      <stock>5</stock>
      <country>Germany</country>
   </action>
   <action>
      <name>Alfa</name>
      <price>1200</price>
      <stock>19</stock>
      <country>Germany</country>
   </action>
   <action>
      <name>Foxtrot</name>
      <price>1500</price>
      <stock>5</stock>
      <country>Australia</country>
   </action>
   <action>
      <name>Tango</name>
      <price>1225</price>
      <stock>3</stock>
      <country>Japan</country>
   </action>
</root>

Explanation:

  1. The identity rule copies every node "as-is".

  2. We have two templates overriding the identity rule. The first template matches any product or any element whose name starts with the string item. It effectively "renames" the matched element to action by creating and outputting an action element.

  3. The second overriding template matches any id attribute of any product element. This template has no body, which effectively "deletes" the matched attribute -- it is not copied/recreated in the output.

Upvotes: 20

John
John

Reputation: 164

You could also just step through it and built it however you like. Ex:

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

    <xsl:template match="/root">
        <xsl:element name="root">
            <xsl:for-each select="node()">
                <xsl:element name="action">
                    <xsl:element name="name"><xsl:value-of select="name"/></xsl:element>
                    <xsl:element name="price"><xsl:value-of select="price"/></xsl:element>
                    <xsl:element name="stock"><xsl:value-of select="stock"/></xsl:element>
                    <xsl:element name="country"><xsl:value-of select="country"/></xsl:element>
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 0

Martin Honnen
Martin Honnen

Reputation: 167446

Sounds easy:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

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

  <xsl:template match="root/*">
    <action>
      <xsl:apply-templates/>
    </action>
  </xsl:template>

</xsl:stylesheet>

If you want us to combine your existing code you need to post it.

Upvotes: 2

Related Questions