Re: [xsl] XSLT 1.0: How to spit out unique values at *second* level of grouping

Subject: Re: [xsl] XSLT 1.0: How to spit out unique values at *second* level of grouping
From: "Mukul Gandhi" <gandhi.mukul@xxxxxxxxx>
Date: Tue, 24 Oct 2006 23:56:50 +0530
Using node-set extension function this is easy to solve. Below is the
modified stylesheet (tested with IE 7):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                      xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                      version="1.0">

<xsl:output method="html"/>


<xsl:key name="food" match="food" use="food_id"/> <xsl:key name="foodType" match="food_type" use="food_type_id"/>

<xsl:template match="/">
  <html>
    <body>
      <p>
        <h3>Example</h3>
        <p>
         <b>Show a unique list of Breakfast Items that belong to food
types "Waffles" and "Combos".</b>
        </p>
        <!-- SHOW HEADER : Waffles = 1, Combos = 4. -->
        <xsl:for-each select="//food_type[count(. |
key('foodType',food_type_id)[1]) = 1]">
          <xsl:variable name="foodType" select="food_type_id"/>
          <xsl:if test="$foodType = 1 or $foodType=4">
            <u>
             <xsl:value-of select="food_type_id"/>)<xsl:text>
</xsl:text><xsl:value-of select="food_type_name"/>
            </u>
            <xsl:text> </xsl:text>
          </xsl:if>
        </xsl:for-each>
        <br></br>
        <xsl:variable name="rtf">
          <xsl:for-each select="//food_type[food_type_id=1 or
food_type_id=4]">
            <xsl:copy-of select="//food[food_id = current()/food_id]" />
          </xsl:for-each>
        </xsl:variable>
        <xsl:for-each select="msxsl:node-set($rtf)/food[count(. |
key('food', food_id)[1])=1]">
          <li><xsl:value-of select="name"/></li>
        </xsl:for-each>
       </p>
     </body>
  </html>
</xsl:template>

</xsl:stylesheet>


On 10/24/06, Henesy, Susan <Susan.Henesy@xxxxxxxxx> wrote:
Dear List,

Thank you for encouraging me to re-post my question.  I'm glad there was
just a strange digest error that ate my post!!

Based on the XML file I have, I want to select two Food_Types, and spit
out a distinct list of Foods that belong to the two Food_Type_Ids.  I
need to prove that multiple FOOD_IDs can belong to multiple FOOD_TYPEs -
and that I can spit out those FOOD_IDs uniquely for the FOOD_TYPE_IDs I
choose.

This seems like it would be simple, but it is proving to be beyond me.
You will understand the dilemma when you see how the two node groups are
structured - similar to data I am working with from a database here at
the office.

Immediately below is my XML file - and below that, XSL code that I am
working on. I thought that if I used a "for-each" loop for each FOOD
TYPE and then nested another "for-each" loop within that one -- which
would use KEYS and the COUNT[] method to return only unique FOODS --
that that would work, but it doesn't.

I tried to use the "generate-id" idea but that didn't work, either.

The best I can guess is that since my first "for-each" loop is looping
through each FOOD_ID found in FOOD_TYPE (which has the duplicate  info)
...generate_id didn't work ... because it just created a unique id for
something that repeated.

As for the count[] method not working in the nested "for-each" loop ...
I am stumped ... I must not understand how those nodes find each other.

Basically, if I choose FOOD_TYPE where the food_type_id = 1 or
food_type_id = 4, I do *NOT* want to see "Belgian Waffles" repeat itself
just because it is in those two groups.  However, the output I get, no
matter HOW HARD I TRY, is always:

*******************************************************************
Show a unique list of Breakfast Items that belong to food types
"Waffles" and "Combos".

1) WAFFLES 4) COMBO BREAKFASTS

1) Belgian Waffles <-- Belgian waffles appears TWICE!!!!
1) Belgian Waffles <-- Belgian waffles appears TWICE!!!!
2) Strawberry Belgian Waffles
3) Berry-Berry Belgian Waffles
5) Homestyle Breakfast
*******************************************************************

Below are my XML and XSL files.  Thank you in advance for any help that
anyone can give me!!

---------------------------------------------------------------
FOOD.XML
---------------------------------------------------------------
<?xml version="1.0" encoding="ISO-8859-1"?>
<breakfast_menu>
       <food>
   <food_id>1</food_id>
               <name>Belgian Waffles</name>
               <price>$5.95</price>
               <description>two of our famous Belgian Waffles with
