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

Subject: [xsl] Selecting previous node in newly-sorted group (not input document order)
From: Tim Lebo <timleboxslt@xxxxxxxxx>
Date: Fri, 27 Jan 2006 16:13:12 -0500
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