Re: [xsl] Finding the maximun number of nodes

Subject: Re: [xsl] Finding the maximun number of nodes
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Sat, 6 Jan 2001 11:18:39 +0000
Hi Dimitre,

> Certainly this cannot be done with the available XSLT instructions, but
> can be simulated by replacing the for-each loop with calling a
> recursive template. In case there's only one row with a maximum number
> of columns, and this row is the last one (the worst case), this
> template will call itself for every next row of the table. In any other
> case it will return immediately when a row with a maximum number of
> columns has been found.

I'm not sure that I understand: in order to know whether 'this row'
has more cells in it than any of the following rows, you *have* to
look at the rest of the rows, so even the best solution has to look at
every row.

Given that, I think that this is the solution that most closely
approximates to what you've described above.

<xsl:template name="maxCols">
  <!-- template 'called on' first row -->
  <xsl:apply-templates select="//tr[1]" mode="maxCols" />
</xsl:template>

<xsl:template match="tr" mode="maxCols">
  <!-- finds the maximum of the other rows to see whether it has the
       most -->
  <xsl:variable name="max">
     <xsl:apply-templates select="following-sibling::tr[1]" mode="maxCols" />
  </xsl:variable>
  <xsl:choose>
    <!-- gives the maximum of the other rows if that's larger -->
    <xsl:when test="$max &gt; count(td)">
       <xsl:value-of select="$max" />
    </xsl:when>
    <!-- gives the maximum of this row if that's larger -->
    <xsl:otherwise><xsl:value-of select="count(td)" /></xsl:otherwise>
  </xsl:choose>
</xsl:template>

> So, in contrast with the current solution, only one number will be
> output -- not a delimited sequence.

All the solutions that I put forward gave only one number rather than
a delimited sequence.

Given that finding the maximum or minimum of an expression run over a
group of nodes is such a common (and problematic) use case, there
seems to be a good case for something like saxon:max()/saxon:min() to
become part of XPath.  In this situation, you could use:

  saxon:max(tr, saxon:expression('count(td)'))

and let the processor optimise how the maximum is found. I guess an
alternative future syntax that's closer to how XPath/XSLT currently
works could be to use an element instead of an XPath function:

  <xsl2:max select="tr" use="count(td)" />

If there was an XPath max() function that worked in the same way as
sum() (i.e. used the value of the nodes to calculate the maximum)
another solution would be to construct a variable (implicitly
interpreted as a node set) and then use max() on it:

<xsl:variable name="cellNumbers">
  <xsl:for-each select="tr">
    <row><xsl:value-of select="count(td)" /></row>
  </xsl:for-each>
</xsl:variable>
<xsl:value-of select="max($cellNumbers)" />

Anyone know if max()/min() is likely to be in the next version of
XPath?

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread