This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Generic Looping
- From: Corey_Haines at progressive dot com
- To: XSL-List at lists dot mulberrytech dot com
- Date: Thu, 7 Feb 2002 15:03:58 -0500
- Subject: [xsl] Generic Looping
- Reply-to: xsl-list at lists dot mulberrytech dot com
Hi,
As a little side project, I've been working on a generic looping template
which will produce a formatted xml tree based on a format input tree and
the list that is passed in. Basically, it is an XML equivalent of printf,
except it loops over a list. I was hoping that the gurus on the list could
point out any efficiencies or changes I could make to the XSL which would
make it work faster or more standard. I'm putting a description below.
I very much appreciate anybody's time that they can spend improving my
idea.
(oh, and a side note, I originally was using <![CDATA[<td>]]> tags with
d-o-e enabled, but a few posts from you guys saying it isn't part of the
rec changed my approach, which ended up with my method being able to have
a much nicer way of writing the output format tree, as well as supporting
nesting and the like. Thanks!)
Thanks,
-Corey Haines
Basically, the requirements for the template are as follows:
1) Pass in a nodelist;
2) Pass in a format;
3) Template loops through nodelist and for each item in the list, process
the item based on the format passed in;
4) The final output of the template is the result tree composed of the
processing of each individual item in your nodelist.
I came up with an XML format for the format tree, here are a couple
examples.
Given the following XML:
<Loop>
<one id="1" name="one">hai-1</one>
<one id="2" name="two">hai-2</one>
</Loop>
I can produce the following
<td id="1" val="hai-1">one<br></br><span
style="font-weight:bold">hai-1</span></td>
<td id="2" val="hai-2">two<br></br><span
style="font-weight:bold">hai-2</span></td>
with the following format tree
<td>
<outputattribute name='id' select='id' />
<outputattribute name='val' select='$value$' />
<inputattribute name='name' /><br />
<span style="font-weight:bold">
<inputvalue />
</span>
</td>
<outputattribute name="" select="" /> effectively does an <xsl:attribute
/> with a name of @name and a value of @select, $value$ returns the value
of the current element being processed (<xsl:value-of />)
<inputattribute name='' /> effectively does a <xsl:value-of
select="@{name} />
<inputvalue /> is effectively <xsl:value-of select='.' />
Here are the two XSL files, one making the call, the other with the
genloop template
---------genlooptest.xsl---------
<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:output method="xml" />
<xsl:include href="genloop.xsl" />
<xsl:variable name='TDbuildlist'>
<td>
<outputattribute name='id' select='id' />
<outputattribute name='val' select='$value$' />
<inputattribute name='name' /><br />
<span style="font-weight:bold">
<inputvalue />
</span>
</td>
</xsl:variable>
<xsl:variable name='CSVbuildlist'>
<inputvalue /><text>,</text>
</xsl:variable>
<xsl:variable name='br'><br /></xsl:variable>
<xsl:template match="/">
<xsl:call-template name="genloop_main">
<xsl:with-param name="loopCriteria" select="Loop/one" />
<xsl:with-param name='outputformat'><xsl:copy-of
select="$TDbuildlist" />
</xsl:with-param>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
---------genloop.xsl---------
<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:template name="genloop_main">
<xsl:param name="loopCriteria" select="/.." />
<xsl:param name='outputformat' select='/..' />
<xsl:for-each select="msxsl:node-set($loopCriteria)">
<xsl:call-template name="genloop_processelement">
<xsl:with-param name='outputformat' select="$outputformat"
/>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template match="node()" mode="genloop_processoutputformat">
<xsl:param name="element" select="/.." />
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:for-each select="outputattribute">
<xsl:attribute name='{@name}'>
<xsl:choose>
<xsl:when test="@select =
'$value$'">
<xsl:value-of
select='$element' />
</xsl:when>
<xsl:otherwise>
<xsl:value-of
select="msxsl:node-set($element)/@*[name() = current()/@select]" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates select="child::node()[not(name() =
'outputattribute')]" mode='genloop_processoutputformat'>
<xsl:with-param name='element' select='$element'
/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match='inputvalue' mode='genloop_processoutputformat'>
<xsl:param name="element" select="/.." />
<xsl:value-of select="$element" />
</xsl:template>
<xsl:template match='inputattribute' mode="genloop_processoutputformat">
<xsl:param name='element' select='/..' />
<xsl:value-of select="msxsl:node-set($element)/@*[name() =
current()/@name]" />
</xsl:template>
<xsl:template name="genloop_processelement">
<xsl:param name="outputformat" select="/.." />
<xsl:apply-templates select="msxsl:node-set($outputformat)/*"
mode='genloop_processoutputformat'>
<xsl:with-param name="element" select="." />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list