Ganeshkumar
Ganeshkumar

Reputation: 61

how to change node name and copy data of that node in xml to another using xslt

My base XML is like

<?xml version="1.0" encoding="iso-8859-1"?>
<Report version="1.0">
  <sourceName Identification="xyz"/>
  <sourcesys Identification="mycomp">
    <Manager>
      <ManagerNo>1023114455</ManagerNo>
      <Address>Delhi,India</Address>
      <Currency>
        <CurrencyType>Rupee</CurrencyType>
      </Currency>
    </Manager>
    <Manager>
      <ManagerNo>236784455</ManagerNo>
      <Address>California,USA</Address>
      <Currency>
        <CurrencyType>Dollar</CurrencyType>
      </Currency>
    </Manager>
  </sourcesys>
</Report>

I want to convert this XML to the following one

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ManagerDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <ManagerDetail>
    <ManagerNo>1023114455</ManagerNo>
    <Address>
      <PermenantAdd>California,USA</PermenantAdd>
    </Address>
    <CurrencyID>Rupee</CurrencyID>
  </ManagerDetail>
  <ManagerDetail>
    <ManagerNo>236784455</ManagerNo>
    <Address>
      <PermenantAdd>Delhi,India</PermenantAdd>
    </Address>
    <CurrencyID>Dollar</CurrencyID>
  </ManagerDetail>
</managerDetails>

Here is the mapping of the tags:

How would you do this with an XSLT?

Upvotes: 0

Views: 155

Answers (2)

Tim C
Tim C

Reputation: 70598

For transformations like this, you should be building upon the identity template which by itself copies all the nodes in your XSLT

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

This means you only need to write templates for nodes you wish to transform (which, having said that, is all by the ManagerNo element).

To transform sourcesys (similarly for Manager), for example, you would do this

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

To remove an element, such as sourceName you would have a template that just ignores it

<xsl:template match="sourceName"/>

To handle Address this is slighty different, as you are needing to add a new element. In this case, I would write a template that matched its text node, and add an element there, like so:

<xsl:template match="Address/text()">
   <PermenantAdd>
      <xsl:value-of select="." />
   </PermenantAdd>
</xsl:template>

Finally, for CurrencyType into CurrencyID, this is straight-forward, but you would also need a template to skip over the parent Currency element, and process its children, like so:

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

Try this XSLT

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

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

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

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

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

   <xsl:template match="sourceName"/>

   <xsl:template match="Address/text()">
      <PermenantAdd>
         <xsl:value-of select="." />
      </PermenantAdd>
   </xsl:template>

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

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

Also note there is a template <xsl:template match="/*"> to skip over the root element, and it won't matter if it has a namespace or not.

EDIT: If you don't want to copy across attributes for sourcesys, but instead use new attributes, try replacing the template like so

   <xsl:template match="sourcesys">
      <ManagerDetails href="...">
         <xsl:apply-templates select="node()"/>
      </ManagerDetails>
   </xsl:template>

Notice how the xsl:apply-templates now lacks @* so it won't copy across any other attribute.

If you want

Upvotes: 1

JohnLBevan
JohnLBevan

Reputation: 24410

Try this:

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

  <xsl:template match="/">
    <xsl:element name="ManagerDetails">
      <xsl:apply-templates />
    </xsl:element>
  </xsl:template>

  <xsl:template match="/Report/sourcesys/Manager">
    <xsl:element name="ManagerDetail">
      <xsl:apply-templates />
    </xsl:element>
  </xsl:template>

  <xsl:template match="/Report/sourcesys/Manager/ManagerNo">
    <xsl:copy-of select="."/>
  </xsl:template>

  <xsl:template match="/Report/sourcesys/Manager/Address">
    <xsl:copy>
      <xsl:element name="PermenantAdd">
        <xsl:value-of select="."/>
      </xsl:element>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/Report/sourcesys/Manager/Currency/CurrencyType">
    <xsl:element name="CurrencyID">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="text()"></xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions