Re: [xsl] Group and sort nodes by attribut in child node

Subject: Re: [xsl] Group and sort nodes by attribut in child node
From: Brandon Ibach <brandon.ibach@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 14 Oct 2011 15:22:49 -0400
Here's a version of Martin's approach that works in XSLT 1.0.
However, is this really a match for your requirements?  I got the
impression from your initial post that the goal was more like "group
the records by their 'Group' value, putting each record with a null
'Group' in its own group, then sort the records by date within their
group and sort the groups by the earliest date in the group".

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="1.0">
  <xsl:output method="text"/>

  <xsl:key name="records" match="record" use="generate-id(.)"/>

  <xsl:template match="records">
    <xsl:call-template name="group-records">
      <xsl:with-param name="id-list">
        <xsl:for-each select="record">
          <xsl:sort
select="concat(substring-after(substring-after(column[@field='Start_Date']/@v
alue,
'.'), '.'),

substring-before(substring-after(column[@field='Start_Date']/@value,
'.'), '.'),

substring-before(column[@field='Start_Date']/@value, '.'))"/>
          <xsl:value-of select="generate-id(.)"/><xsl:text> </xsl:text>
        </xsl:for-each>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="group-records">
    <xsl:param name="id-list" select="''"/>
    <xsl:param name="last" select="''"/>
    <xsl:if test="$id-list">
      <xsl:variable name="record" select="key('records',
substring-before($id-list, ' '))"/>
      <xsl:variable name="group"
select="string($record/column[@field='Group']/@value)"/>
      <xsl:if test="$group and $group != $last">
        <xsl:value-of select="concat($group, '&#10;')"/>
      </xsl:if>
      <xsl:if test="$group"><xsl:text> </xsl:text></xsl:if>
      <xsl:value-of
select="concat($record/column[@field='keyword']/@value, ' - ',
$record/column[@field='Start_Date']/@value, '&#10;')"/>
      <xsl:call-template name="group-records">
        <xsl:with-param name="id-list" select="substring-after($id-list, '
')"/>
        <xsl:with-param name="last" select="$group"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

-Brandon :)


On Fri, Oct 14, 2011 at 11:21 AM, Jens Burkhardt <JensBurkhardt@xxxxxx>
wrote:
> Wow. Thanks for the quick reply. First of all, sorry for not telling that i
have to use XSLT 1.0. I knew i forgot something. The result your style sheet
produces meets my requirement
> perfectly but i need it, as I said for XSLT 1.0.
> Nodes where the group value is empty should not be in the same group so what
you did is perfect. Is there any way to do this for xslt 1.0?
>
> Thank you.
>
> Jens
>
>>Martin Honnen wrote:
>>> Jens Burkhardt wrote:
>>>
>>>> The result should be like this:
>>>> A - 23.10.2010
>>>> X_Group
>>>> C - 23.10.2010
>>>> B - 24.12.2010
>>>> D - 25.10.2010
>>>> Y_Group
>>>> D - 25.12.2010
>>>> E - 26.12.2010
>>>>
>>>> I want to group by the value of the group field in the column node and
>>>> everything should be sorted by start_date. The name of the group (e.g.
>>>> X_Group) should start a group-block, followed by the record nodes
>>>> which belong to the group value.
>>>> Another problem is that i don4t know the group value in advance,
>>>> because they can be set to whatever the user want.
>>>
>>> Do you use XSLT 2.0 or 1.0?
>>> And what about the record with keyword value "A" and the one with
>>> keyword value "D" where the group value is an empty string? Shouldn't
>>> they be in the same group?
>>
>>Here is an XSLT 2.0 stylesheet that sorts first and the groups adjacent
>>records in the sorted sequence:
>>
>><xsl:stylesheet
>> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>> xmlns:xs="http://www.w3.org/2001/XMLSchema";
>> exclude-result-prefixes="xs"
>> version="2.0">
>>
>> <xsl:output method="text"/>
>>
>> <xsl:template match="records">
>> <xsl:variable name="sorted" as="element(record)*">
>> <xsl:perform-sort select="record">
>> <xsl:sort select="xs:date(concat(substring(column[@field =
>>'Start_Date']/@value, 7), '-',
>> substring(column[@field =
>>'Start_Date']/@value, 4, 2), '-',
>> substring(column[@field =
>>'Start_Date']/@value, 1, 2)))"/>
>> </xsl:perform-sort>
>> </xsl:variable>
>> <xsl:for-each-group select="$sorted" group-adjacent="column[@field
>>= 'Group']/@value">
>> <xsl:choose>
>> <xsl:when test="current-grouping-key()">
>> <xsl:value-of select="current-grouping-key()"/>
>> <xsl:text> </xsl:text>
>> <xsl:value-of select="current-group()/concat(' ',
>>column[@field = 'keyword']/@value, ' - ', column[@field =
>>'Start_Date']/@value)"
>> separator=" "/>
>> <xsl:text> </xsl:text>
>> </xsl:when>
>> <xsl:otherwise>
>> <xsl:value-of select="current-group()/concat(column[@field =
>>'keyword']/@value, ' - ', column[@field = 'Start_Date']/@value)"/>
>> <xsl:text> </xsl:text>
>> </xsl:otherwise>
>> </xsl:choose>
>> </xsl:for-each-group>
>> </xsl:template>
>>
>></xsl:stylesheet>
>>
>>With that stylesheet Saxon 9.3 HE, when applying it to the input
>>
>><records>
>><record>
>> <column field="keyword" value="A"></column>
>> <column field="Start_Date" value="23.12.2010"></column>
>> <column field="Group" value=""></column>
>></record>
>><record>
>> <column field="keyword" value="B"></column>
>> <column field="Start_Date" value="24.12.2010"></column>
>> <column field="Group" value="X_Group"></column>
>></record>
>><record>
>> <column field="keyword" value="D"></column>
>> <column field="Start_Date" value="25.12.2010"></column>
>> <column field="Group" value=""></column>
>></record>
>><record>
>> <column field="keyword" value="C"></column>
>> <column field="Start_Date" value="23.12.2010"></column>
>> <column field="Group" value="X_Group"></column>
>></record>
>><record>
>> <column field="keyword" value="D"></column>
>> <column field="Start_Date" value="25.12.2010"></column>
>> <column field="Group" value="Y_Group"></column>
>></record>
>><record>
>> <column field="keyword" value="E"></column>
>> <column field="Start_Date" value="26.12.2010"></column>
>> <column field="Group" value="Y_Group"></column>
>></record>
>></records>
>>
>>outputs
>>
>>A - 23.12.2010
>>X_Group
>> C - 23.12.2010
>> B - 24.12.2010
>>D - 25.12.2010
>>Y_Group
>> D - 25.12.2010
>> E - 26.12.2010
>>
>>
>>Does that solution meet your requirement?
>
>
>
> ___________________________________________________________
> SMS schreiben mit WEB.DE FreeMail - einfach, schnell und
> kostenguenstig. Jetzt gleich testen! http://f.web.de/?mc=021192

Current Thread