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 > $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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Emulating XPATH2 range in XSL, Hermann Stamm-Wilbra | Thread | Re: [xsl] Emulating XPATH2 range in, Hermann Stamm-Wilbra |
Re: [xsl] Pairing elements accordin, Hermann Stamm-Wilbra | Date | Re: [xsl] Emulating XPATH2 range in, Hermann Stamm-Wilbra |
Month |