Search code examples
xslt-1.0xslt-2.0

XSLT Transform from a Generic Model to a Specific Model


I am trying to convert a XML form that is sent to my backend using a generic model to the internal XML model the system uses using XSLT.

The generic model consists of sections, lines and tables (a table is basically an array/group of elements). The PK's are from the sequence for the tableRow and the maxPK is a count. MaxPK I can probably populate afterwards, not sure if that is possible through XSLT.

Any help would be appreciated!

Generic Model

    <form>
    <section>
        <name>identification</name>
        <sequence>1</sequence>
        <line>
            <sequence>0</sequence>
            <field>
                <name>firstName</name>
                <value>JOHN</value>
            </field>
        </line>
        <line>
            <sequence>1</sequence>
            <field>
                <name>lastName</name>
                <value>DOE</value>
            </field>
        </line>
    </section>
    <section>
        <name>contactDetails</name>
        <sequence>1</sequence>
        <line>
            <sequence>0</sequence>
            <field>
                <name>primaryPhone</name>
                <value>+44 100 1234</value>
            </field>
        </line>
        <table>
            <name>secondaryPhoneGroup</name>
            <tableRow>
                <sequence>1</sequence>
                <field>
                    <sequence>0</sequence>
                    <name>secondaryPhone</name>
                    <value>+44 100 1235</value>
                </field>
            </tableRow>
            <tableRow>
                <sequence>2</sequence>
                <field>
                    <sequence>0</sequence>
                    <name>secondaryPhone</name>
                    <value>+44 100 1236</value>
                </field>
            </tableRow>
        </table>
    </section>
</form>

Internal Model

<form>
    <identification>
        <firstName>
            <asCurrent>JOHN</asCurrent>
        </firstName>
        <lastName>
            <asCurrent>DOE</asCurrent>
        </lastName>
    </identification>
    <contactDetails>
        <primaryPhone>
            <asCurrent>+44 100 1234</asCurrent>
        </primaryPhone>
        <secondaryPhoneGroup>
            <secondaryPhone>
                <pk>1</pk>
                <phone>
                    <asCurrent>+44 100 1235</asCurrent>
                </phone>
            </secondaryPhone>
            <secondaryPhone>
                <pk>2</pk>
                <phone>
                    <asCurrent>+44 100 1236</asCurrent>
                </phone>
            </secondaryPhone>
            <maxPK>2</maxPK>
        </secondaryPhoneGroup>
    </contactDetails>
</form>

Solution

  • Try along the following lines:

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    
        <xsl:output indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="line">
            <xsl:apply-templates/>
        </xsl:template>
    
        <xsl:template match="sequence"/>
    
        <xsl:template match="section | field">
            <xsl:element name="{name}">
                <xsl:apply-templates select="* except name"/>
            </xsl:element>
        </xsl:template>
    
        <xsl:template match="*[name]/value">
            <asCurrent>
                <xsl:apply-templates/>
            </asCurrent>
        </xsl:template>
    
        <xsl:template match="table">
            <xsl:element name="{name}">
                <xsl:apply-templates select="* except name"/>
                <maxPK>
                    <xsl:value-of select="count(tableRow)"/>
                </maxPK>
            </xsl:element>
        </xsl:template>
    
        <xsl:template match="tableRow">
            <xsl:element name="{field/name}">
                <xsl:apply-templates select="* except name"/>
            </xsl:element>
        </xsl:template>
    
        <xsl:template match="tableRow/sequence">
            <pk>
                <xsl:apply-templates/>
            </pk>
        </xsl:template>
    
        <xsl:template match="tableRow/field[name = 'secondaryPhone']">
            <phone>
                <xsl:apply-templates select="value"/>
            </phone>
        </xsl:template>
    
    </xsl:transform>