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

Subject: Re: [xsl] Group and sort nodes by attribut in child node
From: "Jens Burkhardt" <JensBurkhardt@xxxxxx>
Date: Mon, 17 Oct 2011 13:06:21 +0200 (CEST)
Hi Brandon,

thank you so much for your help. As far as I can see this is excactly what I
needed. Thanks to everyone else who tried to help me!

Best,
Jens


-----UrsprC<ngliche Nachricht-----
Von: "Brandon Ibach" <brandon.ibach@xxxxxxxxxxxxxxxxxxx>
Gesendet: 17.10.2011 10:43:26
An: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Betreff: Re: [xsl] Group and sort nodes by attribut in child node

>Yes, the approach can be adapted fairly easily. We can start with the
>same first step, building a list of the records sorted by the
>Start_Date field, then output that list in order, except that whenever
>we hit the first record in each group, we output the header and walk
>the rest of the list, outputting only records in that group, then
>continue with the rest of the list where we left off.
>
>The only part of the transform that needs to change is the
>"group-records" template.
>
> <xsl:template name="group-records">
> <xsl:param name="id-list" select="''"/>
> <xsl:param name="do-group" select="''"/>
> <xsl:param name="done" 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:choose>
> <xsl:when test="$group = $do-group">
> <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, ' ')"/>
> </xsl:when>
> <xsl:when test="not($do-group) and not(contains($done,
>concat(' ', $group, ' ')))">
> <xsl:value-of select="concat($group, ' ')"/>
> <xsl:call-template name="group-records">
> <xsl:with-param name="id-list" select="$id-list"/>
> <xsl:with-param name="do-group" select="$group"/>
> </xsl:call-template>
> </xsl:when>
> </xsl:choose>
> <xsl:call-template name="group-records">
> <xsl:with-param name="id-list" select="substring-after($id-list, ' ')"/>
> <xsl:with-param name="do-group" select="$do-group"/>
> <xsl:with-param name="done" select="concat($done, $group, ' ')"/>
> </xsl:call-template>
> </xsl:if>
> </xsl:template>
>
>-Brandon :)
>
>
>On Mon, Oct 17, 2011 at 3:27 AM, Jens Burkhardt <JensBurkhardt@xxxxxx>
wrote:
>> Hello Brandon,
>>
>> i was able to test your approach and youB4re right, i have to group the
records by their group (with its own group for null values) and sort the
values within their group by date and finally
>> sort the groupy by their date.
>> The output should be like MartinB4s output:
>>
>> A - 23.12.2010
>> X_Group
>> B  C - 23.12.2010
>> B  B - 24.12.2010
>> B  D - 25.12.2010
>> Y_Group
>> B  D - 25.12.2010
>> B  E - 26.12.2010
>>
>> Howevery, is this possible? I will try to rewrite your approach but will be
thankful for every hint :).
>>
>> Thanks in advance.
>>
>> Best,
>> Jens
>>
>>
>> -----UrsprC<ngliche Nachricht-----
>> Von: "Brandon Ibach" <brandon.ibach@xxxxxxxxxxxxxxxxxxx>
>> Gesendet: 14.10.2011 21:22:49
>> An: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
>> Betreff: Re: [xsl] Group and sort nodes by attribut in child node
>>
>>>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']
/@value,
>>>'.'), '.'),
>>>
>>>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, ' ')"/>
>>> </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, ' ')"/>
>>> <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 donB4t 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