[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Conditional Grouping Problem


Subject: Re: [xsl] Conditional Grouping Problem
From: "James A. Robinson" <jimr@xxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 25 May 2004 20:51:17 -0700

> If we focus on section 1 for now, I'm using the Muenchian Method with a
> key like:
> <xsl:key name="product-by-name" match="Product" use="name" />
> How can I modify this key to match only products which are part of a 
> single order (the Product's buyer only bought 1 item)?
> I'm stretching my xsl knowledge here..

If we make the important assumption that each product element has a unique
buyer/name pairing (in other words, Jane Doe & Our Worst Widget will
only appear once), I believe you can use keys of buyers for products
and products for buyers to achieve what you want (there may well be
better ways of doing this, but I've had a few beers so please forgive
any inefficiencies).

<?xml version="1.0" encoding="UTF-8" ?>
<!--
List all buyers of a single product by product
List all buyers of multiple products by buyer
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:output method="xml" indent="yes"/>

  <!-- all products keyed off of name -->
  <xsl:key name="products" match="product" use="string(name)"/>

  <!-- all buyers keyed off product name -->
  <xsl:key name="buyer_for_product" match="buyer" use="string(following-sibling::name)"/>

  <!-- all products keyed off of buyer -->
  <xsl:key name="products_for_buyer" match="product" use="string(buyer)"/>

  <!-- all buyers keyed of buyer name -->
  <xsl:key name="buyers" match="buyer" use="string(.)"/>

  <xsl:template match="/">
    <xsl:text>&#10;</xsl:text>
    
    <xsl:comment>single product buyers by product name</xsl:comment>
    <!-- for each unique product in list of purchased products -->
    <xsl:for-each select="//product[generate-id() = generate-id(key('products', string(name))[1])]">
      <!-- output product name -->
      <name>
        <xsl:value-of select="name"/>
      </name>
      <!-- for each buyer for this particular product -->
      <xsl:for-each select="key('buyer_for_product', string(name))">
        <!--
            output buyer name if buyer purchased 1 product (i.e., only bought this one)
            (it's important to note this assume UNIQUE product buyer & name pairings)
          -->
        <xsl:if test="count(key('products_for_buyer', string(.))) = 1">
          <buyer>
            <xsl:value-of select="."/>
          </buyer>
        </xsl:if>
      </xsl:for-each>
    </xsl:for-each>
    <xsl:text>&#10;</xsl:text>

    <xsl:comment>multiple product buyers by buyer</xsl:comment>
    <!-- for each unique buyer -->
    <xsl:for-each select="//buyer[generate-id() = generate-id(key('buyers', string(.))[1])]">
      <!--
        print buyer if they purhcased more than one product
        (it's important to note this assumes UNIQUE product buyer & name pairings)
      -->
      <xsl:if test="count(key('products_for_buyer', string(.))) &gt; 1">
        <buyer>
          <xsl:value-of select="."/>
        </buyer>
        <xsl:for-each select="key('products_for_buyer', string(.))">
          <product>
            <xsl:value-of select="string(name)"/>
          </product>
        </xsl:for-each>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Results in:

<?xml version="1.0" encoding="utf-8"?>
<!--single product buyers by product name-->
<name>Our Best Widget</name>
<buyer>John Dow</buyer>
<buyer>Jane Doe</buyer>
<name>Our Worst Widget</name>
<buyer>Jill Doe</buyer>
<!--multiple product buyers by buyer-->
<buyer>John Q. Public</buyer>
<product>Our Best Widget</product>
<product>Our Worst Widget</product>


Current Thread
Keywords
xsl