Re: [xsl] A challenge.. Group Periods of Data (1..5, 2..8, 4..9) (10..12; 10..14)

Subject: Re: [xsl] A challenge.. Group Periods of Data (1..5, 2..8, 4..9) (10..12; 10..14)
From: Karl Stubsjoen <kstubs@xxxxxxxxx>
Date: Wed, 4 May 2005 18:06:26 -0700
David, thanks for the reply!  Also, just curious...

How long did it take you to come up with this solution?
Was it easy maybe even obvious for you?
Have you seen similar problems like this in the past so you had a good
idea how to approach this?


On 5/4/05, David Carlisle <davidc@xxxxxxxxx> wrote:
>
>
> > David, WOW!  ... i'm still trying to figure out how it works ...
> > So, can you explain?  This is like magic..
>
> Have you considered the possibility that it really is magic?
> Asking how it works might spoil the fun.
> It's just like sawing ladies in half...
>
> > Things I don't get:
> Oh if you insist...
>
>
> > 1)  Variable e2 select.
> > select="@period_end[. &gt; $e]|$e[. &gt;= current()/@period_end]"
> >
>
> That expression is just me being tricksy, It just sets e2 to being the
> maximum of e and the current period_end attribute, ie as you walk along
> the list one at a time it keeps a note of the current period end.
>
> I could have written
>
> <xsl:variable name="e2">
> <xsl:choose>
>  <xsl:when test="@period_end &gt; $e"><xsl:value-of
select="@period_end"/></xsl:when>
>  <xsl:otherwise><xsl:value-of select="$e"/></xsl:otherwise>
> </xsl:choose>
> </xsl:variable>
>
> but that would just make people yearn for XSLT2's
>
> <xsl:variable name="e2" select="max(@period_end,$e)"/>
>
> Whereas the version I used makes XSLT1 look exotic and enticing:-)
>
> > How does the pipe work here and is this only evaluating the current B
> > element, or evaluating all @period_end(s)?
>
> The thing about understanding Xpath expressions is to remember that
> things mean what they mean, even if they get used in unexpected places,
> so if I'd have gone
> select="a|b"
> you would probably not have asked what | means: it means select all a's
> and all b's and take the union of those two selections.
> similarly if I'd have gone
> selct="@foo"
> you probably wouldn't have asked which element this is the foo atribute
> of, it's (just) the curent element.
> so putting it all together
> @period_end[. &gt; $e]
> selects those period_end attributes of the current element for which the
> value of the attribute is greater than $e. Since there is only one
> period_end  attribute this either selects that attribute (if it is
> greater than $e) or selects the empty set otherwise.
>
> the other side of the |
> is
> $e[. &gt;= current()/@period_end]
> the [] predicate is the negation of the last one, so this node set is $e
> if the other node set is empty and empty if the other node set is
@period_end
>
> so the | is the union of two node sets, one of which has one attribute
> node, the other is empty so $e2 ends up being a node set of exactly one
> attribute node, with value the maximum of the two attributes compared.
>
>
> > 2)  Right off the bat (first iteration), I don't understand how you
> > determine the period attribute "ends" value.
>
> You walk along the nodes one at a time, carrying the current best guess
> of the end of the period in the parameter $e, as discussed above.
> You can tell when to stop because there is no B note that "overlaps"
> this current guessed end, ie there is a B that starts before $e2 and
> ends after it:
>
> <xsl:when test="../B[@period_begin &lt;=$e2 and @period_end &gt; $e2]">
>
> If this condition is not satisfied you just process the next node and try
> again. You never output any elements until you get to the end of a
> range, you just pass the beginning of the range, the current best guess
> of the end, and all the B nodes so far collected in the three parameters
> b e and g.
>
> Once it is satisfied you can make your wrapper element with the
> determined range and then just copy-of $g and the current element
> to form the content, then agsin process the next B, this time not
> setting any parameters so you initialise a new range.
>
> > 3)  Variable g select, what does this get you, the ancestor record?
> > select="/.."
>
> The value on a param setting is only used if a parameter is not
> explictly supplied. /.. is the parent of the root node, which doesn't
> exist so this is the empty set. If instead I had gone
> <xsl:param name="g" />
> the default value would have been an empty string
> but then when you try to add teh current node to teh collection when
> moving on to the next node:
>  <xsl:with-param name="g" select="$g|."/>
> The | would generate an error that it can't be used with an empty
> string if $g was ""/ If $g is the empty set then $g|. is the union of
> the emopty set and the current node, which is the current node.
>
>
> > 4) The copy of within the element period within the otherwise then the
> > apply templates rule, it obviously creates the new <period/> element,
> > but I don't see how your recursive template call inserts the
> > "members", I don't get how you are preserving the member element of
> > period
>
> No. The copy-of copies $g (all the B elements picked up earlier in this
> range, and . which is the current B element)
> the period element isn't copied from anywhere, it's gneretaed as a
> literal result element on the line above:
>  <period begins="{$b}" ends="{$e2}">
>
> Having just looked over this, I think my XSLT is easier to understand
> than my English description of it, so maybe I should just give up and
> see if the list auto-documentation-daemon is triggered and documentation
> arrives from elsewhere....
>
> David
>
> ________________________________________________________________________
> This e-mail has been scanned for all viruses by Star. The
> service is powered by MessageLabs. For more information on a proactive
> anti-virus service working around the clock, around the globe, visit:
> http://www.star.net.uk
> ________________________________________________________________________

Current Thread