Search code examples
xmlxslt

How to transpose XSLT from Rows Into Elements


I am seeking advice on the corrext XSLT method to transpose XML output from rows to there correct logical elements.

As an example i have the following output

<?xml version="1.0" encoding="utf-8"?>
<Report>
    <Field>GetMembershipDetails</Field>
    <Row>
        <Item>MembershipID</Item>
        <Item>MemberNumber</Item>
        <Item>MembershipStatus</Item>
        <Item>BenefitStartDate</Item>
        <Item>BenefitEndDate</Item>
        <Item>MembershipStartDate</Item>
        <Item>MembershipEndDate</Item>
        <Item>MembershpResignationDate</Item>
        <Item>MembershipAnniversaryDate</Item>
        <Item>MembershipType</Item>
        <Item>ContactId</Item>
        <Item>ContactTitle</Item>
        <Item>ContactFirstName</Item>
        <Item>ContactLastName</Item>
        <Item>ContactGender</Item>
        <Item>ContactDateOfBirth</Item>
        <Item>ContactEmployeeNumber</Item>
        <Item>ContactEmployeDateJoined</Item>
        <Item>ContactCorporateAccountNo</Item>
        <Item>ContactEmailAddress</Item>
        <Item>ContactPostalStreet</Item>
        <Item>ContactPostalCity</Item>
        <Item>ContactPostalState</Item>
        <Item>ContactPostalPostCode</Item>
        <Item>ContactResidentialStreet</Item>
        <Item>ContactResidentialState</Item>
        <Item>ContactResidentialCity</Item>
        <Item>ContactResidentialPostCode</Item>
        <Item>ContactResidentialCountry</Item>
        <Item>ContactType</Item>
        <Item>ProductName</Item>
        <Item>ProductDescription</Item>
        <Item>ProductType</Item>
        <Item>ProductAmount</Item>
        <Item>MembershipProductID</Item>
    </Row>
    <Row>
        <Item>8</Item>
        <Item>A2000</Item>
        <Item>Current</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>Current</Item>
        <Item>109</Item>
        <Item>Mr</Item>
        <Item>John</Item>
        <Item>Foley</Item>
        <Item>Male</Item>
        <Item>10/09/2014</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>0</Item>
        <Item>[email protected]</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>0</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>Australia</Item>
        <Item>Primary</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>No Value</Item>
        <Item>0</Item>
        <Item>8</Item>
    </Row>
</Report>

Which should become something like

<Table>
<Row>
<MembershipID>8</MembershipID>
...
...
</Row>
</Table>

Or Even

<Table>
<Row>
<Column name="MembershipID">8</Column>
...
</Row>
</Table>

Thanks in advance


Solution

  • The second option is definitely preferable. Try it this way:

    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:key name="column-name" match="Row[1]/Item" use="count(preceding-sibling::Item)" />
    
    <xsl:template match="/">
        <Table>
            <xsl:for-each select="Report/Row[position() > 1]">
                <Row>
                    <xsl:apply-templates select="Item"/>
                </Row>
            </xsl:for-each>
        </Table>
    </xsl:template>
    
    <xsl:template match="Item">
        <Column name="{key('column-name', count(preceding-sibling::Item))}">
            <xsl:value-of select="."/>
        </Column>
    </xsl:template>
    
    </xsl:stylesheet>
    

    --

    Or perhaps you prefer changing:

    <xsl:template match="Item">
    

    to:

    <xsl:template match="Item[not(.='No Value')]">