Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XML to XML Mapping using XSLT

Tags:

xml

xslt

xslt-2.0

I am new to XSLT and trying to map one XML to another XML using xslt, here is my first XML

<root>
    <record>
        <element name="LoginId">a</element>
        <element name="name">Admin Manager</element>
        <element name="password">12345</element>
        <element name="Age">28</element>
        <element name="Sex">M</element>
    </record>
    <record>
        <element name="LoginId">b</element>
        <element name="name">HR exec</element>
        <element name="password">pass1</element>
        <element name="Age">26</element>
        <element name="Sex">F</element>
    </record>
    <record>
        <element name="LoginId">c</element>
        <element name="name">PR Manager</element>
        <element name="password">pass2</element>
        <element name="Age">27</element>
        <element name="Sex">M</element>
    </record>
</root>

I need to convert this XML to the following

<?xml version="1.0" encoding="UTF-8"?>
<final>
    <test>
        <UID>a</UUID>
        <Name>HR manager</Name>
        <Groups>admingroup</Groups>
        <Password>12345</Password>
    </test>
    <test>
        <UID>b</UUID>
        <Name>HR exec</Name>
        <Groups>admingroup</Groups>
        <Password>pass1</Password>
    </test>
    <test>
        <UID>c</UUID>
        <Name>PR manager</Name>
        <Groups>admingroup</Groups>
        <Password>pass2</Password>
    </test>
</final>

i tried following xslt for transformation

<?xml version="1.0" encoding="UTF-8" ?> 
- <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
- <xsl:template match="/">
- <test>
- <xsl:for-each select="root/record">
  <xsl:apply-templates select="element" /> 
  </xsl:for-each>
  </test>
  </xsl:template>
- <xsl:template match="element">
- <test>
  <Employee /> 
- <UID>
  <xsl:value-of select="@LoginId" /> 
  </UID>
- <xsl:choose>
- <xsl:when test="@name = ''">
- <Name>
  <xsl:text>demo employee</xsl:text> 
  </Name>
  </xsl:when>
- <xsl:otherwise>
- <Name>
  <xsl:value-of select="@name" /> 
  </Name>
  </xsl:otherwise>
  </xsl:choose>
- <Groups>
  <xsl:text>admingroup</xsl:text> 
  </Groups>
- <Password>
  <xsl:value-of select="@password" /> 
  </Password>
  </test>
  </xsl:template>
  </xsl:transform>

but this xslt is generating following XML output

<?xml version="1.0" encoding="UTF-8"?>
<impex>
    <final>
        <Employee />
        <UID />
        <Name>LoginId</Name>
        <Groups>admingroup</Groups>
        <Password />
    </final>

total 15 <final></final> with similar output

i can do it easily in Java but some how have to do in xslt and only problem i am facing is the repetition of <element> tag with different attribute values

any help in this regard will be much helpful for me

like image 341
Umesh Awasthi Avatar asked Aug 30 '11 15:08

Umesh Awasthi


1 Answers

Even if you already have the excellent solution proposed by @Martin's answer (+1), I'm fixing here your transform to show you where you were wrong. This might help you in learning a bit more of how XSLT (and XPath) works.

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <final>
                <xsl:apply-templates select="root/record" /> 
        </final>
    </xsl:template>

    <xsl:template match="record">
        <test>
            <Employee /> 
            <UID>
                <xsl:value-of select="element[@name='LoginId']" /> 
            </UID>
            <xsl:choose>
                <xsl:when test="element[@name='name']=''">
                    <Name>
                        <xsl:text>demo employee</xsl:text> 
                    </Name>
                </xsl:when>
                <xsl:otherwise>
                    <Name>
                        <xsl:value-of select="element[@name='name']"/> 
                    </Name>
                </xsl:otherwise>
            </xsl:choose>
            <Groups>
                <xsl:text>admingroup</xsl:text> 
            </Groups>
            <Password>
                <xsl:value-of select="element[@name='password']" /> 
            </Password>
        </test>
    </xsl:template>

</xsl:transform>

Note that xsl:choose approach is correct, even if normally the preferable XSLT way is template rules:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>

    <xsl:template match="/">
        <final>
            <xsl:apply-templates select="root/record" /> 
        </final>
    </xsl:template>

    <xsl:template match="record">
        <test>
            <Employee /> 
            <UID>
                <xsl:value-of select="element[@name='LoginId']" /> 
            </UID>
            <Name>
                <xsl:apply-templates select="element[@name='name']"/>
            </Name>
            <Groups>
                <xsl:text>admingroup</xsl:text> 
            </Groups>
            <Password>
                <xsl:value-of select="element[@name='password']" /> 
            </Password>
        </test>
    </xsl:template>

    <xsl:template match="element[@name='name'][.='']">
            <xsl:text>demo employee</xsl:text> 
    </xsl:template>

    <xsl:template match="element[@name='name'][.!='']">
            <xsl:value-of select="."/> 
    </xsl:template>

</xsl:transform>
like image 104
Emiliano Poggi Avatar answered Nov 14 '22 23:11

Emiliano Poggi