1
votes

I find XSLT 1.0 Meunchian grouping very complex. If you can guide me on the following using xsl:key, that would be great. The actual XML is huge, and I've only used a partial portion of it to indicate the structure.

If you need any additional clarification please let me know.

My requirement is to have the following sample XML displayed in a tabular format, grouped first by the itemtype name and then by customer name. Please note that the node Details has always only one node Detail

Desired Output

ItemType Customer Name Price

Book John Smith 7

DVD John Smith 45

DVD Jane Doe 44

INPUT:

<Item> 
   <SomeRandomField>abc</SomeRandomField>  
  <Details>
    <Detail>
        <Price>7.00</Price
        <CustomerName>John Smith</CustomerName>
     </Detail>
   </Details>
   <ItemType>   
      <Key>1</Key>
      <Name>Book</Name>
   </ItemType>
</Item>

<Item> 
   <SomeRandomField>mno</SomeRandomField>  
  <Details>
    <Detail>
        <Price>45.00</Price
        <CustomerName>John Smith</CustomerName>
     </Detail>
   </Details>
   <ItemType>   
      <Key>2</Key>
      <Name>DVD</Name>
   </ItemType>
</Item> 
<Item> 
   <SomeRandomField>xyz</SomeRandomField>  
  <Details>
    <Detail>
        <Price>44.00</Price
        <CustomerName>Jane Doe</CustomerName>
     </Detail>
   </Details>
   <ItemType>   
      <Key>2</Key>
      <Name>DVD</Name>
   </ItemType>
</Item> 
3
I think you mean sorted, not grouped. You have described a sorting criteria not a grouping criteria. Therefore you do not need Muenchian grouping. - Sean B. Durkin
Did you want html output? or text output? - Sean B. Durkin

3 Answers

0
votes

You can use following xslt to transform your xml in order to get desired output, And I have modified your xml by adding <Items> root node.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="html" indent="yes"/>

  <xsl:template match="Items">
    <table>
      <tr>
        <td>
          <b>ItemType</b>
        </td>
        <td>
          <b>Customer Name</b>
        </td>
        <td>
          <b>Price</b>
        </td>
      </tr>
      <xsl:for-each select="Item">
       <xsl:sort select="ItemType/Name" order="ascending"/>
        <tr>
          <td>
            <xsl:value-of select="ItemType/Name"/>
          </td>
          <td>
            <xsl:value-of select="Details/Detail/CustomerName"/>
          </td>
          <td>
            <xsl:value-of select="Details/Detail/Price"/>
          </td>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>
0
votes

I believe the following achieves the desired result. The key is used to group by ItemType, you can then include a sort if needed to group the customer names.

XML

<?xml version="1.0" encoding="UTF-8"?>
<Items>
    <Item> 
        <SomeRandomField>abc</SomeRandomField>  
        <Details>
            <Detail>
                <Price>7.00</Price>
                <CustomerName>John Smith</CustomerName>
            </Detail>
        </Details>
        <ItemType>   
            <Key>1</Key>
            <Name>Book</Name>
        </ItemType>
    </Item>

    <Item> 
        <SomeRandomField>mno</SomeRandomField>  
        <Details>
            <Detail>
                <Price>45.00</Price>
                <CustomerName>John Smith</CustomerName>
            </Detail>
        </Details>
        <ItemType>   
            <Key>2</Key>
            <Name>DVD</Name>
        </ItemType>
    </Item> 
    <Item> 
        <SomeRandomField>xyz</SomeRandomField>  
        <Details>
            <Detail>
                <Price>44.00</Price>
                <CustomerName>Jane Doe</CustomerName>
            </Detail>
        </Details>
        <ItemType>   
            <Key>2</Key>
            <Name>DVD</Name>
        </ItemType>
    </Item> 
</Items>

XSL

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:key name="itemname" match="/Items/Item/ItemType" use="Name"/>
    <xsl:key name="custname" match="/Items/Item/Details/Detail" use="CustomerName"/>
    <xsl:output method="html" indent="yes"/>
    <xsl:template match="/">
        <html>
            <body>
                <xsl:for-each select="/Items/Item/ItemType
                    [generate-id(.) = generate-id(key('itemname', Name))]
                    ">
                    <xsl:variable name="local_item" select="Name"/>
                    <xsl:for-each select="/Items/Item">
                        <xsl:if test="ItemType/Name = $local_item">
                            <p><xsl:value-of select="$local_item"/>-
                                <xsl:value-of select="Details/Detail/CustomerName"/>-
                                <xsl:value-of select="Details/Detail/Price"/></p>
                        </xsl:if>
                    </xsl:for-each>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

HTML

<html>
   <body>
      <p>Book-John Smith-7.00</p>
      <p>DVD-John Smith-45.00</p>
      <p>DVD-Jane Doe-44.00</p>
   </body>
</html>
0
votes

In addition to my answer above, I believe for this example a simple sort will also suffice.

<?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:key name="itemname" match="/Items/Item/ItemType" use="Name"/>
        <xsl:key name="custname" match="/Items/Item/Details/Detail" use="CustomerName"/>
        <xsl:output method="html" indent="yes"/>
        <xsl:template match="/">
            <html>
                <body>
                    <xsl:for-each select="/Items/Item">
                        <xsl:sort select="ItemType/Name"/>
                        <xsl:sort select="Details/Detail/CustomerName"/>
                        <xsl:value-of select="."/><br/>
                    </xsl:for-each>
                </body>
            </html>
        </xsl:template>
    </xsl:stylesheet>