[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

[xsl] Meunch away on this


Subject: [xsl] Meunch away on this
From: "Thomas Stone" <stonethomasjames@xxxxxxxxx>
Date: Thu, 21 Dec 2006 22:15:39 -0800

   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
Keywords