Re: [xsl] Re: sorting a variable that contains a nodeset

Subject: Re: [xsl] Re: sorting a variable that contains a nodeset
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Thu, 10 Jan 2002 19:00:50 +0000
Hi Rafael,

>>My intuition tells me that you might be wanting to do this because
>>you want to create groups of ARTICULO elements. If that's the case,
>>then there are different (and more portable) ways to go about it, so
>>let us know if that's what you're trying to do.
>
> Hi Jeni! You said it! I want to group articles depending on its
> category and subcategory to show them grouped in a table. I´d thank
> you your ideas!

OK. I'll show you the Muenchian grouping method. You might want to
look at http://www.jenitennison.com/xslt/grouping for more examples
and explanation.

Assuming that you want to group first by NOMBRE_FAMILIA and then by
NOMBRE_SUBFAMILIA, you need to construct two keys. The first indexes
all the ARTICULO elements by their NOMBRE_FAMILIA child element:

<xsl:key name="familia" match="ARTICULO" use="NOMBRE_FAMILIA" />

and the second indexes all the ARTICULO elements by their
NOMBRE_FAMILIA *and* NOMBRE_SUBFAMILIA child elements by concatenating
these values together:

<xsl:key name="familia-and-subfamilia" match="ARTICULO"
         use="concat(NOMBRE_FAMILIA, '+', NOMBRE_SUBFAMILIA)" />

You can then use the key() function to quickly access the ARTICULO
elements. For example:

  key('familia', 'alimentacion')

would return all the ARTICULO elements whose NOMBRE_FAMILIA had a
value of 'alimentacion'.

Likewise:

  key('familia-and-subfamilia', 'alimentacion+carnes')

would return all the ARTICULO elements whose NOMBRE_FAMILIA was
'alimentacion' and whose NOMBRE_SUBFAMILIA was 'carnes'.

So given that the context node is an ARTICULO element, you can find
all the other ARTICULO elements with the same NOMBRE_FAMILIA with:

  key('familia', NOMBRE_FAMILIA)

You can then test whether the ARTICULO element that you're looking at
is the same as the first of the ARTICULO elements returned by the key.
If it is, then it's the first ARTICULO in the document with that value
for NOMBRE_FAMILIA. You can test whether they're the same ARTICULO in
two ways:

  generate-id() = generate-id(key('familia', NOMBRE_FAMILIA)[1])

or:

  count(.|key('familia', NOMBRE_FAMILIA)[1]) = 1

You can collect all the ARTICULO elements for which this is true (i.e.
the first in the document with that NOMBRE_FAMILIA) with the
following:

  ARTICULO[count(.|key('familia', NOMBRE_FAMILIA)[1]) = 1]

Thus, you can iterate over each of the ARTICULO elements with a unique
NOMBRE_FAMILIA, in NOMBRE_FAMILIA order with:

  <xsl:for-each
    select="ARTICULO[count(.|key('familia', NOMBRE_FAMILIA)[1]) = 1]">
    <xsl:sort select="NOMBRE_FAMILIA" />
    Familia: <xsl:value-of select="NOMBRE_FAMILIA" />
    ...
  </xsl:for-each>

You can do a similar kind of thing for the second-level sort:

  <xsl:for-each
    select="ARTICULO[count(.|key('familia', NOMBRE_FAMILIA)[1]) = 1]">
    <xsl:sort select="NOMBRE_FAMILIA" />
    
    Nombre Familia: <xsl:value-of select="NOMBRE_FAMILIA" />

    <xsl:for-each
      select="key('familia', NOMBRE_FAMILIA)
                [count(.|key('familia-and-subfamilia',
                             concat(NOMBRE_FAMILIA, '+',
                                    NOMBRE_SUBFAMILIA)[1]) = 1]">
      <xsl:sort select="NOMBRE_SUBFAMILIA" />

      Nombre Subfamilia: <xsl:value-of select="NOMBRE_SUBFAMILIA" />
      ...
    </xsl:for-each>
  </xsl:for-each>

And then iterate over all the ARTICULO elements in that subgroup using
the familia-and-subfamilia key again to produce whatever details you
like.

  <xsl:for-each
    select="ARTICULO[count(.|key('familia', NOMBRE_FAMILIA)[1]) = 1]">
    <xsl:sort select="NOMBRE_FAMILIA" />
    
    Nombre Familia: <xsl:value-of select="NOMBRE_FAMILIA" />

    <xsl:for-each
      select="key('familia', NOMBRE_FAMILIA)
                [count(.|key('familia-and-subfamilia',
                             concat(NOMBRE_FAMILIA, '+',
                                    NOMBRE_SUBFAMILIA))[1]) = 1]">
      <xsl:sort select="NOMBRE_SUBFAMILIA" />

      Nombre Subfamilia: <xsl:value-of select="NOMBRE_SUBFAMILIA" />

      <xsl:for-each
        select="key('familia-and-subfamilia',
                    concat(NOMBRE_FAMILIA, '+', NOMBRE_SUBFAMILIA))">
        <xsl:sort select="DESCRIPCION_CORTA"/>
        
        <xsl:value-of select="DESCRIPCION_CORTA" />

      </xsl:for-each>
    </xsl:for-each>
  </xsl:for-each>

Cheers,

Jeni

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


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


Current Thread