esgg
esgg

Reputation: 45

Using <xsl:apply-templates> and <xsl:sort>

How do I use the element to sort the elements within the table I am outputting? I would like to use the elements within the element. I tried placing the element in my xsl document but it doesn't sort the element.

Here is my xml:

<presidents xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="president.xsd" date="2014-09-24" >
    <president>
        <number>1</number>
        <name>George Washington</name>
         <birthday>1732-02-22</birthday>
        <took_office>1789-04-30</took_office>
        <left_office>1797-03-04</left_office>
        <party>no party</party>
        <term>
            <term_number>1</term_number>
            <vice_president>John Adams</vice_president> 
        </term>
        <term>
            <term_number>2</term_number>
            <vice_president>John Adams</vice_president>
        </term>
    </president>

    <president>
        <number>2</number>
        <name>John Adams</name>
         <birthday>1735-10-30</birthday>
        <took_office>1797-03-04</took_office>
        <left_office>1801-03-04</left_office>
        <party>Federalist</party>
        <term>
            <term_number>3</term_number>
            <vice_president>Thomas Jefferson</vice_president>
        </term>
    </president>
</presidents>

And here is my .xsl:

<xsl:template match="/">
    <html>
    <head>
    <link rel="stylesheet" type="text/css" href="president_table.css"/>
    <title>Table of Us Presidents</title>
    </head>
    <body>
        <h1>Table of Us Presidents</h1>
        <table>
            <tr>
                <th>Name</th>
                <th>Birthday</th>
                <th>Took Office</th>
                <th>Left Office</th>
                <th>Party</th>
                <th>Vice President</th>
            </tr>
            <xsl:apply-templates/>
        </table>
    </body>
    </html>
</xsl:template>

<xsl:template match="president">
<tr>
    <td><xsl:apply-templates select="name"/></td>
    <td><xsl:apply-templates select="birthday"/></td>
    <td><xsl:apply-templates select="took_office"/></td>
    <td><xsl:apply-templates select="left_office"/></td>
    <td>
    <xsl:apply-templates select="party">
        <xsl:sort select="party"/>
    </xsl:apply-templates>
    </td>
    <td>
    <xsl:for-each select="term">
        <xsl:number value="position()" format="1. " />
        <xsl:value-of select="vice_president" /><br />
    </xsl:for-each>
    </td>
</tr>
</xsl:template>

Upvotes: 4

Views: 3343

Answers (1)

Mathias M&#252;ller
Mathias M&#252;ller

Reputation: 22617

I would like to output the data so it is sorted according to the element in an alphabetical order. So all of the 'Democratic' presidents would appear first.

Then, let us test with an example where the natural order of elements would not suggest that a Democratic president comes first in the output:

XML Input

<presidents date="2014-09-24" >
    <president>
        <number>1</number>
        <name>George Washington</name>
         <birthday>1732-02-22</birthday>
        <took_office>1789-04-30</took_office>
        <left_office>1797-03-04</left_office>
        <party>Federalist</party>
        <term>
            <term_number>1</term_number>
            <vice_president>John Adams</vice_president> 
        </term>
        <term>
            <term_number>2</term_number>
            <vice_president>John Adams</vice_president>
        </term>
    </president>

    <president>
        <number>2</number>
        <name>John Adams</name>
         <birthday>1735-10-30</birthday>
        <took_office>1797-03-04</took_office>
        <left_office>1801-03-04</left_office>
        <party>Democratic</party>
        <term>
            <term_number>3</term_number>
            <vice_president>Thomas Jefferson</vice_president>
        </term>
    </president>
</presidents>

Then, on to sorting your data. Currently, you are applying xsl:sort in the context of a template matching president, like this:

<xsl:apply-templates select="party">
  <xsl:sort select="party"/>
</xsl:apply-templates>

But the unit you'd like to sort is not party, but president elements. It just that the sort condition is the textual content of the party element, which is a child element of president.

So, you have to apply sorting higher up in the XML hierarchy for the desired effect. You have to sort in the context of presidents, where templates are applied to president elements.

Stylesheet

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

    <xsl:template match="/presidents">
    <html>
    <head>
    <link rel="stylesheet" type="text/css" href="president_table.css"/>
    <title>Table of Us Presidents</title>
    </head>
    <body>
        <h1>Table of Us Presidents</h1>
        <table>
            <tr>
                <th>Name</th>
                <th>Birthday</th>
                <th>Took Office</th>
                <th>Left Office</th>
                <th>Party</th>
                <th>Vice President</th>
            </tr>
            <xsl:apply-templates select="president">
                <xsl:sort select="party"/>
            </xsl:apply-templates>
        </table>
    </body>
    </html>
</xsl:template>

<xsl:template match="president">
<tr>
    <td><xsl:apply-templates select="name"/></td>
    <td><xsl:apply-templates select="birthday"/></td>
    <td><xsl:apply-templates select="took_office"/></td>
    <td><xsl:apply-templates select="left_office"/></td>
    <td>
    <xsl:apply-templates select="party"/>
    </td>
    <td>
    <xsl:for-each select="term">
        <xsl:number value="position()" format="1. " />
        <xsl:value-of select="vice_president" /><br />
    </xsl:for-each>
    </td>
</tr>
</xsl:template>

</xsl:transform>

HTML Output

As you can see, the president with the Democratic party now comes first.

<!DOCTYPE html
  PUBLIC "XSLT-compat">
<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <link rel="stylesheet" type="text/css" href="president_table.css">
      <title>Table of Us Presidents</title>
   </head>
   <body>
      <h1>Table of Us Presidents</h1>
      <table>
         <tr>
            <th>Name</th>
            <th>Birthday</th>
            <th>Took Office</th>
            <th>Left Office</th>
            <th>Party</th>
            <th>Vice President</th>
         </tr>
         <tr>
            <td>John Adams</td>
            <td>1735-10-30</td>
            <td>1797-03-04</td>
            <td>1801-03-04</td>
            <td>Democratic</td>
            <td>1. Thomas Jefferson<br></td>
         </tr>
         <tr>
            <td>George Washington</td>
            <td>1732-02-22</td>
            <td>1789-04-30</td>
            <td>1797-03-04</td>
            <td>Federalist</td>
            <td>1. John Adams<br>2. John Adams<br></td>
         </tr>
      </table>
   </body>
</html>

Upvotes: 3

Related Questions