[xsl] Maximum (Was Re: counting/comparing values)

Subject: [xsl] Maximum (Was Re: counting/comparing values)
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Fri, 9 Nov 2001 21:35:16 -0800 (PST)
> I am stuck trying to get the highest number of child elements of a
> particular type.  What I would like to do is return the count of the most
> <entry> elements within a single <row> of a <table>:

In January there was a thread in this group on the solution of exactly the same
problem.

Another, functional solution is the following:

maximum  = foldl1 max

where foldl1 is a foldl function that is defined on non-empty lists

Here's a translation of this into XSLT:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:maximum-pick-bigger="f:maximum-pick-bigger"
xmlns:maximum-own-compare="f:maximum-own-compare"
exclude-result-prefixes="xsl maximum-own-compare maximum-pick-bigger"
>
   <xsl:import href="foldl.xsl"/>

   <maximum-pick-bigger:maximum-pick-bigger/>
   <maximum-own-compare:maximum-own-compare/>

    <xsl:template name="maximum">
      <xsl:param name="pList" select="/.."/>
      <xsl:param name="pCMPFun" select="/.."/>

      <xsl:variable name="vdfCMPFun" 
           select="document('')/*/maximum-own-compare:*[1]"/>
      <xsl:variable name="vFoldFun" 
           select="document('')/*/maximum-pick-bigger:*[1]"/>
   
      <xsl:if test="$pList">
         <xsl:variable name="vCMPFun" select="$pCMPFun |
$vdfCMPFun[not($pCMPFun)]"/>
         <xsl:variable name="vFuncList">
            <xsl:copy-of select="$vFoldFun"/> <!-- Pick Bigger -->
            <xsl:copy-of select="$vCMPFun"/>  <!-- Compare -->
         </xsl:variable>

         <xsl:call-template name="foldl">
            <xsl:with-param name="pFunc" select="msxsl:node-set($vFuncList)/*"/>
            <xsl:with-param name="pList" select="$pList"/>
            <xsl:with-param name="pA0" select="$pList[1]"/>
         </xsl:call-template>
      </xsl:if>
    </xsl:template>

    <xsl:template name="pickBigger" match="maximum-pick-bigger:*">
         <xsl:param name="arg0"/>
         <xsl:param name="arg1"/>
         <xsl:param name="arg2"/>

         <xsl:variable name="vIsGreater">
           <xsl:apply-templates select="$arg0">
             <xsl:with-param name="arg1" select="$arg1"/>
             <xsl:with-param name="arg2" select="$arg2"/>
           </xsl:apply-templates>
         </xsl:variable>
         <xsl:choose>
           <xsl:when test="$vIsGreater = 1">
             <xsl:copy-of select="$arg1"/>
           </xsl:when>
           <xsl:otherwise>
             <xsl:copy-of select="$arg2"/>
           </xsl:otherwise>
         </xsl:choose>
    </xsl:template>

    <xsl:template name="isGreaterDefault" match="maximum-own-compare:*">
         <xsl:param name="arg1"/>
         <xsl:param name="arg2"/>

         <xsl:choose>
          <xsl:when test="$arg1 > $arg2">1</xsl:when>
          <xsl:otherwise>0</xsl:otherwise>
         </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

This returns a copy of the "maximum" node. The caller may provide as parameters
their own function (template reference to a template) that returns 1 if the node
passed as "arg1" to it is the "bigger" of the two nodes. In case the compared values
are numbers, no reference to an isGreater template needs to be provided and a
default internal one is used.

The XSLT implementation of foldl is available at:

http://sources.redhat.com/ml/xsl-list/2001-11/msg00214.html

Cheers,
Dimitre Novatchev.






__________________________________________________
Do You Yahoo!?
Find a job, post your resume.
http://careers.yahoo.com

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


Current Thread