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

XSLT repetition constructs comparison

Subject: XSLT repetition constructs comparison
From: "Mukul Gandhi mukulg@xxxxxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 14 Jan 2021 09:05:29 -0000
 XSLT repetition constructs comparison
Hi all,
   I'm comparing the functionality of, XSLT repetition constructs
xsl:for-each and xsl:iterate (versions 2.0 & 3.0). Below is my example use
case, and the corresponding XSLT solutions from my side,

XML input document:

<?xml version="1.0"?>
<students>
   <student>
      <rollNo>1</rollNo>
      <fName>Sharon</fName>
      <lName>Adler</lName>
   </student>
   <student>
      <rollNo>2</rollNo>
      <fName>Anders</fName>
      <lName>Berglund</lName>
   </student>
   <student>
      <rollNo>3</rollNo>
      <fName>Norm</fName>
      <lName>Walsh</lName>
   </student>
   <student>
      <rollNo>4</rollNo>
      <fName>Michael</fName>
      <lName>Sperberg-McQueen</lName>
   </student>
   <student>
      <rollNo>5</rollNo>
      <fName>Florent</fName>
      <lName>Georges</lName>
   </student>
</students>

I wish to transform, the above XML data into HTML, using XSLT. The
resulting HTML, needs to have a table containing rows representing each XML
input "student" element, and a total record count at the bottom of HTML
output.

Below are my various XSLT solutions,

(1) An XSLT 2.0 solution, with sorting (sorting by fName & lName):

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform">

   <xsl:output method="html" indent="yes"/>

   <xsl:template match="students">
      <html>
        <head>
           <title>Student list</title>
        </head>
        <body>
           <table>
              <tr>
                 <td><b>Roll No.</b></td>
                 <td><b>First name</b></td>
                 <td><b>Last name</b></td>
              </tr>
              <xsl:for-each select="student">
                 <xsl:sort select="fName"/>
                 <xsl:sort select="lName"/>
                 <tr>
                    <td align="center"><xsl:value-of select="rollNo"/>.</td>
                    <td><xsl:value-of select="fName"/></td>
                    <td><xsl:value-of select="lName"/></td>
                 </tr>
              </xsl:for-each>
              <tr>
        <td colspan="3">&#xa0;</td>
      </tr>
      <tr>
        <td colspan="2"><b>Total no of students</b> : </td>
        <td><xsl:value-of select="count(student)"/></td>
              </tr>
           </table>
        </body>
      </html>
   </xsl:template>

</xsl:stylesheet>

(2) An XSLT 3.0 solution, without sorting:

<?xml version="1.0"?>
<xsl:stylesheet version="3.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
                                               xmlns:xs="
http://www.w3.org/2001/XMLSchema"
                                               exclude-result-prefixes="xs">

   <xsl:output method="html" indent="yes"/>

   <xsl:template match="students">
      <html>
        <head>
           <title>Student list</title>
        </head>
        <body>
           <table>
              <tr>
                 <td><b>Roll No.</b></td>
                 <td><b>First name</b></td>
                 <td><b>Last name</b></td>
              </tr>
              <xsl:iterate select="student">
                 <xsl:param name="total" select="0" as="xs:integer"/>
                 <xsl:on-completion>
                    <tr>
                       <td colspan="3">&#xa0;</td>
                    </tr>
                    <tr>
                      <td colspan="2"><b>Total no of students</b> : </td>
                      <td><xsl:value-of select="$total"/></td>
                    </tr>
                 </xsl:on-completion>
                 <tr>
                    <td align="center"><xsl:value-of select="rollNo"/>.</td>
                    <td><xsl:value-of select="fName"/></td>
                    <td><xsl:value-of select="lName"/></td>
                 </tr>
                 <xsl:next-iteration>
                    <xsl:with-param name="total" select="$total + 1"/>
                 </xsl:next-iteration>
              </xsl:iterate>
           </table>
        </body>
      </html>
   </xsl:template>

</xsl:stylesheet>

(3) An XSLT 3.0 solution, with sorting:

<?xml version="1.0"?>
<xsl:stylesheet version="3.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform"
                                               xmlns:xs="
http://www.w3.org/2001/XMLSchema"
                                               exclude-result-prefixes="xs">

   <xsl:output method="html" indent="yes"/>

   <xsl:template match="students">
      <html>
        <head>
           <title>Student list</title>
        </head>
        <body>
           <table>
              <tr>
                 <td><b>Roll No.</b></td>
                 <td><b>First name</b></td>
                 <td><b>Last name</b></td>
              </tr>
              <xsl:variable name="result_1" as="element(tr)*">
                 <xsl:iterate select="student">
                    <xsl:param name="total" select="0" as="xs:integer"/>
                    <xsl:on-completion>
                       <tr>
                          <td colspan="3">&#xa0;</td>
                       </tr>
                       <tr>
                         <td colspan="2"><b>Total no of students</b> : </td>
                         <td><xsl:value-of select="$total"/></td>
                       </tr>
                    </xsl:on-completion>
                    <tr>
                       <td align="center"><xsl:value-of
select="rollNo"/>.</td>
                       <td><xsl:value-of select="fName"/></td>
                       <td><xsl:value-of select="lName"/></td>
                    </tr>
                    <xsl:next-iteration>
                       <xsl:with-param name="total" select="$total + 1"/>
                    </xsl:next-iteration>
                 </xsl:iterate>
              </xsl:variable>
              <xsl:perform-sort select="$result_1[position() le
(count($result_1)-2)]">
                 <xsl:sort select="td[2]"/>
                 <xsl:sort select="td[3]"/>
              </xsl:perform-sort>
              <xsl:copy-of select="$result_1[position() gt
(count($result_1)-2)]"/>
           </table>
        </body>
      </html>
   </xsl:template>

</xsl:stylesheet>

I haven't mentioned the solution, where we could use xsl:apply-templates
instead of xsl:for-each or xsl:iterate.

Firstly, I find xsl:iterate much more functionally rich (except that it
doesn't provide native sorting support) than xsl:for-each, if there's a
requirement of XSLT sequential looping. If there's no requirement for
sorting, then in XSLT 3.0 environment, I'd opt to use xsl:iterate. If
there's requirement for sorting, then in XSLT 3.0 environment, I might opt
to use xsl:for-each instead of xsl:iterate (does anybody differ?). When
using XSLT 3.0 xsl:iterate, with a requirement of sorting, can anyone
suggest a different (and possibly better as well) solution than (3) above?

Any thoughts, about performance aspects of various XSLT solutions relevant
to this thread, would also be useful to know.



-- 
Regards,
Mukul Gandhi

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-2013 All Rights Reserved.