Home > other >  Is it possible to group entries using XSLT 1.0?
Is it possible to group entries using XSLT 1.0?

Time:09-16

I'm working on a way to make XML pick lists more human-readable. The data looks something like this:

<data>
  <entry>
    <customer>Acme</customer>
    <sku>123123</sku>
    <desc>Name Of First Product</desc>
  </entry>
  <entry>
    <customer>GeneriCo</customer>
    <sku>456456</sku>
    <desc>Name Of Second Product</desc>
  </entry>
  <entry>
    <customer>Acme</customer>
    <sku>789789</sku>
    <desc>Name Of Third Product</desc>
  </entry>
</data>

What I'm trying to do is filter the data such that all products ordered by each customer are grouped together (the customers don't necessarily need to be sorted). Something like this:

Acme:
    123123 Name of First Product
    789789 Name of Third Product

GeneriCo:
    456456 Name of Second Product

Questions I already looked at:

  • XSLT filtering nodes on conditional logic doesn't help because I don't know in advance what the dataset will be. The database has thousands of active customers and it's not reasonable to hardcode thousands of if statements.
  • Handling array like variable with XSLT straight up does not work. I copy-pasted the code exactly as written and when viewing the page (using Google Chrome, file hosted on a local WAMPserver instance) nothing was printed out.

Upgrading to XSLT 2.0 or 3.0 is not an option because of the limitations of our work environment. If there is no way to solve this problem within XSLT 1.0, I'll have to completely throw out this entire line of thinking and start working on a pitch for a PHP dashboard or something.

CodePudding user response:

Regardless of this post's comment, we can all use another Muenchian example!, mainly because the context where the grouping occurs is different, so this is one tailored to OP, based on this post:https://stackoverflow.com/a/2334224/1690217

  1. Define the key resolver, in this case the customer element on an entry

    <xsl:key name="customers" match="entry" use="customer" />
    
  2. Select the unique grouped values

    <xsl:apply-templates select="data/entry[generate-id()=generate-id(key('customers',customer)[1])]"/>
    
  3. Define your template for each element, in this case the entry

     <xsl:template match="entry">
         <h1>
             <xsl:value-of select="customer"/>
         </h1>
         <table id="{customer}">
             <tr class="heading">
                 <th scope="col">SKU</th>
                 <th scope="col">Description</th>
             </tr>
             <xsl:for-each select="key('customers', customer)">
                 <tr>
                     <td>
                         <xsl:value-of select="sku"/>
                     </td>
                     <td>
                         <xsl:value-of select="desc"/>
                     </td>
                 </tr>
             </xsl:for-each>
         </table>
     </xsl:template>
    

See it in action: http://xsltransform.net/nc4P6y1/3

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

    <xsl:key name="customers" match="entry" use="customer" />
    
    <xsl:template match="entry">
        <h1>
            <xsl:value-of select="customer"/>
        </h1>
        <table id="{customer}">
            <tr class="heading">
                <th scope="col">SKU</th>
                <th scope="col">Description</th>
            </tr>
            <xsl:for-each select="key('customers', customer)">
                <tr>
                    <td>
                        <xsl:value-of select="sku"/>
                    </td>
                    <td>
                        <xsl:value-of select="desc"/>
                    </td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>
    
    <xsl:template match="/">
      <html>
        <head>
          <title>Group By Customer</title>
        </head>
        <body>
            <xsl:apply-templates select="data/entry[generate-id()=generate-id(key('customers',customer)[1])]"/>
        </body>
      </html>
    </xsl:template>
    
</xsl:transform>

<!DOCTYPE html
  PUBLIC "XSLT-compat">
<html>
   <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Group By Customer</title>
   </head>
   <body>
  <h1>Acme</h1>
  <table id="Acme">
     <tr class="heading">
        <th scope="col">SKU</th>
        <th scope="col">Description</th>
     </tr>
     <tr>
        <td>123123</td>
        <td>Name Of First Product</td>
     </tr>
     <tr>
        <td>789789</td>
        <td>Name Of Third Product</td>
     </tr>
  </table>
  <h1>GeneriCo</h1>
  <table id="GeneriCo">
     <tr class="heading">
        <th scope="col">SKU</th>
        <th scope="col">Description</th>
     </tr>
     <tr>
        <td>456456</td>
        <td>Name Of Second Product</td>
     </tr>
  </table>
   </body>
</html>

  • Related