[xsl] A Generic template for multi-pass processing (Was: Re: Applying two transformations consecutively)

Subject: [xsl] A Generic template for multi-pass processing (Was: Re: Applying two transformations consecutively)
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Tue, 26 Jun 2001 06:45:42 -0700 (PDT)
Jeni Tennison wrote:

> Otherwise, I think that it works out OK to just always sort on that
> particular column, first boolean on whether it's a number, second by
> number and finally by text. Note that the first sort is the other way
> round from how I did it before, to get the text to sort after the
> numbers rather than the other way around, but that this is fixed
> rather than using the $sortorder parameter so that the TOTAL row is
> always after the numerical ones, but this means that the sort order
> for the rows might not be exactly what you want:

Congratulations Peer and Rechell!

If even Jeni can be brought into this state, this definitely means that something's
completely wrong with the approach to solve the problem.

In several messages before I have pointed out that using the generic sort() template
helps in complicated xsl:sort cases.

Now I'm providing another generic template -- a generic multi-pass processing
template.

Just for demonstration purposes I'm using it with a very simple example. The source
xml file consists of one top element and it has only a single text-node child.

The task is on the first pass to change all 'a'-s to 'b'-s, and on the second pass
to change all 'b'-s to 'c'-s.

I'm also using just a single custom template for these both passes.


However, because of its genericity, the template can be used in any case of
multi-pass processing -- for any number of passes, involving any number of not known
in advance templates for carrying out each pass, allowing each template to be passed
any number of parameters.


Here's the code:

xml source:
----------
<t>
An example of two pass processing
</t>


Stylesheet:
----------
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:saxon="http://icl.com/saxon";
xmlns:pass1="myPass1"
xmlns:pass2="myPass2"
exclude-result-prefixes="xsl msxsl saxon pass1 pass2"
>
    <xsl:output  encoding="US-ASCII" omit-xml-declaration="yes"/>

      <xsl:variable name="pipeParam">
        <pass1>
          <templateRef><pass1:node /></templateRef>
          <params>
             <param>a</param>
             <param>b</param>
          </params>
        </pass1>
        <pass2>
          <templateRef><pass2:node /></templateRef>
          <params>
             <param>b</param>
             <param>c</param>
          </params>
        </pass2>
      </xsl:variable>


    <xsl:template match="/">

      <xsl:call-template name="multiPass">
        <xsl:with-param name="inputPipe" select="/*"/>
        <xsl:with-param name="passes" select="msxsl:node-set($pipeParam)/*"/>
      </xsl:call-template>
    </xsl:template>
    
    <xsl:template name="multiPass">
      <xsl:param name="inputPipe" select="/.."/>
      <xsl:param name="passes" select="/.."/>
      
      <xsl:choose>
        <xsl:when test="not($passes)">
          <xsl:copy-of select="$inputPipe"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="thisPass" select="$passes[1]"/>
          <xsl:variable name="nextPasses" select="$passes[position() > 1]"/>

          <xsl:variable name="vOutput">
            <xsl:apply-templates select="$thisPass/templateRef/*">
              <xsl:with-param name="input" select="$inputPipe"/>
              <xsl:with-param name="params" select="$thisPass/params"/>
            </xsl:apply-templates>
          </xsl:variable>
          
          <xsl:call-template name="multiPass">
            <xsl:with-param name="inputPipe" select="msxsl:node-set($vOutput)"/>
            <xsl:with-param name="passes" select="$nextPasses"/>
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>

    <xsl:template match="*[namespace-uri() = 'myPass1'
                           or namespace-uri() = 'myPass2'
                           ]">
         <xsl:param name="input" select="/.."/>
         <xsl:param name="params" select="/.."/>

       <xsl:for-each select="$input">
        <xsl:copy>
          <xsl:value-of select="translate(., $params/param[1], $params/param[2])"/>
        </xsl:copy>
      </xsl:for-each>
    </xsl:template>


</xsl:stylesheet>



Result:
------

An excmple of two pcss processing



I hope this helped.

Cheers,
Dimitre Novatchev.


__________________________________________________
Do You Yahoo!?
Get personalized email addresses from Yahoo! Mail
http://personal.mail.yahoo.com/

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread