Re: [xsl] running a 'pipeline' as a loop?

Subject: Re: [xsl] running a 'pipeline' as a loop?
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Mon, 27 Oct 2008 18:27:15 -0400

Like any "loop" in XSLT, this can be done using a recursive template that calls itself with parameters. In this case, the first pass accepts the set of updates as a parameter, along with the source, processes the source with the first update, and then calls itself with its result sent in to be the source, and the update just used removed from the update set. This continues until the update set is empty, at which point you have your final result.

Unfortunately, my time at the moment is short so I can't sketch this out in detail. If this hint isn't enough, maybe another intrepid XSLTer could help you work it out. :-)

Note that this can be processor and memory-intensive, but depending on the processor used there may also be ways around these issues.

BTW, this technique will work only in XSLT 2.0 or extended 1.0 (but you seem to be using 2.0), since unextended XSLT 1.0 can't process its own results.


At 05:59 PM 10/27/2008, you wrote:

I'd like to apply (essentially) the same transformation to an input doc several times. In my case, I've got an 'base' doc and several 'update' docs. The update docs contain elements that should replace their corresponding elements in the base doc. There can be a variable number of update docs.

The key point is that the output of one update is to become the input to the next update.

It seems like the cleanest way to do this would be to initialize a variable '$source' with the base doc, and then loop through the update docs, copying the $source to a new variable, '$output', making the appropriate substitutions along the way. Before the loop iterates to the next update doc, copy $output to $source, so the output of one update becomes the input to the next update. Conceptually, the algorithm might look like:

$source = base_doc
for each update_doc
   $output = apply-update($source, update_doc)
   $source= $output

In xslt:
    <xsl:template match="/">
            <xsl:apply-templates mode="begin" />

<xsl:template match="service-manual" mode="begin">
<!-- load all update files for the current doc -->
<xsl:variable name="updates" select="collection($filedir)//service-manual[@update = 'true']"/>
<!-- initialize $source with the base document -->
<xsl:variable name="source"><xsl:copy-of select="."/></xsl:variable>
<!-- now loop through the update docs, in update order, and create an new, updated version in the $output doc -->
<xsl:for-each select="$updates">
<xsl:sort select="article[1]/meta/@update" order="ascending"/>
<xsl:variable name="output">
<!-- now perform the update by operating on $source -->
<xsl:apply-templates select="$source">
<xsl:with-param name="updates" select="$updates"/>
<!-- copy this output to source, in preparation for applying the next update on top of this one -->
<!-- tried copy-of instead of apply-templates...mode="copy", but it did no better... -->
<xsl:variable name="source"><xsl:apply-templates select="$output" mode="copy"/></xsl:variable>
<xsl:copy-of select="$output"/>

After the loop completes, $output should contain the final version of the updated doc, but after the loop is exited, $output goes out of scope (I'm getting an 'undefined variable' error on the last copy-of select="$output", which would be where the final doc is finally outputted).

Anyone have any ideas about how I might be able to create this kind of transform, where the input comes from the output?

Thanks in advance for any help.

Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.      
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
  Mulberry Technologies: A Consultancy Specializing in SGML and XML

Current Thread