Re: [xsl] Grouping problem

Subject: Re: [xsl] Grouping problem
From: Martin Honnen <Martin.Honnen@xxxxxx>
Date: Thu, 08 Apr 2010 20:27:00 +0200
Joel Dubien wrote:

Desired Output:
<item>
    <master_affiliate_id>68800</master_affiliate_id>
    <queries_by_period>75,120,0,0</queries_by_period>
    <subitems>
        <item>
            <affiliate_id>68801</affiliate_id>
            <queries_by_period>75,120,0,0</queries_by_period>
        </item>
    </subitems>
</item>
<item>
    <master_affiliate_id>69767</master_affiliate_id>
    <queries_by_period>75,120,0,0</queries_by_period>
    <subitems>
        <item>
            <affiliate_id>69775</affiliate_id>
            <queries_by_period>75,120,0,0</queries_by_period>
        </item>
    </subitems>
</item>

Here is an XSLT 1.0 stylesheet that produces the described output:


<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  version="1.0">

<xsl:output indent="yes"/>

<xsl:param name="plist" select="'test2010040802.xml'"/>
<xsl:variable name="periods" select="document($plist)/period_list/period"/>


<xsl:variable name="main-root" select="/"/>

<xsl:key name="k1" match="master_affiliate" use="master_affiliate_id"/>

<xsl:key name="k2" match="master_affiliate/summary" use="concat(../master_affiliate_id, '|', period)"/>

<xsl:key name="k3" match="affiliates/affiliate" use="affiliate_id"/>

<xsl:key name="k4" match="affiliates/affiliate" use="concat(affiliate_id, '|', period)"/>

<xsl:template match="/">
<xsl:for-each select="descendant::master_affiliate[generate-id() = generate-id(key('k1', master_affiliate_id)[1])]">
<xsl:variable name="cgk" select="master_affiliate_id"/>
<item>
<xsl:copy-of select="master_affiliate_id"/>
<queries_by_period>
<xsl:for-each select="$periods">
<xsl:variable name="period" select="."/>
<xsl:for-each select="$main-root">
<xsl:variable name="s" select="key('k2', concat($cgk, '|', $period))"/>
<xsl:choose>
<xsl:when test="$s">
<xsl:value-of select="$s/queries"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:if test="position() != last()"><xsl:text>,</xsl:text></xsl:if>
</xsl:for-each>
</queries_by_period>
<subitems>
<xsl:for-each select="key('k1', master_affiliate_id)/affiliates/affiliate[generate-id() = generate-id(key('k3', affiliate_id)[1])]">
<item>
<xsl:copy-of select="affiliate_id"/>
<xsl:variable name="cgk1" select="affiliate_id"/>
<queries_by_period>
<xsl:for-each select="$periods">
<xsl:variable name="period" select="."/>
<xsl:for-each select="$main-root">
<xsl:variable name="s" select="key('k4', concat($cgk1, '|', $period))"/>
<xsl:choose>
<xsl:when test="$s">
<xsl:value-of select="$s/queries"/>
</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:if test="position() != last()"><xsl:text>,</xsl:text></xsl:if>
</xsl:for-each>
</queries_by_period>
</item>
</xsl:for-each>
</subitems>
</item>
</xsl:for-each>
</xsl:template>


</xsl:stylesheet>

I am not quite sure however it will work for more complex input documents as I am not sure the same affiliate could occur under different master_affiliate elements. In that case the key 'k4' would need to include the master affiliate id as well.


--


	Martin Honnen
	http://msmvps.com/blogs/martin_honnen/

Current Thread