Re: [xsl] Emulating XPATH2 range in XSLT 1.0

Subject: Re: [xsl] Emulating XPATH2 range in XSLT 1.0
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Wed, 29 Jul 2009 06:24:49 -0700
You are discovering the "iter" function/template of FXSL 1.x, which
has been available for 7+ years :)  :

Here is the file generateFromTo.xsl from Fxsl 1.x :

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:ext="http://exslt.org/common";
  xmlns:f="http://fxsl.sf.net/";
  xmlns:myIncrement="f:myIncrement"
  exclude-result-prefixes="ext f myIncrement"
 >

 <xsl:import href="iter.xsl"/>
 <!-- To be applied on any xml file -->

 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/">
    <xsl:call-template name="generateBatch">
      <xsl:with-param name="pFrom" select="3"/>
      <xsl:with-param name="pTo" select="300"/>
    </xsl:call-template>
  </xsl:template>

  <myIncrement:myIncrement/>

  <xsl:template name="generateBatch">
    <xsl:param name="pFrom"/>
    <xsl:param name="pTo"/>

    <xsl:variable name="vFunIncr"
         select="document('')/*/myIncrement:*[1]"/>

    <xsl:variable name="vResult">
      <xsl:call-template name="scanIter">
        <xsl:with-param name="arg1" select="$pTo - $pFrom + 1"/>
        <xsl:with-param name="arg2" select="$vFunIncr"/>
        <xsl:with-param name="arg3" select="$pFrom - 1"/>
        <xsl:with-param name="arg4" select="'obj'"/>
      </xsl:call-template>
    </xsl:variable>

    <xsl:copy-of select="ext:node-set($vResult)/*[position() > 1]"/>
   </xsl:template>

   <xsl:template match="myIncrement:*" mode="f:FXSL">
     <xsl:param name="arg1"/>
       <childnode>
       <xsl:value-of select="$arg1 + 1"/>
       </childnode>
   </xsl:template>

</xsl:stylesheet>


When applied on any XML file (ignored), it produces the wanted (long
to be included) result.

The above was written at the time with demonstration purposes and uses
simple recursion.

I will provide a DVC-style of the same transformation, which has no
problems with recursion stack overflow for big and practical values of
$pTo - $pFrom.


--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
Never fight an inanimate object
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play




