xsl-list
[Top] [All Lists]

Re: Conditional Grouping Problem

2004-05-26 01:25:23
I had an alternative solution. But I relied on XSLT 2.0 [SAXON].

-Menon

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <xsl:template match="products">
       <xsl:variable name="current" select="."/>
       <xsl:text>&#x0A;</xsl:text>
       <xsl:comment>single product buyers by product name</xsl:comment>
       <xsl:text>&#x0A;</xsl:text>
       <xsl:for-each-group select="product" group-by="name">
           <name>
               <xsl:value-of select="name"/>
           </name>
           <xsl:variable name="parentGroupName" select="name"/>
           <xsl:for-each-group select="$current/product" group-by="buyer">
<xsl:if test="name = $parentGroupName and count($current/product[buyer=current-group()/buyer]) &lt; 2">
                   <buyer>
                       <xsl:value-of select="buyer"/>
                   </buyer>
               </xsl:if>
           </xsl:for-each-group>
       </xsl:for-each-group>
<xsl:text>&#x0A;</xsl:text> <xsl:comment>multiple product buyers by buyer</xsl:comment>
       <xsl:text>&#x0A;</xsl:text>
       <xsl:for-each-group select="product" group-by="buyer">
<xsl:if test="count($current/product[buyer=current-group()/buyer]) &gt; 1">
               <buyer>
                   <xsl:value-of select="buyer"/>
               </buyer>
               <xsl:variable name="parentGroupBuyer" select="buyer"/>
<xsl:for-each-group select="$current/product" group-by="name">
                   <xsl:if test="buyer=$parentGroupBuyer">
                       <name>
                           <xsl:value-of select="name"/>
                       </name>
                   </xsl:if>
               </xsl:for-each-group>
           </xsl:if>
       </xsl:for-each-group>
   </xsl:template>
</xsl:stylesheet>


James A. Robinson wrote:

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>


--+------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--+--





<Prev in Thread] Current Thread [Next in Thread>