user640232
user640232

Reputation: 119

XSLT to convert XML with grouping the value with the same tags

I have an XML that shows values with the field having the field values that looks like:

<data>
    <currentRow>
      <columnValue>usa</columnValue>
      <columnValue>ma</columnValue>
      <columnValue>boston</columnValue>
      <columnValue>bob</columnValue>
    </currentRow>
    <currentRow>
      <columnValue>usa</columnValue>
      <columnValue>ma</columnValue>
      <columnValue>boston</columnValue>
      <columnValue>george</columnValue>
    </currentRow>
    <currentRow>
      <columnValue>usa</columnValue>
      <columnValue>ny</columnValue>
      <columnValue>nyc</columnValue>
      <columnValue>mary</columnValue>
    </currentRow>
  </data>

I want to generate an Xml producing that looks like

<Class>
  <Student>
    <Country>usa</Country>
    <State>ma</State>
    <City>boston</City>
       <name>bob</name>
       <name>george</name>
  </Student>
  <Student>
    <Country>usa</Country>
    <State>ny</State>
    <City>nyc</City>
       <name>mary</name>
  </Student>
<Class>

In short, I have two questions:

  1. I want to loop over the Current Rows to generate a generic XMl
  2. I want to group the student Names over the location they lives, first over the city, then state and then country

Any ideas how do I do that?

Upvotes: 1

Views: 136

Answers (1)

Mads Hansen
Mads Hansen

Reputation: 66723

The following stylesheet uses the Muenchian Method to group the currentRow elements using the values of the first 3 columnValue elements.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>

    <!--Create a key grouping on the concatenated values of 
        country, state, and city separated by '-'-->
    <xsl:key name="students-by-country-state-city" 
             match="currentRow"
             use="concat(columnValue[1], 
                         '-', 
                         columnValue[2], 
                         '-', 
                         columnValue[3])"/>

    <xsl:template match="data">
        <Class>
            <!--apply templates to the first item in each grouping of items -->
            <xsl:apply-templates
                select="currentRow[generate-id() =
                                   generate-id(
                                     key('students-by-country-state-city', 
                                         concat(columnValue[1],
                                         '-', 
                                         columnValue[2],  
                                         '-', 
                                         columnValue[3]))[1]
                                   )]"
            />
        </Class>
    </xsl:template>

    <xsl:template match="currentRow">
        <Student>
            <Country>
                <xsl:value-of select="columnValue[1]"/>
            </Country>
            <State>
                <xsl:value-of select="columnValue[2]"/>
            </State>
            <City>
                <xsl:value-of select="columnValue[3]"/>
            </City>

            <!-- find all of the names for this grouping -->
            <xsl:for-each
                select="key('students-by-country-state-city', 
                                    concat(columnValue[1], 
                                           '-', 
                                           columnValue[2],  
                                           '-', 
                                           columnValue[3]))/columnValue[4]">
                <name>
                    <xsl:value-of select="."/>
                </name>
            </xsl:for-each>
        </Student>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions