[xsl] Re: Selecting previous node in newly-sorted group (not input document order)

Subject: [xsl] Re: Selecting previous node in newly-sorted group (not input document order)
From: Tim Lebo <timleboxslt@xxxxxxxxx>
Date: Fri, 27 Jan 2006 17:44:56 -0500
OBE. Solution:

      2 <xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">
      3 <xsl:output method="text"/>
      4
      5 <xsl:template match="/">
      6   <xsl:for-each-group select="//outline[@Start]" group-by="@Date">
      7     <xsl:value-of select="concat(current-grouping-key(),$NL)"/>
      8
      9     <xsl:variable name="todaysentries">
     10       <xsl:perform-sort select="current-group()">
     11         <xsl:sort select="substring-before(@Start,':')"
data-type="number"/>
     12         <xsl:sort select="substring-after(@Start,':')"
data-type="number"/>
     13       </xsl:perform-sort>
     14     </xsl:variable>
     15
     16     <xsl:for-each select="$todaysentries/outline">
     17       <xsl:if test="position() &gt; 1">
     18         <xsl:variable name="previousposition" select="position() -
1"/>
     19         <xsl:variable name="previous"
select="$todaysentries/outline[$previousposition]"/>
     20         <xsl:value-of select="concat(@Date,' prev position
',$previousposition,' stopped ',$previous/@Stop,
     21                                      ' current entry
',@Start,' ',@Stop,$NL)"/>
     22       </xsl:if>
     23     </xsl:for-each>
     24
     25   </xsl:for-each-group>
     26 </xsl:template>
     27
     28 <xsl:variable name="NL">
     29 <xsl:text>
     30 </xsl:text>
     31 </xsl:variable>
     32
     33 </xsl:transform>


On 1/27/06, Tim Lebo <timleboxslt@xxxxxxxxx> wrote:
> I have task listings in OPML that looks like the following. I am
> trying to write a transform that will point out temporal gaps existing
> between the entries of a single day (e.g. 9:00 to 9:15 DNE in sample).
>
> I was making pretty good headway with the for-each-group and sort
> constructs, which orders the entries just fine. However, I am unable
> to select the previous node of the newly-ordered nodes. I think the
> preceding-sibling axis on line 14 is looking back to the document
> order and not the newly-ordered nodes. So, I tried to direct my scope
> to the current-group with:
>
> 14         <xsl:variable name="previous"
>
select="$todaysentries/preceding-sibling::outline[position()=$previouspositio
n]"/>
>
> But this selects more than one node. I also attempted a multivalue key
> with @Date and @Stop to no avail. Does this require use of a sequence
> constructor instead of the @use attribute?
>
> Thanks yet again,
> Tim Lebo
>
> Input:
> <?xml version="1.0" encoding="UTF-8"?>
> <opml version="1.0">
>   <body>
>     <outline text="2010.1.25">
>       <outline text="task1" Date="2010.1.25" Start="7:00" Stop="8:00"/>
>       <outline text="task2" Date="2010.1.25" Start="8:00" Stop="9:00"/>
>       <outline text="skipped 15 minutes since last stop"
> Date="2010.1.25" Start="9:15" Stop="9:30"/>
>       <outline text="multiple entries within an hour" Date="2010.1.25"
> Start="9:30" Stop="9:45"/>
>       <outline text="multiple entries within an hour out of order"
> Date="2010.1.25" Start="9:50" Stop="10:00"/>
>       <outline text="multiple entries within an hour" Date="2010.1.25"
> Start="9:45" Stop="9:50"/>
>       <outline text="should be before first entry" Date="2010.1.25"
> Start="6:00" Stop="7:00"/>
>     </outline>
>   </body>
> </opml>
>
> XSLT 2.0 (Saxon8b):
>      2 <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> version="2.0">
>       3 <xsl:output method="text"/>
>       4
>       5 <xsl:template match="/">
>       6   <xsl:for-each-group select="//outline[@Start]" group-by="@Date">
>       7     <xsl:value-of select="concat(current-grouping-key(),$NL)"/>
>       8     <xsl:variable name="todaysentries" select="current-group()"/>
>       9     <xsl:for-each select="current-group()">
>      10       <xsl:sort select="substring-before(@Start,':')"
> data-type="number"/>
>      11       <xsl:sort select="substring-after(@Start,':')"
> data-type="number"/>
>      12       <xsl:if test="position() &gt; 1">
>      13         <xsl:variable name="previousposition" select="position() -
1"/>
>      14         <xsl:variable name="previous"
> select="preceding-sibling::outline[position()=$previousposition]"/>
>      15         <xsl:value-of select="concat(@Date,' prev position
> ',$previousposition,' stopped ',$previous/@Stop,
>      16                                      ' current entry
> ',@Start,' ',@Stop,$NL)"/>
>      17       </xsl:if>
>      18     </xsl:for-each>
>      19   </xsl:for-each-group>
>      20 </xsl:template>
>      21
>      22 <xsl:variable name="NL">
>      23 <xsl:text>
>      24 </xsl:text>
>      25 </xsl:variable>
>      26
>      27 </xsl:transform>
>
>
> Current Output:
> 2010.1.25
> 2010.1.25 prev position 1 stopped  current entry 7:00 8:00
> 2010.1.25 prev position 2 stopped  current entry 8:00 9:00
> 2010.1.25 prev position 3 stopped  current entry 9:15 9:30
> 2010.1.25 prev position 4 stopped  current entry 9:30 9:45
> 2010.1.25 prev position 5 stopped 8:00 current entry 9:45 9:50
> 2010.1.25 prev position 6 stopped  current entry 9:50 10:00
>
> Desired Output:
> 2010.1.25
> 2010.1.25 prev position 1 stopped 7:00 current entry 7:00 8:00
> 2010.1.25 prev position 2 stopped 8:00 current entry 8:00 9:00
> 2010.1.25 prev position 3 stopped 9:00 current entry 9:15 9:30
> 2010.1.25 prev position 4 stopped 9:30 current entry 9:30 9:45
> 2010.1.25 prev position 5 stopped 9:45 current entry 9:45 9:50
> 2010.1.25 prev position 6 stopped 9:50 current entry 9:50 10:00

Current Thread