Dynamicly sorting with XSLT ......

Discussions

XML & Web services: Dynamicly sorting with XSLT ......

  1. Dynamicly sorting with XSLT ...... (5 messages)

    Given the next xml and xsl file:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <friends>
         <friend>
            <name>John</name>
            <age>24</age>
         </friend>
         ......
    </friends>

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform">
    <xsl:param name="sortby" select="name"/>
    <xsl:template match="/">
        <table border="1" width="761">
          <tr bgcolor="#9acd32">
            <th align="left">Name</th>
            <th align="left">Age</th>
          </tr>
          <xsl:for-each select="friends/friend">
          <xsl:sort select="$sortby"/>
          <tr>
            <td><xsl:value-of select="name"/></td>
            <td><xsl:value-of select="age"/></td>
          </tr>
          </xsl:for-each>
        </table>
    </xsl:template>
    </xsl:stylesheet>
    My idea is to sort the records dynamicly according to the parameter given by the client.
    Namely it should be sorted by 'name' when the 'name' parameter is given or it should be sorted by 'age' when 'age' paramter is given.
    So I define a global param in the .xsl file <xsl:param name="sortby" select="name"> and called it just see above .xsl file . But it didn't work...
    I'm confused with it. What's wrong with it? How to implement my idea for dynamicly sort with XSLT?
    Please help !!!

    Thanks in advance!

    Threaded Messages (5)

  2. Dynamicly sorting with XSLT ......[ Go to top ]

    1. How are you passing the parameter into the XSLT file?

    If you are using client-side processing, there is no standard way (that I know of) to pass a parameter to you transform.

    If you are using JAXP for your transform, its easy:

    transformer.setParameter("sortby", "[field]");

    2. You can't specify the variable value itself as you XPath, as you do here:

    <xsl:sort select="$sortby"/>

    The select attribute of the xsl:sort instruction needs to be an XPath. The above statement will evaluate to the string literal for the $sortby variable ("name"), and will therefore be the same for every element.

    What you want are conditional statements like the following:

    <xsl:choose>
      <xsl:when test="$sortby = 'name'">
        <xsl:for-each select="friends/friend">
          <xsl:sort select="name"/>
          <tr>
            <td><xsl:value-of select="name"/></td>
            <td><xsl:value-of select="age"/></td>
          </tr>
        </xsl:for-each>
      </xsl:when>
      <xsl:when test="$sortby = 'age'">
        <xsl:for-each select="friends/friend">
          <xsl:sort select="age"/>
          <tr>
            <td><xsl:value-of select="name"/></td>
            <td><xsl:value-of select="age"/></td>
          </tr>
        </xsl:for-each>
      </xsl:when>
      <xsl:otherwise>
        <xsl:for-each select="friends/friend">
          <tr>
            <td><xsl:value-of select="name"/></td>
            <td><xsl:value-of select="age"/></td>
          </tr>
        </xsl:for-each>
      </xsl:otherwise>
    </xsl:choose>


    An even better way to do this is to use a different template to print out friend data:


    ...
    <xsl:choose>
      <xsl:when test="$sortby = 'name'">
        <xsl:apply-templates select="friends/friend">
          <xsl:sort select="name"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:when test="$sortby = 'age'">
        <xsl:apply-templates select="friends/friend">
          <xsl:sort select="age"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:apply-templates select="friends/friend"/>
      </xsl:otherwise>
    </xsl:choose>
    ...

    <xsl:template match="friends/friend">
      <tr>
        <td><xsl:value-of select="name"/></td>
        <td><xsl:value-of select="age"/></td>
      </tr>
    </xsl:template>
  3. Dynamicly sorting with XSLT ......[ Go to top ]

    Thanks for your reply Paul.
    I use JAXP to transform the file.
    What I think is it will display the records and sort by element 'name' for above xml file and xsl file I give. But it didn't sort by 'name'.
    I think when transforming the xml file,parameter 'sortby' will be replaced with 'name',so code <xsl:sort select="$sortby"/> should be replaced with <xsl:sort select="name"/>. But the result is not what I have thought. It didn't sort by anything. Maybe It's wrong to use <xsl:sort> like that.
  4. Dynamicly sorting with XSLT ......[ Go to top ]

    I did try what Paul Suggested with JDK1.4 and a simple standalone client (as I am also interested in the solution). It works (meaning sort by name or age as per the parameter). All I did is modified the XSL as suggested by Paul and it worked. Please let me know if you need more info.

    However there was a weird problem when it sorted by age if I have ages like 24,22,23,8, I got the sorting order as 22,23,24,8. When I replaced 8 with 21, I got the order as 21,22,23,24. Sorting by name always worked.
  5. Dynamicly sorting with XSLT ......[ Go to top ]

    XSLT always sorts items as text. Since "8" after before "23" in alphabetical order, that is why you are getting the sort results you have.

    I get around this problem by adding a large number to each numerical value. For example, with ages, sort by:

    "age + 1000"

    The sort keys for 24, 22, 23, 8 will be 1024, 1022, 1023, 1008, so that the numeric and alphabet ordering will be the same.
  6. Dynamicly sorting with XSLT ......[ Go to top ]

    XSLT will sort item as text default.You can sort item by specifing its data type.
    <xsl:sort select="age" data-type="number"/>
    So it will sort by the number of the data.