Re: [xsl] Help me to select group based on maximum value

Subject: Re: [xsl] Help me to select group based on maximum value
From: Michael Kay <mike@xxxxxxxxxxxx>
Date: Fri, 31 Aug 2012 16:04:58 +0100
Untested solution:

<xsl:for-each-group select="Product" group-adjacent="@id">
  <xsl:for-each select="current-group()">
      <xsl:sort select="number(rank)" order="descending"/>
      <xsl:if test="position() = 1">
         <xsl:copy-of select="."/>
      </xsl:if>
   </xsl:for-each>
</xsl:for-each-group>

Michael Kay
Saxonica

On 31/08/2012 15:56, ROCK ROCKA wrote:
Hi ,

I want to use XSL 2.0 to transform very big file of size 20 MB XML
data to filter some of the elements. I downsized that input and pasted
here.  I want to select only one node based on highest number in it's
element 'rank'  from multiple product elements by grouping it's
attribute 'id'. Output should look like shown below.

My XSL is selecting all productids and  can't get the logic to group
by id. I will appreciate if you can help me doing group by id
attribute in this XSL.

Here is my input XML :

<?xml version="1.0"?>
<Products groupid="14567-567">
     <Manager id="8789"/>
     <Product id="998">
         <rank>1</rank>
         <LocationID>676</LocationID>
         <CompanyID>A58</CompanyID>
         <QAcheckID>Q349</QAcheckID>
     </Product>
     <Product id="998">
         <rank>2</rank>
         <LocationID>897</LocationID>
         <CompanyID>A56</CompanyID>
         <QAcheckID>Q349</QAcheckID>
     </Product>
     <Product id="998">
         <rank>3</rank>
         <LocationID>556</LocationID>
         <CompanyID>A51</CompanyID>
         <QAcheckID>Q349</QAcheckID>
     </Product>
     <Product id="998">
         <rank>4</rank>
         <LocationID>544</LocationID>
         <CompanyID>A50</CompanyID>
         <QAcheckID>Q349</QAcheckID>
     </Product>
     <Product id="754">
         <rank>1</rank>
         <LocationID>672</LocationID>
         <CompanyID>A58</CompanyID>
         <QAcheckID>Q349</QAcheckID>
     </Product>
     <Product id="754">
         <rank>2</rank>
         <LocationID>891</LocationID>
         <CompanyID>A56</CompanyID>
         <QAcheckID>Q350</QAcheckID>
     </Product>
     <Product id="442">
         <rank>3</rank>
         <LocationID>556</LocationID>
         <CompanyID>A51</CompanyID>
         <QAcheckID>Q350</QAcheckID>
     </Product>
     <Product id="998">
         <rank>5</rank>
         <LocationID>544</LocationID>
         <CompanyID>A50</CompanyID>
         <QAcheckID>Q349</QAcheckID>
     </Product>
     <ratingrank>A1</ratingrank>
     <salesratio>.82</salesratio>
</Products>


output:


<?xml version="1.0"?>
<Products groupid="14567-567">
     <Manager id="8789"/>
     <Product id="998">
         <rank>4</rank>
         <LocationID>544</LocationID>
         <CompanyID>A50</CompanyID>
         <QAcheckID>Q349</QAcheckID>
     </Product>
     <Product id="754">
         <rank>2</rank>
         <LocationID>891</LocationID>
         <CompanyID>A56</CompanyID>
         <QAcheckID>Q350</QAcheckID>
     </Product>
     <Product id="442">
         <rank>3</rank>
         <LocationID>556</LocationID>
         <CompanyID>A51</CompanyID>
         <QAcheckID>Q350</QAcheckID>
     </Product>
     <Product id="998">
         <rank>5</rank>
         <LocationID>544</LocationID>
         <CompanyID>A50</CompanyID>
         <QAcheckID>Q349</QAcheckID>
     </Product>
     <ratingrank>A1</ratingrank>
     <salesratio>.82</salesratio>
</Products>


my XSL:



<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; xmlns:xs="http://www.w3.org/2001/XMLSchema"; xmlns:my="my:my"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
   <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
   </xsl:copy>
  </xsl:template>

  <xsl:template match=
  "Product [@id]
    [not(rank eq my:max(../Product/rank))
    or
     rank = preceding-sibling::Product /rank
    ]"/>

  <xsl:function name="my:max" as="xs:string">
    <xsl:param name="pValues" as="xs:string+"/>

    <xsl:sequence select=
     "if(not(distinct-values($pValues)[2]))
        then $pValues[1]
      else
       for $vMax1 in
              max(for $s in $pValues
                   return
                     xs:integer(substring-before(concat($s,'.'),'.'))
                  ),

           $vcntMax1Values in
              count($pValues[starts-with(., string($vMax1))])

         return
           if($vcntMax1Values eq 1)
             then $pValues[starts-with(., string($vMax1))]
                           [1]
             else
              for $submax in
                      (my:max(for $val in
                                     $pValues[starts-with(., string($vMax1))]
                                                 [contains(., '.')],
                                     $subval in substring-after($val, '.')
                                 return
                                     $subval
                              )
                       )
                  return
                    concat($vMax1, '.', $submax)

     "/>
  </xsl:function>
</xsl:stylesheet>

- Sunny

Current Thread