Re: [xsl] In XSL how do you group common child nodes and associate duplicate parents to it?

Subject: Re: [xsl] In XSL how do you group common child nodes and associate duplicate parents to it?
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Thu, 7 Feb 2002 10:00:36 +0000
Hi Su,

What you're essentially doing is grouping all the C elements by their
Dname descendants. Naturally you can use the Muenchian Method (see
http://www.jenitennison.com/xslt/grouping - read it before you try
this solution) but there's a bit of a twist because each C element can
have multiple Dname descendants. What you have to do is index the
Dname elements themselves, by their value, and then work backwards
from there.

The key that you need is:

<xsl:key name="Ds" match="Dname" use="." />

Then, given a particular Dname, held in a $Dname variable, you can
find all the Dnames with the same value with:

  key('Ds', $Dname)

>From these Dname elements, you can move up the node tree to the CName
elements that you're interested in, with:

  key('Ds', $Dname)/../../CName

The tricky part is finding the unique Dnames throughout the document.
Assuming you're on the A element, you need to do something like:

  <xsl:for-each select="C/D/Dname">
    <xsl:variable name="current-group" select="key('Ds', .)" />
    <xsl:if test="generate-id() = generate-id($current-group[1])">
      <tr>
        <td><xsl:value-of select="." /></td>
        <xsl:for-each select="$current-group/../../CName">
          <td><xsl:value-of select="." /></td>
        </xsl:for-each>
      </tr>
    </xsl:if>
  </xsl:for-each>

---

Note for experienced Muenchian Method watchers - the above uses Ken
Holman's method of separating out the steps - the xsl:for-each selects
the nodes that you want to group; the xsl:variable collects together
the group for that node; the xsl:if does the filtering that would
normally be stuffed in a predicate. Doing this makes it closer to what
you'd have in XSLT 2.0:

  <xsl:for-each-group select="C/D/Dname" group-by=".">
    <tr>
      <td><xsl:value-of select="." /></td>
      <xsl:for-each select="current-group()/../../CName">
        <td><xsl:value-of select="." /></td>
      </xsl:for-each>
    </tr>
  </xsl:for-each-group>

The one problem is that the position()s are probably not what you want
in the XSLT 1.0 version - based on the positions of the Dnames in the
original document, rather than in the list of distinct values.
  
Cheers,

Jeni

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


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


Current Thread