On Wed, Jul 29, 2009 at 3:37 AM, Hermann
Stamm-Wilbrandt<STAMMW@xxxxxxxxxx> wrote:
>
> Emulating the XSLT2 statement
> B  B for $f in 1 to 10000
> B  B  B ...
>
> may be done in XSLT1 (providing similar scoping of variable $f) by:
> B  B <xsl:for-each select="range:to(1,10000)">
> B  B  B <xsl:variable name="f" select="."/>
> B  B  B ...
> B  B </xsl:for-each>
>
> In this case the complete set of numbers is generated into memory.:
> For bigger iteration count ("1 to 1000000" in T2.xsl) this
> may cause problems for the XSLT processor.
>
> Therefore "loop.xsl" may be used (T2.xsl, T3.xsl) to just iterate and
> do not generate all the numbers into memory. In order to allow for
> different bodies of the loops a template with name "loop" is called.
> Different implementations (body2.xsl, body3.xsl) are included
> together with "loop.xsl" into different stylesheets (T2.xsl, T3.xsl).
>
>
> I teststed this successfully with the following XSLT 1.0 processors:.
> - xsltproc (Using libxml 20626, libxslt 10117 and libexslt 813)
> - xalan-j (2.7.1)
> - IBM Websphere DataPower compiler
>
>
> All files may be downloaded here:
> http://www.stamm-wilbrandt.de/en/xsl-list/range/files.zip
>
> Find an example execution for T3.xsl at the bottom.
>
> $ cat range.xsl
> <xsl:stylesheet version="1.0"
> B xmlns:xsl B  = "http://www.w3.org/1999/XSL/Transform";
> B xmlns:exslt = "http://exslt.org/common";
> B xmlns:func B = "http://exslt.org/functions";
> B xmlns:range = "urn:xpath1range"
> B extension-element-prefixes="func">
>
> B <func:function name="range:to">
> B  B <xsl:param name="a"/>
> B  B <xsl:param name="b"/>
>
> B  B <func:result select="exslt:node-set(range:TO($a,$b))/*/text()"/>.
> B </func:function>
>
> B <func:function name="range:TO">
> B  B <xsl:param name="a"/>
> B  B <xsl:param name="b"/>
>
> B  B <xsl:choose>
> B  B  B <xsl:when test="$a > $b"/>>
> B  B  B <xsl:when test="$a = $b">>>
> B  B  B  B <func:result>
> B  B  B  B  B <e><xsl:value-of select="$a"/></e>
> B  B  B  B </func:result>
> B  B  B </xsl:when>
> B  B  B <xsl:otherwise>>
> B  B  B  B <xsl:variable name="m" select="$a + floor(($b - $a) div 2)"/>
> B  B  B  B <func:result>
> B  B  B  B  B <xsl:copy-of select="range:TO($a,$m)"/>
> B  B  B  B  B <xsl:copy-of select="range:TO($m+1,$b)"/>
> B  B  B  B </func:result>
> B  B  B </xsl:otherwise>
> B  B </xsl:choose>
> B </func:function>
>
> </xsl:stylesheet>>
>
> $ cat loop.xsl
> <xsl:stylesheet version="1.0"
> B xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
>
> B <xsl:template name="loop">
> B  B <xsl:param name="from"/>
> B  B <xsl:param name="to"/>
>
> B  B <xsl:choose>
> B  B  B <xsl:when test="$from &gt; $to"/>
> B  B  B <xsl:when test="$from = $to">
> B  B  B  B <xsl:call-template name="body">
> B  B  B  B  B <xsl:with-param name="iter" select="$from"/>
> B  B  B  B </xsl:call-template>
> B  B  B </xsl:when>
> B  B  B <xsl:otherwise>
> B  B  B  B <xsl:variable name="middle"
> B  B  B  B  B  B  B  B  B  B  B select="$from + floor(($to - $from) div
2)"/>
>
> B  B  B  B <xsl:call-template name="loop">
> B  B  B  B  B <xsl:with-param name="from" select="$from" />
> B  B  B  B  B <xsl:with-param name="to" select="$middle" />
> B  B  B  B </xsl:call-template>
> B  B  B  B <xsl:call-template name="loop">
> B  B  B  B  B <xsl:with-param name="from" select="$middle+1" />
> B  B  B  B  B <xsl:with-param name="to" select="$to" />
> B  B  B  B </xsl:call-template>
> B  B  B </xsl:otherwise>
> B  B </xsl:choose>
> B </xsl:template>
>
> </xsl:stylesheet>
>
> $ cat T1.xsl
> <xsl:stylesheet version="1.0"
> B xmlns:xsl B  = "http://www.w3.org/1999/XSL/Transform";
> B xmlns:range = "urn:xpath1range">
>
> B <xsl:include href="range.xsl"/>>
>
> B <xsl:template match="/">.
> B <!--:
> B  B for $f in 1 to 10000
> B  B  B ...
>
> B  B emulated by:
> B  B <xsl:for-each select="range:to(1,10000)">
> B  B  B <xsl:variable name="f" select="."/>
> B  B  B ...
> B  B </xsl:for-each>
> B -->
> B  B <xsl:for-each select="range:to(1,10000)">
> B  B  B <xsl:variable name="f" select="."/>
>
> B  B  B <xsl:value-of select="$f"/>
> B  B </xsl:for-each>
> B </xsl:template>
>
> </xsl:stylesheet>
>
> $ cat T2.xsl
> <xsl:stylesheet version="1.0"
> B xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
>
> B <xsl:output method="text"/>
>
> B <xsl:include href="loop.xsl"/>
> B <xsl:include href="body2.xsl"/>
>
> B <xsl:template match="/">.
> B  B <xsl:call-template name="loop">
> B  B  B <xsl:with-param name="from" select="1" />
> B  B  B <xsl:with-param name="to" select="1000000" />
> B  B </xsl:call-template>
> B </xsl:template>
>
> </xsl:stylesheet>
> $ cat body2.xsl
> <xsl:stylesheet version="1.0"
> B xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
>
> B <xsl:template name="body">
> B  B <xsl:param name="iter"/>
> B  B <xsl:value-of select="$iter"/>
> B </xsl:template>
> </xsl:stylesheet>
>
> $ cat T3.xsl
> <xsl:stylesheet version="1.0"
> B xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
> B <xsl:output method="xml" />
>
> B <xsl:include href="loop.xsl"/>
> B <xsl:include href="body3.xsl"/>
>
> B <xsl:template match="/">.
> B  B <file>
> B  B  B <xsl:call-template name="loop">
> B  B  B  B <xsl:with-param name="from" select="data/loop/@from" />)
> B  B  B  B <xsl:with-param name="to" select="data/loop/@to" />
> B  B  B </xsl:call-template>
> B  B </file>
> B </xsl:template>
>
> </xsl:stylesheet>
> $ cat body3.xsl
> <xsl:stylesheet version="1.0"
> B xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
>
> B <xsl:template name="body">
> B  B <xsl:param name="iter"/>
> B  B <data>
> B  B  B <no><xsl:value-of select="$iter"/></no>
> B  B  B <sqr><xsl:value-of select="$iter*$iter"/></sqr>
> B  B  B <name><xsl:value-of select="data/pers/lname" />, <xsl:value-of
> select="data/pers/fname" /></name>
> B  B </data>>
> B </xsl:template>
> </xsl:stylesheet>
> $ cat data.xml
> <data>
> B <loop from="3" to="5"/>
> B <pers>
> B  B <lname>Smith</lname>>
> B  B <fname>John</fname>>>
> B </pers>
> </data>
>
> $ xsltproc T3.xsl data.xml | tidy -q -xml
> <?xml version="1.0"?>
> <file>
> B <data>
> B  B <no>3</no>
> B  B <sqr>9</sqr>.
> B  B <name>Smith, John</name>
> B </data>>
> B <data>>>
> B  B <no>4</no>
> B  B <sqr>16</sqr>
> B  B <name>Smith, John</name>
> B </data>>
> B <data>>>
> B  B <no>5</no>
> B  B <sqr>25</sqr>
> B  B <name>Smith, John</name>
> B </data>>
> </file>
>
> $
>
>
> Mit besten GrC<Cen / Best wishes,
>
> Hermann Stamm-Wilbrandt
> Developer, XML Compiler
> WebSphere DataPower SOA Appliances
> ----------------------------------------------------------------------
> IBM Deutschland Research & Development GmbH
> Vorsitzender des Aufsichtsrats: Martin Jetter
> GeschC$ftsfC<hrung: Erich Baier
> Sitz der Gesellschaft: BC6blingen
> Registergericht: Amtsgericht Stuttgart, HRB 243294

Current Thread