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

Re: XSLT repetition constructs comparison

Subject: Re: XSLT repetition constructs comparison
From: "Martin Honnen martin.honnen@xxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Thu, 14 Jan 2021 10:28:38 -0000
Re:  XSLT repetition constructs comparison
Am 14.01.2021 um 10:05 schrieb Mukul Gandhi mukulg@xxxxxxxxxxxxxxxxx:
Hi all,
 B  B I'm comparing the functionality of, XSLTB 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>
 B  B <student>
 B  B  B  <rollNo>1</rollNo>
 B  B  B  <fName>Sharon</fName>
 B  B  B  <lName>Adler</lName>
 B  B </student>
 B  B <student>
 B  B  B  <rollNo>2</rollNo>
 B  B  B  <fName>Anders</fName>
 B  B  B  <lName>Berglund</lName>
 B  B </student>
 B  B <student>
 B  B  B  <rollNo>3</rollNo>
 B  B  B  <fName>Norm</fName>
 B  B  B  <lName>Walsh</lName>
 B  B </student>
 B  B <student>
 B  B  B  <rollNo>4</rollNo>
 B  B  B  <fName>Michael</fName>
 B  B  B  <lName>Sperberg-McQueen</lName>
 B  B </student>
 B  B <student>
 B  B  B  <rollNo>5</rollNo>
 B  B  B  <fName>Florent</fName>
 B  B  B  <lName>Georges</lName>
 B  B </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
<http://www.w3.org/1999/XSL/Transform>">

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

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

</xsl:stylesheet>

(2)B 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
<http://www.w3.org/1999/XSL/Transform>"

 B xmlns:xs="http://www.w3.org/2001/XMLSchema
<http://www.w3.org/2001/XMLSchema>"

B exclude-result-prefixes="xs">

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

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

</xsl:stylesheet>

(3)B 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
<http://www.w3.org/1999/XSL/Transform>"

 B xmlns:xs="http://www.w3.org/2001/XMLSchema
<http://www.w3.org/2001/XMLSchema>"

B exclude-result-prefixes="xs">

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

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

I agree with Michael that you can always use fn:sort for the select expression of xsl:iterate in XSLT 3 or at least, in Saxon 9.8 and 9.9 HE where the higher-order variant of fn:sort is not available, roll your own sort function with xsl:function and xsl:perform sort that you then call in the select attribute of xsl:iterate.


In general, for that use case, I don't see why xsl:iterate is better than xsl:for-each. I would probably use push style processing with xsl:apply-templates.

Last, for the use with the variable, don't forget that
`xsl:perform-sort` can be directly applied to result constructed by
nested XSLT so you could also use

             <xsl:perform-sort>
                  <xsl:sort select="td[2]"/>
                  <xsl:sort select="td[3]"/>
                  <xsl:iterate select="student">
                  ...
                  </xsl:iterate>
             </xsl:perform-sort>

perhaps although I guess that will not work with the total column you
want to treat differently.

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.