RE: [xsl] two at a time, using a sequence expression

Subject: RE: [xsl] two at a time, using a sequence expression
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Thu, 5 Jun 2008 22:58:18 +0100
> I'm curious if there is a more elegant way to use a sequence 
> expression to process two adjacent elements at a time.  With 
> XSLT 1.0 I would have used recursion, but with XSLT/XPath 2.0 
> I'm wondering if I can exploit sequences.  Below is something 
> I've come up with so far.

>       <xsl:for-each select="for $i in 1 to (count(*) idiv 2 +
> (count(*) mod 2)) return *[($i*2)-1]">
>         <pair>
>           <xsl:copy-of select="." />
>           <xsl:copy-of select="./following-sibling::*[1]" />
>         </pair>
>       </xsl:for-each>

It seems to me that you can either write code that assumes you're working
with a sequence of siblings, or you can write code that works with an
arbitrary sequence. For sibling elements, the following works just fine:

<xsl:for-each select="*[position() mod 2 = 1]">
  <pair>
    <xsl:copy-of select="., following-sibling::*[1]" />
  </pair>
</xsl:for-each>

If you want to work with an arbitrary sequence $SEQ (not necessarily
siblings), try

<xsl:for-each select="1 to count($SEQ)[. mod 2 = 1]">
  <xsl:variable name="p" select="."/>
  <pair>
    <xsl:copy-of select="$SEQ[$p], $SEQ[$p+1]" />
  </pair>
</xsl:for-each>

Alternatively of course there is

<xsl:for-each-group select="$SEQ" group-adjacent="(position()-1) idiv 2">
  <pair>
    <xsl:copy-of select="current-group()"/>
  </pair>
</xsl:for-each-group>

> 
> An interesting side note, I thought the sequence expression 
> would error because of divide by zero, but it appears to be 
> side effect free, at least with Saxon.

I can't see where you think you might be dividing by zero.

Michael Kay
http://www.saxonica.com/

Current Thread