Re: [xsl] grouping

Subject: Re: [xsl] grouping
From: "Dave Pawson dave.pawson@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 2 Jan 2026 15:42:28 -0000
On Fri, 2 Jan 2026 at 15:23, G. Ken Holman g.ken.holman@xxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:

> Ouch! I think I prefer David's answer, but this is what I came up with
> working semantically instead of syntactically:
>

Just so Ken. Math(s) wins out again.
   Took me about 20 mins to work it through.
Elegant? Yep.
<xsl:function name="dp:s">
    <xsl:param name="p" as="element(period)"/>
    <xsl:message><xsl:value-of select="$p/concat(start/date,':', 3 *
(xs:int(substring-before(start/time,':')) idiv 3))"/>
    </xsl:message>
    <xsl:sequence select="$p/concat(start/date,':', 3 *
(xs:int(substring-before(start/time,':')) idiv 3))"/>
  </xsl:function>

Worth pondering IMHO.

Thanks Ken.

regards




>
> ~/t $ cat dave.xsl
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>   xmlns:xs="http://www.w3.org/2001/XMLSchema";
>   xmlns:math="http://www.w3.org/2005/xpath-functions/math";
>   xmlns:dave="urn:X-Dave"
>   exclude-result-prefixes="xs math dave"
>   version="3.0">
>
> <xsl:output method="text"/>
>
> <xsl:template match="data">
>   <xsl:for-each-group select="period"
>                       group-by="dave:modulo3hours(start)">
>     <xsl:value-of select="'&#xa;' || current-grouping-key() || ' ' ||
>                       count(current-group()) || ' entries with total cost:
> ' ||
>                       sum(current-group()/number(cost))"/>
>   </xsl:for-each-group>
>   <xsl:text>&#xa;</xsl:text>
> </xsl:template>
>
> <xsl:function name="dave:modulo3hours" as="xs:string">
>   <xsl:param name="start" as="element(start)"/>
>   <xsl:variable name="startTime" select="xs:time($start/time || ':00')"/>
>   <xsl:variable name="fromMidnightDuration"
>                 select="xs:duration($startTime - xs:time('00:00:00') )"/>
>   <xsl:variable name="fromMidnightMinutes"
>                 select="hours-from-duration($fromMidnightDuration) * 60 +
>                         minutes-from-duration($fromMidnightDuration)"/>
>   <xsl:sequence select="$start/date || '-' || $fromMidnightMinutes idiv
> 180"/>
> </xsl:function>
>
> </xsl:stylesheet>
> ~/t $ xslt2 dave.xml dave.xsl
>
> 12-01-0 3 entries with total cost: 3.32516625
> 12-01-1 6 entries with total cost: 11.899479375
> 12-01-2 6 entries with total cost: 122.236542015
> 12-01-3 6 entries with total cost: 66.41845759499999
> 12-01-4 6 entries with total cost: 48.98321693999999
> 12-01-5 6 entries with total cost: 113.2815999
> 12-01-6 6 entries with total cost: 28.573543214999997
> 12-01-7 6 entries with total cost: 25.968715394999997
> 12-02-0 1 entries with total cost: 0.6300315
> ~/t $
>
>
> At 02/01/2026 15:08 +0000, Dave Pawson dave.pawson@xxxxxxxxx wrote:
> >Thank you David.\xC2
> >
> >regards
> >
> >On Fri, 2 Jan 2026 at 15:04, David Carlisle <mailto:
> d.p.carlisle@xxxxxxxxx>d.p.carlisle@xxxxxxxxx <<mailto:
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> >this?
> >
> ><!DOCTYPE HTML>
> ><html>
> >\xC2  \xC2 <p>12-01:0 3.32516625</p>
> >\xC2  \xC2 <p>12-01:3 11.899479375</p>
> >\xC2  \xC2 <p>12-01:6 122.236542015</p>
> >\xC2  \xC2 <p>12-01:9 66.41845759499999</p>
> >\xC2  \xC2 <p>12-01:12 48.98321693999999</p>
> >\xC2  \xC2 <p>12-01:15 113.2815999</p>
> >\xC2  \xC2 <p>12-01:18 28.573543214999997</p>
> >\xC2  \xC2 <p>12-01:21 25.968715394999997</p>
> >\xC2  \xC2 <p>12-02:0 0.6300315</p>
> ></html>
> >
> >
> >from
> >
> ><xsl:stylesheet version="2.0"
> >xmlns:xsl="<http://www.w3.org/1999/XSL/Transform>
> http://www.w3.org/1999/XSL/Transform";
> >xmlns:xs="<http://www.w3.org/2001/XMLSchema>
> http://www.w3.org/2001/XMLSchema";
> >xmlns:dp="data:,dp"
> >exclude-result-prefixes="dp xs"
> >>
> >
> >\xC2  <xsl:template match="data">
> >\xC2  \xC2  <html>
> >\xC2  \xC2  \xC2  <xsl:for-each-group group-by="dp:s(.)" select="period">
> ><p>
> >\xC2 <xsl:value-of select="current-grouping-key()"/>
> >\xC2 <xsl:text> </xsl:text>
> >\xC2 <xsl:value-of select="sum(current-group()/cost)"/>
> ></p>
> >\xC2  \xC2  \xC2  </xsl:for-each-group>
> >\xC2  \xC2  </html>
> >\xC2  </xsl:template>
> >
> >\xC2  <xsl:function name="dp:s">
> >\xC2  \xC2  <xsl:param name="p" as="element(period)"/>
> >\xC2  \xC2  <xsl:sequence select="$p/concat(start/date,':', 3 *
> (xs:int(substring-before(start/time,':')) idiv 3))"/>
> >\xC2  </xsl:function>
> >\xC2  \xC2  \xC2
> ></xsl:stylesheet>
> >
> >
> >
> >
> >On Fri, 2 Jan 2026 at 14:50, Dave Pawson <mailto:dave.pawson@xxxxxxxxx>
> dave.pawson@xxxxxxxxx <<mailto:xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> >Even easier
> ><
> https://privatebin.net/?1306eef3a715a90d#75Jfu1qzHcNaEdno9PyuBj4mq4N695bUJB8WPHwAhoAw
> >
> https://privatebin.net/?1306eef3a715a90d#75Jfu1qzHcNaEdno9PyuBj4mq4N695bUJB8WPHwAhoAw
> >
> >a full months worth.
> >
> >I'd forgotten about pastebin!
> >
> >regards
> >
> >
> >--
> >Dave Pawson
> >XSLT XSL-FO FAQ.
> >Docbook FAQ.
> ><http://www.mulberrytech.com/xsl/xsl-list>XSL-List info and archive
> ><http://lists.mulberrytech.com/unsub/xsl-list/2739265>EasyUnsubscribe
> (by email)
> >
> ><http://www.mulberrytech.com/xsl/xsl-list>XSL-List info and archive
> ><http://lists.mulberrytech.com/unsub/xsl-list/2607481>EasyUnsubscribe
> (by email)
> >
> >
> >
> >--
> >Dave Pawson
> >XSLT XSL-FO FAQ.
> >Docbook FAQ.
> ><http://www.mulberrytech.com/xsl/xsl-list>XSL-List info and archive
> ><http://lists.mulberrytech.com/unsub/xsl-list/96802>EasyUnsubscribe
> (<>by email)
>
>
> --
> Contact info, blog, articles, etc. http://www.CraneSoftwrights.com/s/ |
> Check our site for free XML, XSLT, XSL-FO and UBL developer resources |
> Streaming hands-on XSLT/XPath 2 training class @US$50 (5 hours free!) |
> Essays (UBL, XML, etc.) http://www.linkedin.com/today/author/gkholman |
> 
>
>

-- 
Dave Pawson
XSLT XSL-FO FAQ.
Docbook FAQ.

Current Thread