0
votes

I am new to XSLT. I want to convert one XML format to another format. Input format:

<record>
    <field>Firstname</field>
    <field>Lastname</field>
</record>
<record>
    <field>abc</field>
    <field>def</field>
</record>
<record>
    <field>geh</field>
    <field>fgh</field>
</record>

I need output from XSLT as shown below. Note that first record in the input will have the field names. Number of fields in the inputs can very so XSLT should take care of that as well.

<record>
    <Firstname>abc</field>
    <Lastname>def</field>
</record>
<record>
    <Firstname>geh</field>
    <Lastname>fgh</field>
</record>

Any help will be much appreciated.

Thanks,

2

2 Answers

0
votes

Given a well-formed input, such as:

<root>
    <record>
        <field>Firstname</field>
        <field>Lastname</field>
    </record>
    <record>
        <field>abc</field>
        <field>def</field>
    </record>
    <record>
        <field>geh</field>
        <field>fgh</field>
    </record>
</root>

the following stylesheet:

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="/root">
    <root>
        <xsl:variable name="field-names" select="record[1]/field" />
        <xsl:for-each select="record[position() > 1 ]">
            <xsl:copy>
                <xsl:for-each select="field">
                <xsl:variable name="i" select="position()" />   
                    <xsl:element name="{$field-names[$i]}">
                        <xsl:value-of select="." />
                    </xsl:element>
                </xsl:for-each>
            </xsl:copy>     
        </xsl:for-each>
    </root>
</xsl:template>

</xsl:stylesheet>

will return:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <record>
      <Firstname>abc</Firstname>
      <Lastname>def</Lastname>
   </record>
   <record>
      <Firstname>geh</Firstname>
      <Lastname>fgh</Lastname>
   </record>
</root>

Note that this assumes that the provided column names are valid XML element names.

0
votes

You are new in XSLT, so let's be pedagogic! I propose the following solution, for you to compare with michael.hor257k's. Mine emphasis the declarative nature of XSLT. You'll notice there is no for-each loop. Also please refer to michael.hor257k's anwser for the well-formed input xml.

 <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="/root">
     <root>
       <xsl:apply-templates select="record[position() > 1 ]"/>
     </root>
   </xsl:template>

   <xsl:template match="record">
     <xsl:copy>
       <xsl:apply-templates select="field"/>
     </xsl:copy>
   </xsl:template>

   <xsl:template match="field">
     <xsl:variable name="pos" select="position()"/>
     <xsl:element name="{//record[1]/field[position()=$pos]/text()}">
       <xsl:value-of select="."/>
     </xsl:element>
   </xsl:template>

 </xsl:stylesheet>