XSLT - Dynamic Map Columns

787 Views Asked by At

I have 3 different XML files. Some columns of them common and someone are not. And ordinalPosition of them are changing. Each time, i get new file in my ftp and need to read one by one and load into system. But i don't know about column names of the file.

  XML 1 :
  <?xml version="1.0" encoding="UTF-8"?>
    <SourceFile>
       <Data>
         <CustNo>126</CustNo>
         <Gender/>
         <isActive>0</isActive>
         <Email/>
       </Data>
    </SourceFile>   

XML 2 :
<?xml version="1.0" encoding="UTF-8"?>
 <SourceFile>
   <Data>
    <CustNo>124</CustNo>
    <Phone/>
    <Country/>
    <isActive>1</isActive>
   </Data>
 </SourceFile> 

XML 3:
<?xml version="1.0" encoding="UTF-8"?>
 <SourceFile>
   <Data>
    <KeyId>123</KeyId>
    <FirstName/>
    <LastName/>
    <Email/>  
    <isActive>0</isActive>
   </Data>
 </SourceFile> 

I am very new with XSLT. I want generate below output whenever a file arrived in my ftp.

  Result for XML 1 :
  <?xml version="1.0" encoding="UTF-8"?>
    <SourceFile>
      <Data>
        <KeyID>124</KeyID>  <!-- CustNo will be mapped to KeyId -->
        <FirstName/>
        <LastName/>
        <Email/> 
        <Phone/>
        <Country/>
        <isActive>0</isActive> 
      </Data>
    </SourceFile> 

Many thanks, Mehmet

2

There are 2 best solutions below

0
michael.hor257k On

Assuming that you always want to have all the listed elements present in the output (populated or not), and that you want them in the given order, you could do:

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:template match="/SourceFile">
    <xsl:copy>
        <xsl:for-each select="Data">
            <xsl:copy>
                <KeyID>
                    <xsl:value-of select="CustNo | KeyId"/>
                </KeyID>
                <FirstName>
                    <xsl:value-of select="FirstName"/>
                </FirstName>
                <LastName>
                    <xsl:value-of select="LastName"/>
                </LastName>
                <Email> 
                    <xsl:value-of select="Email"/>
                </Email> 
                <Phone>
                    <xsl:value-of select="Phone"/>
                </Phone>
                <Country>
                    <xsl:value-of select="Country"/>
                </Country>
                <isActive>
                    <xsl:value-of select="isActive"/>
                </isActive> 
            </xsl:copy>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>
0
uL1 On

One try would be:

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

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="Data">
       <xsl:copy>
           <KeyID><xsl:value-of select="CustNo | KeyId"/></KeyID>
           <FirstName><xsl:value-of select="FirstName"/></FirstName>
           <Email><xsl:value-of select="Email"/></Email>
           <Phone><xsl:value-of select="Phone"/></Phone>
           <Country><xsl:apply-templates select="Country"/></Country>
           <isActive><xsl:value-of select="isActive"/></isActive>
       </xsl:copy>
    </xsl:template>

    <xsl:template match="Country">
        <xsl:value-of select="."/>
    </xsl:template>

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

</xsl:stylesheet>

Explanation:

On element Data you always create the expected outcome. Like KeyID, FirstName, and so on.. Whenever the select of either <xsl:value-of or <xsl:apply-templates matches, you get the content of node.

<xsl:value-of /> just returns the string of an element.

<xsl:apply-templates /> will eventually execute other template-rules as well! This is important if you have child-nodes for example. You see this in the example for element Country.

XML and XSLT are case-sensitiv.