xsl-list
[Top] [All Lists]

Re: [xsl] XSLT repetition constructs comparison

2021-01-14 03:19:37
I would personally only use xsl:iterate where you need something that 
xsl:for-each can't do, such as early exit, or accumulation of parameter values. 
But an xsl:iterate with no parameters, no xsl:break, no xsl:on-completion is 
equivalent to xsl:for-each so there's no intrinsic reason to prefer one over 
the other. There may be implementation differences but that's 
processor-specific.

If you need some of the features of xsl:iterate and also want sorting, then I 
would normally use the sort() function:

<xsl:iterate select="sort(student, (), function($s){$s/(fName, lName))">...

or if that's not possible (e.g because you need a descending sort), then sort 
first (into a variable) using xsl:perform-sort.

Michael Kay
Saxonica

On 14 Jan 2021, at 09:05, Mukul Gandhi mukulg(_at_)softwarebytes(_dot_)org 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:

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 
<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 
<http://www.w3.org/1999/XSL/Transform>" 
                                               
xmlns:xs="http://www.w3.org/2001/XMLSchema <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 
<http://www.w3.org/1999/XSL/Transform>" 
                                               
xmlns:xs="http://www.w3.org/2001/XMLSchema <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
XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/293509> (by 
email <>)
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--
<Prev in Thread] Current Thread [Next in Thread>