Re: node after current node in xsl:for-each with xsl:sort (was: conditional page-break table based on row number?)

In regard to: Re: node after current node in xsl:for-each with xsl:sort...:

> Actually it's a bit tricky in pure xslt 1 to sort and then access the
> sorted list at the same time, as the sorted list information goes to the
> result tree where by design you can't really get it back.
>
> If you can use your processor's node-set extension (if it has one) first
> sort the input into a temporary variable then process every other item
> in this sorted list, and access the next item by
> following-sibling::*[1]
> if xx:node-set() isn't available, ask again:-)

[For the benefit of the list archives]

With David's help and some additional info from the web, especially
archived posts to the xsl-list by Michael Kay

 	http://www.mail-archive.com/xslt@p2p.wrox.com/msg06645.html

and Jeni Tennison

 	http://www.xslt.com/html/xsl-list/2002-01/msg00472.html
 	http://www.jenitennison.com/xslt/index.html     (the grouping links)

I eventually arrived at:

     <fo:table-body>

         <xsl:variable name="sorted_accounts">
             <xsl:for-each select="/request/account">
                 <xsl:sort select="id" />
                 <xsl:copy-of select="." />
             </xsl:for-each>
         </xsl:variable>

         <xsl:for-each select="exslt:node-set($sorted_accounts)/account">

         <!-- output a table row if position() mod 2 = 1 -->
         <xsl:if test="position() mod 2 = 1">
             <xsl:value-of select="$newline" />
             <fo:table-row keep-together="always">
             <xsl:value-of select="$newline" />
                 <xsl:apply-templates select="." mode="cutsheet" />
                 <xsl:apply-templates
                             select="following-sibling::*[1]"
                             mode="cutsheet" />
             </fo:table-row>
             <xsl:value-of select="$newline" />
         </xsl:if>
         </xsl:for-each>

     </fo:table-body>


Along with an "account" template (two, with two different modes for the
two types of account cells I need to output on different parts of the
form) for each cell in the table, this is working perfectly.

Two notes for future archive searchers:

- it would seem like the exslt:node-set used in the xsl:for-each should
   be just

 	<xsl:for-each select="exslt:node-set($sorted_accounts)">

Since I'm already iterating over /request/account when I create the
variable.  That's not the case, though.  The node-set($sorted_accounts)
essentially "re-roots" a copy of everything that was included in the
xsl:variable.

- This has implications for the xsl:apply-templates calls, because they're
being called with this "re-rooted" document, so if the templates want to
access something like

 	<xsl:value-of select="/request/foo/bar" />

that won't work because the template is being applied to this "re-rooted"
document, which doesn't have the same document root as the overall
document.  The trick that's used to get around this is to make a variable
that "points to" your main document root, via something like

 	<xsl:variable name="maindoc_root" select="/" />

near the top of your stylesheet, and then use

 	<xsl:value-of select="$maindoc_root/request/foo/bar" />

within the template calls that need to access nodes outside the
"re-rooted" nodes they've been called with.

My understanding of these last two points is still hazy so my explanation
is probably poor, but I hope this helps someone else in the future.

Thanks all, especially David!

Tim
-- 
Tim Mooney                              mooney@dogbert.cc.ndsu.NoDak.edu
Information Technology Services         (701) 231-1076 (Voice)
Room 242-J6, IACC Building              (701) 231-8541 (Fax)
North Dakota State University, Fargo, ND 58105-5164

Received on Wednesday, 13 October 2004 20:02:59 UTC