[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

[xsl] Generic Looping


Subject: [xsl] Generic Looping
From: Corey_Haines@xxxxxxxxxxxxxxx
Date: Thu, 7 Feb 2002 15:03:58 -0500

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



Current Thread
Keywords