Re: [xsl] one key or a whole bunch?

Subject: Re: [xsl] one key or a whole bunch?
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Tue, 21 May 2002 18:12:43 +0100
Hi Marina,

> I need to get a count of all the groups of <SHELF_NO>'s that are the
> same. I need the output to be in the form (with the example above):-
> Shelf Groups   Number of Copies
> 0   0 <--i.e. no instance of no shelf number
> 1   1 <--i.e. 1 instance of just one unique shelf number
> 2   0 <--i.e no instance of two shelf numbers the same
> 3   1 <--i.e. 1 instance where three shelf numbers were the same
> etc etc

If I understand you properly, that's quite a difficult analysis to do,
especially in one step. The best thing to do would be to break it down
into two steps:

  - create a list of the unique shelf numbers and the number of
    occurrences of each of those shelf numbers

  - use a recursive template to go up through the possible numbers of
    repeats, and count how many there are of each.

The first step involves your kShelf key:

<xsl:key name="kShelf" match="SPORTS | LEISURE | CLOTHES | GIFTS"

To create the node set of unique SHELF_NO elements, you need to use
the Muenchian method, as you'd started doing:

  <xsl:variable name="shelves-rtf">
    <xsl:for-each select="SHOP/*[generate-id() =
      <SHELF_NO count="count(key('kShelf', SHELF_NO))">
        <xsl:value-of select="SHELF_NO" />
  <xsl:variable name="shelves" select="exsl:node-set($shelves-rtf)" />

That will give you $shelves, as a node set containing something like:

  <SHELF_NO count="1">4567</SHELF_NO>
  <SHELF_NO count="3">3344</SHELF_NO>

You can then pass this node set to a recursive template that steps up
from 0 through to however many is required, counting how many SHELF_NO
elements have a particular value for their count attribute. The
recursive call adds one to the count, and only passes on those
SHELF_NO elements that don't have the particular count (gradually
working through the list of SHELF_NO elements). Something like:

<xsl:template name="frequency-table">
  <xsl:param name="count" select="0" />
  <xsl:param name="shelves" select="/.." />
  <xsl:if test="$shelves">
    <xsl:variable name="shelves-with-count"
                  select="$shelves[@count = $count]" />
    <xsl:variable name="nshelves-with-count"
                  select="count($shelves-with-count)" />
    <xsl:value-of select="$count" />
    <xsl:text> </xsl:text>
    <xsl:value-of select="$nshelves-with-count" />
    <xsl:call-template name="frequency-table">
      <xsl:with-param name="count" select="$count + 1" />
      <xsl:with-param name="shelves"
                      select="$shelves[count(.|$shelves-with-count) !=
                                       $nshelves-with-count]" />

Once you'd created the $shelves variable (as above), you could call
this template with:

  <xsl:call-template name="frequency-table">
    <xsl:with-param name="shelves" select="$shelves" />



Jeni Tennison

 XSL-List info and archive:

Current Thread