[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Meunch away on this

Subject: Meunch away on this
From: "Thomas Stone" <stonethomasjames@xxxxxxxxx>
Date: Thu, 21 Dec 2006 22:15:39 -0800
meunch
   I am looking for feedback on my solution to a very old topic... sorting and
grouping in XSLT version 1.0.  I am using Mozilla Firefox version 1.0.7 to
read an XML document referencing an XSLT stylesheet to produce a simple HTML
table.  The desired data is, oddly enough, the element names of the XML
document.

   Any source XML document will do.  It will need to have a processor
directive pointing to the below sample stylesheet.

<?xml-stylesheet type="text/xsl" href="Display_Entities.xml"?>


   To list all the elements of that document, the stylesheet would be as
follows:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <html><head><title>Tags List</title></head>
      <body><table border="1">
          <tr><th>Tag Name</th></tr>

          <xsl:apply-templates select="//*" mode="all">
            <xsl:sort select="name()"/>
          </xsl:apply-templates>
      </table></body>
    </html>
  </xsl:template>


  <xsl:template match="*" mode="all">
    <tr>
      <td><xsl:value-of select="name()"/></td>
    </tr>
  </xsl:template>
</xsl:stylesheet>


   This list is sorted and shows all the data I need, but the question that
I've seen posts on back to 1999 is how to make this a sorted unique list.  My
hat's still off to Steve Meunch for the key value solution.  I don't even want
to try to figure out a faster way to uniquely sort a list.  I was only
interested in finding a less, if you'll pardon me, convoluted way to do it so
it could be implemented without a long explanation.  Though, again, thanks to
Jeni for her site.

   Here is what I came up with that seems pretty straight forward.  Using the
Position() function within the sorted list, only output the first position.
This will always get the first entry in alphabetical order.  Select sorted all
elements that are not the same name as the first and recurse to the same
procedure, thus displaying only the second entry in alphabetical order.
Append each entry to a delimited string array and use a Contains() test to
eliminate duplicates from the next selection list.

          <xsl:apply-templates select="//*" mode="unique">
            <xsl:sort select="name()"/>
            <xsl:with-param name="code_list" select="';'"/>
          </xsl:apply-templates>


  <xsl:template match="*" mode="unique">
    <xsl:param name="code_list"/>

    <xsl:if test="position()=1">

      <xsl:variable name="ent_name" select="name()"/>

      <tr>
        <td><xsl:value-of select="$ent_name"/></td>
      </tr>

      <xsl:variable name="new_list" select="concat($code_list,
concat($ent_name, ';'))"/>

      <xsl:apply-templates select="//*[contains($new_list, concat(';',
concat(name(), ';')))=false()]" mode="unique">
        <xsl:sort select="name()"/>
        <xsl:with-param name="code_list" select="$new_list"/>
      </xsl:apply-templates>
    </xsl:if>
  </xsl:template>



   This gives me a unique sorted list of all entities in the document.  I
prefer to have them enumerated.

          <xsl:apply-templates select="//*" mode="summary">
            <xsl:sort select="name()"/>
            <xsl:with-param name="code_list" select="';'"/>
            <xsl:with-param name="seq_counter" select="1"/>
          </xsl:apply-templates>


  <xsl:template match="*" mode="summary">
    <xsl:param name="code_list"/>
    <xsl:param name="seq_counter"/>

    <xsl:if test="position()=1">

      <xsl:variable name="ent_name" select="name()"/>

      <tr>
        <td><xsl:value-of select="$seq_counter"/></td>
          <td><xsl:value-of select="$ent_name"/></td>
      </tr>

      <xsl:variable name="new_list" select="concat($code_list,
concat($ent_name, ';'))"/>

      <xsl:apply-templates select="//*[contains($new_list, concat(';',
concat(name(), ';')))=false()]" mode="summary">
        <xsl:sort select="name()"/>
        <xsl:with-param name="code_list" select="$new_list"/>
        <xsl:with-param name="seq_counter" select="$seq_counter+1"/>
      </xsl:apply-templates>
    </xsl:if>
  </xsl:template>



   From this structure, I can group by placing a correlated sub-query
<apply-templates> where the <tr> output is.  The uniqueness test can be
applied just as directly to character data or attributes.


--
___________________________________________________
Search for products and services at:
http://search.mail.com

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2007 All Rights Reserved.