aybrady
aybrady

Reputation: 39

XSLT Group Elements by attribute under new parent

I'm trying to transform the following XML

I have a transformation that I need to add an additional part to.

This is the current format of the XML file.

<?xml version="1.0" encoding="utf-8" ?>
<contacts>
    <contact>
        <attribute>
            <name>text12</name>
            <value>B00085590</value>
        </attribute>
        <attribute>
            <name>text34</name>
            <value>Atomos</value>
        </attribute>
        <attribute>
            <name>date866</name>
            <value>02/21/1991</value>
        </attribute>
        <attribute>
            <name>text123</name>
            <value>[email protected]</value>
        </attribute>
        <attribute>
            <name>text875</name>
            <value>123-456-7890</value>
        </attribute>
    </contact>
    <contact>
        <attribute>
            <name>text12</name>
            <value>B00058478</value>
        </attribute>
        <attribute>
            <name>text34</name>
            <value>Balderas</value>
        </attribute>
        <attribute>
            <name>date866</name>
            <value>11/24/1997</value>
        </attribute>
        <attribute>
            <name>text123</name>
            <value>[email protected]</value>
        </attribute>
        <attribute>
            <name>text875</name>
            <value>098-765-4321</value>
        </attribute>
    </contact>
</contacts>

This is my current transformation

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>


    <!--Identify location of the lookup xml-->
    <xsl:param name="lookupDoc" select="document('C:\Projects\FormattedAttributes.xml')" />
    <!--Lookup Key-->
    <xsl:key name="att-lookup" match="attributes/attribute" use="name"/>
    <!--Main Template-->
    <xsl:template match="/contacts">
        <contacts>
            <!--Apply Formatted Contacts Template-->
            <xsl:apply-templates select="contact" />
        </contacts>
    </xsl:template>

    <!--Formatted Contacts Template-->
    <xsl:template match="contact">
        <contact>           
            <xsl:for-each select="attribute">
                <!--Create variable to hold New Name after passing the Data Name to the Lookup Key-->
                <xsl:variable name="name" select="name"/>
                <xsl:variable name="newName">
                    <xsl:for-each select="$lookupDoc">
                        <xsl:apply-templates select="key('att-lookup', $name)/mappingname"/>
                    </xsl:for-each>                     
                </xsl:variable>     
                <!--Format Contact Element with New Name variable-->
                <xsl:element name="{$newName}">
                    <xsl:value-of select="value"/>
                </xsl:element>          
            </xsl:for-each>         
        </contact>
    </xsl:template>




</xsl:stylesheet>

This is a sample of the lookup XML used in the transformation

<?xml version="1.0" encoding="utf-8" ?>
<attributes>
    <attribute folder="PERSONAL">
        <name>text12</name>
        <mappingname>ID</mappingname>
        <datatype>Varchar2</datatype>
        <size>30</size>
    </attribute>
    <attribute folder="PERSONAL">
        <name>text34</name>
        <mappingname>LAST_NAME</mappingname>
        <datatype>Varchar2</datatype>
        <size>30</size>
    </attribute>
    <attribute folder="PERSONAL">
        <name>date866</name>
        <mappingname>DOB</mappingname>
        <datatype>Date</datatype>
        <size></size>
    </attribute>
    <attribute folder="CONTACT_INFO">
        <name>text123</name>
        <mappingname>EMAIL</mappingname>
        <datatype>Varchar2</datatype>
        <size>30</size>
    </attribute>
    <attribute folder="CONTACT_INFO">
        <name>text875</name>
        <mappingname>PHONE</mappingname>
        <datatype>Varchar2</datatype>
        <size>20</size>
    </attribute>
</attributes>

Currently my transformation provides the following output like a charm

<?xml version="1.0" encoding="utf-8" ?>
<contacts>
    <contact>
        <ID>B00085590</ID>
        <LAST_NAME>Brady</LAST_NAME>
        <DOB>02/21/1991</DOB>
        <EMAIL>[email protected]</EMAIL>
        <PHONE>123-456-7890</PHONE>
    </contact>
    <contact>
        <ID>B00058478</ID>
        <LAST_NAME>Balderas</LAST_NAME>
        <DOB>11/24/1997</DOB>
        <EMAIL>[email protected]</EMAIL>
        <PHONE>098-765-4321</PHONE>
    </contact>
</contacts>

My requirements have changed and I need to change the final transformation to take the folder attribute into account and treat the ID element as an attribute for all the newly created folder parent attributes. How do I group all the elements by attribute under a newly created folder parent?

<?xml version="1.0" encoding="utf-8" ?>
<data>
    <PERSONAL ID="B00085590">
        <LAST_NAME>Brady</LAST_NAME>
        <DOB>02/21/1991</DOB>
    </PERSONAL>
    <PERSONAL ID="B00058478">
        <LAST_NAME>Balderas</LAST_NAME>
        <DOB>11/24/1997</DOB>
    </PERSONAL>
    <CONTACT_INFO ID="B00085590">
        <EMAIL>[email protected]</EMAIL>
        <PHONE>123-456-7890</PHONE>
    </CONTACT_INFO>
    <CONTACT_INFO ID="B00058478">
        <EMAIL>[email protected]</EMAIL>
        <PHONE>098-765-4321</PHONE>
    </CONTACT_INFO>
</data>

Upvotes: 0

Views: 34

Answers (1)

Tim C
Tim C

Reputation: 70598

Try this template, which involves the technique of Muenchian Grouping to get the distinct folders. The attributes for each distinct folder are then stored in a variable, and that variable is used to output the relevant attributes for contact details.

<xsl:template match="contact">
    <xsl:variable name="contact" select="." />
    <xsl:for-each select="$lookupDoc">
        <xsl:variable name="idKey" select="attributes/attribute[mappingname='ID']/name" />
        <xsl:for-each select="attributes/attribute[generate-id() = generate-id(key('folder-lookup', @folder)[1])]">
            <xsl:element name="{@folder}">
                <xsl:attribute name="ID">
                    <xsl:value-of select="$contact/attribute[name=$idKey]/value" />
                </xsl:attribute>
                <xsl:variable name="attributes" select="key('folder-lookup', @folder)" />
                <xsl:for-each select="$contact/attribute[name = $attributes/name][name != $idKey]">
                    <xsl:variable name="newName" select="$attributes[name=current()/name]/mappingname" />
                    <xsl:element name="{$newName}">
                        <xsl:value-of select="value"/>
                    </xsl:element>          
                </xsl:for-each>
            </xsl:element>
        </xsl:for-each>
    </xsl:for-each>                     
</xsl:template>

Upvotes: 2

Related Questions