plenty of real maple syrup</description>
               <calories>650</calories>
       </food>
       <food>
   <food_id>2</food_id>
               <name>Strawberry Belgian Waffles</name>
               <price>$7.95</price>
               <description>light Belgian waffles covered with
strawberries and whipped cream</description>
               <calories>900</calories>
       </food>
       <food>
   <food_id>3</food_id>
               <name>Berry-Berry Belgian Waffles</name>
               <price>$8.95</price>
               <description>light Belgian waffles covered with an
assortment of fresh berries and whipped cream</description>
               <calories>900</calories>
       </food>
       <food>
   <food_id>4</food_id>
               <name>French Toast</name>
               <price>$4.50</price>
               <description>thick slices made from our homemade
sourdough bread</description>
               <calories>600</calories>
       </food>
       <food>
   <food_id>5</food_id>
               <name>Homestyle Breakfast</name>
               <price>$6.95</price>
               <description>two eggs, bacon or sausage, toast, and our
ever-popular hash browns</description>
               <calories>950</calories>
       </food>

 <!-- Food Type 1: WAFFLES -->
 <food_type>
   <food_type_id>1</food_type_id>
   <food_type_name>WAFFLES</food_type_name>
   <food_id>1</food_id>
 </food_type>
 <food_type>
   <food_type_id>1</food_type_id>
   <food_type_name>WAFFLES</food_type_name>
   <food_id>2</food_id>
 </food_type>
 <food_type>
   <food_type_id>1</food_type_id>
   <food_type_name>WAFFLES</food_type_name>
   <food_id>3</food_id>
 </food_type>
 <!-- Food Type 2: FRENCH TOAST -->
 <food_type>
   <food_type_id>2</food_type_id>
   <food_type_name>FRENCH TOAST</food_type_name>
   <food_id>4</food_id>
 </food_type>
 <!-- Food Type 3: TRADITIONAL BREAKFASTS -->
 <food_type>
   <food_type_id>3</food_type_id>
   <food_type_name>TRADITIONAL BREAKFASTS</food_type_name>
   <food_id>5</food_id>
 </food_type>
 <!-- Food Type 4: COMBO BREAKFASTS -->
 <food_type>
   <food_type_id>4</food_type_id>
   <food_type_name>COMBO BREAKFASTS</food_type_name>
   <food_id>5</food_id>
 </food_type>
 <food_type>
   <food_type_id>4</food_type_id>
   <food_type_name>COMBO BREAKFASTS</food_type_name>
   <food_id>1</food_id>
 </food_type>

</breakfast_menu>

---------------------------------------------------------------
FOOD.XSL
---------------------------------------------------------------
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="1.0">

<xsl:output method="html"/>



 <xsl:key name="food" match="food" use="food_id"/>
 <xsl:key name="foodType" match="food_type" use="food_type_id"/>



 <xsl:template match="/">
   <html>
     <body>

       <p>
         <h3>Example</h3>
       <p>

           <b>Show a unique list of Breakfast Items that belong to food
types "Waffles" and "Combos".</b>

</p>

<!-- SHOW HEADER : Waffles = 1, Combos = 4. -->

         <xsl:for-each select="//food_type[count(. |
key('foodType',food_type_id)[1]) = 1]">

            <xsl:variable name="foodType" select="food_type_id"/>
           <xsl:if test="$foodType = 1 or $foodType=4">

             <u>
               <xsl:value-of select="food_type_id"/>)<xsl:text>
</xsl:text><xsl:value-of select="food_type_name"/>
             </u>

             <xsl:text> </xsl:text>
           </xsl:if>



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




<!--||************************************************************** || TROUBLE AREA - CAN'T GET DISTINCT FOOD IDS!!!!!

||*************************************************************-->

               <xsl:for-each select="//food_type[food_type_id=1 or
food_type_id=4]">
                       <xsl:sort select="food_id"/>
                       <xsl:variable name="foodType"
select="food_type_id"/>
                       <xsl:variable name="foodID" select="food_id"/>

                      <xsl:for-each select="//food[count(. |
key('food', $foodID)[1])=1]">
                             <li><xsl:value-of select="name"/></li>
                       </xsl:for-each>

</xsl:for-each>



<!--||**************************************************************-->


</p> </body> </html> </xsl:template> </xsl:stylesheet>

------------------------------------------------------------------------
---
END OF POST
------------------------------------------------------------------------


--
Regards,
Mukul Gandhi

Current Thread