xsl-list
[Top] [All Lists]

Re: [xsl] Problem sorting incoming node list

2019-05-08 12:18:18
I haven't had a chance to study all of this, but please note that if you want 
to use the XPath 3.1 function then you should be using a more recent Saxon 
release than 9.3. The current version is 9.9. Also, only the 1-argument version 
of sort() will work in Saxon-HE; the more useful versions of the function (that 
allow a user-defined sort key) are higher order functions and therefore require 
Saxon-PE or Saxon-EE. The syntax would be

<xsl:for-each-group select=“sort(entry[location=$undulator], function($entry) 
{data($entry/(isodate,time))})" group-by="statistics_category">

Michael Kay
Saxonica

On 8 May 2019, at 18:08, Raimund Kammering 
raimund(_dot_)kammering(_at_)desy(_dot_)de 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:

Hello,

I have simple sorting problem but none the less am completely stuck!

I know the standard techniques for sorting and how and where to apply it - at 
least I thought so! But for the given set of transformations I fail to fiddle 
in the sorting for one part of the transformations!

Problem is as follows:

XML is like this (sorry for the long example, but to make the not nice order 
clear I need to supply such a sequence)

<list>
<entry>
<severity>NONE</severity>
<isodate>2019-05-06</isodate>
<time>07:01:03</time>
<location>not set</location>
<category>USERLOG</category>
</entry>
<entry>
<severity>STATISTICS</severity>
<isodate>2019-05-06</isodate>
<time>07:00:00</time>
<location>SASE1</location>
<statistics_category>SASE_delivery</statistics_category>
<SASE_tuning>not_set</SASE_tuning>
<Linac_setup>not_set</Linac_setup>
<Down>not_set</Down>
<category>STATISTICS</category>
</entry>
<entry>
<severity>STATISTICS</severity>
<isodate>2019-05-06</isodate>
<time>07:00:00</time>
<location>SASE2</location>
<statistics_category>SASE_delivery</statistics_category>
<SASE_tuning>not_set</SASE_tuning>
<Linac_setup>not_set</Linac_setup>
<Down>not_set</Down>
<category>STATISTICS</category>
</entry>
<entry>
<severity>STATISTICS</severity>
<isodate>2019-05-06</isodate>
<time>07:00:00</time>
<location>SASE3</location>
<statistics_category>SASE_delivery</statistics_category>
<SASE_tuning>not_set</SASE_tuning>
<Linac_setup>not_set</Linac_setup>
<Down>not_set</Down>
<category>STATISTICS</category>
</entry>
<entry>
<severity>NONE</severity>
<isodate>2019-05-06</isodate>
<time>07:15:53</time>
<location>not set</location>
<category>USERLOG</category>
</entry>
...
<entry>
<severity>NONE</severity>
<isodate>2019-05-06</isodate>
<time>08:57:47</time>
<category>USERLOG</category>
</entry>
<entry>
<severity>STATISTICS</severity>
<isodate>2019-05-06</isodate>
<time>08:30:00</time>                                       <——— This <entry> 
is NOT sorted according to time!
<location>ACCELERATOR</location>
<statistics_category>Linac_setup</statistics_category>
<Linac_setup>not_set</Linac_setup>
<SASE_tuning>not_set</SASE_tuning>
<Down>not_set</Down>
<category>STATISTICS</category>
</entry>
<entry>
<severity>NONE</severity>
<isodate>2019-05-06</isodate>
<time>09:08:45</time>
<category>USERLOG</category>
</entry>
</list>

‘Normal’ processing of this is no problem with the following XSLT

<xsl:template match=“list”>
…
 <xsl:apply-templates select="entry">
   <xsl:sort order=“descending" select="isodate"/>
   <xsl:sort order=“descending" select="time"/>
 </xsl:apply-templates>
…
</xsl:template>

This correctly produces one to one processing of the standard entries 
(category=USERLOG). But now I need to do some bulk processing to evaluate 
some time differences. Logic is roughly like this:

1. get (first) category=‘STATISTICS’ entry
2. find next one (smaller times since descending) with same location
3. Calculate time difference (done by a function f:duration-in-hours())
4. Advance to new found time step
5. repeat

This is done for all possible locations and even allows easily summing up  
the partial time spans like this:

<xsl:template name="statistics_summary">
<xsl:param name="undulator"/>
 <xsl:for-each-group select="entry[location=$undulator]" 
group-by="statistics_category">
   <xsl:value-of select="current-grouping-key()"/>
   <xsl:text>: &#160;</xsl:text>
   <xsl:value-of 
select="format-number(sum(current-group()/f:duration-in-hours(.,$undulator)), 
'0.00'), ' h'"/>
 </xsl:for-each-group>
</xsl:template>

This template is called from the list template like this:

<xsl:template match=“list”>
…
 <xsl:call-template name="statistics_summary">
    <xsl:with-param name="undulator">ACCELERATOR</xsl:with-param>
 </xsl:call-template>
 <xsl:call-template name="statistics_summary">
    <xsl:with-param name="undulator”>SASE1</xsl:with-param>
 </xsl:call-template>
 <xsl:call-template name="statistics_summary">
    <xsl:with-param name="undulator”>SASE2</xsl:with-param>
 </xsl:call-template>
 <xsl:call-template name="statistics_summary">
    <xsl:with-param name="undulator”>SASE3</xsl:with-param>
 </xsl:call-template>
...
 <xsl:apply-templates select="entry">
   <xsl:sort order=“descending" select="isodate"/>
   <xsl:sort order=“descending" select="time"/>
 </xsl:apply-templates>
…
</xsl:template>

The whole transformations work well except for that the incorrect order in 
respect to the <time> value make the result incorrect!

So idea is clearly: Sort the entries according to the <time> element before 
processing with for-each-group. But here I completely failed!
First idea would be to use apply-templates instead of call-template to allow 
the use of xsl:sort, but this breaks all logic implemented for the time span 
calculations. Next would be to sort within the statistics_summary template, 
but here I guess I’m on the wrong axis - right?
Even tried to do a copy-of to create a small node set only containing the 
relevant entries and sort these prior to passing it to the for-each-group but 
did not manage to do so and might anyhow not be very clever. Naively thinking 
I would love to have a kind of xpath sort to allow something like this:

<xsl:for-each-group select=“sort(entry[location=$undulator]”, (isodate,time)) 
group-by="statistics_category">

and found this to be present in xpath 3.1. But here I ran into transformer 
exceptions concerning the syntax (using Saxon 9.3.0.5 HE)

So that I’m now finally complete stuck to find an reasonable solution 
(without reworking the whole statistics calculation)! Any help would be very 
appreciated!

Greetings,
Raimund

--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--

<Prev in Thread] Current Thread [Next in Thread>