Subject: [xsl] Re: Re: A Generic template for multi-pass processing (Was: Re: Applying two transformations consecutively) From: Dimitre Novatchev <dnovatchev@xxxxxxxxx> Date: Sat, 7 Jul 2001 12:59:53 -0700 (PDT) |
Chris Nolte wrote: > Dimitre, > > I'd like to be able to understand how your generic template works so I can > adapt it. I was able to get it to work on your example, but I'm confused by > it. > [snip -- the first group of questions were already answered by David Carlisle: thank you David] > Finally, can you show me how to modify your template so that, say, in pass1 > I call template1 (or apply-templates mode='one') and in pass2 I call > template2 (or apply-templates mode='two')? > > How would you set it up to use "any number of not known in advance" > templates? Hi Chris, The main mechanism, which I use to implement generic templates is the "template reference". This is a node of a unique type (having a unique namespace-uri). In case we also provide a unique (one and only one) template that matches exactly this type of node, then the node can be used as a template reference. When such a unique node is specified as the value of the "select" attribute of xsl:apply-templates, we know that exactly ("our") the template matching it will be instantiated by the XSLT processor. This is very similar to using xsl:call-template, with one of the most important differences between the two being that you can pass a node (the template reference) as a parameter to another template, but QNames (the values that have to be specified for the "name" attribute of xsl:call-template) must always be specified explicitly and a xsl:parameter or xsl:variable reference is not allowed. Because of this, it is not possible to call a template by name dynamically (without knowing the ***literal*** name of the template in advance), as you can read in the xslt-faq (can't give an URL, as stable URLs are not supported by this FAQ site). However, it is perfectly possible to instantiate a template dynamically, without knowing anything about it in advance. This has been implemented using the notion of a template reference. To return to your question, here's the generic 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)/node()"/> <xsl:with-param name="passes" select="$nextPasses"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> Focus your attention on the following snippet: <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> As you can see, the xsl:apply-templates will instantiate a (unknown) template, based on a template reference, passed as part of one of the parameters to this template. The caller of the template decides what template reference(s) to specify as parameters, and what templates to have that match this template reference. This allows the author of the generic template (me in this case) to be a different person from the caller of the template (e.g. you) and not to know anything about any of the callers of his generic template, and what template references they're going to pass as parameters, and what actual templates they'd need to instantiate. So, if you want to instantiate (not to call) template1 in pass1 and template2 in pass2, you'll do it like this: <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="yourPass1" xmlns:pass2="yourPass2" 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> <!-- Put here whatever parameters template1 needs, replace the next two lines with your <param> elements --> <param>a</param> <param>b</param> </params> </pass1> <pass2> <templateRef><pass2:node /></templateRef> <params> <!-- Put here whatever parameters template2 needs, replace the next two lines with your <param> elements --> <param>b</param> <param>c</param> </params> </pass2> <!-- You can specify as many passes to be performed with whatever templates and whatever parameters you need like in the commented third pass below --> <!-- <pass3> <templateRef><pass3:node /></templateRef> <params> <param>c</param> <param>d</param> </params> </pass3> --> </xsl:variable> <xsl:template match="/"> <xsl:call-template name="multiPass"> <!-- Specify whatever necessary for initial input to template1 as below --> <xsl:with-param name="inputPipe" select="/*"/> <xsl:with-param name="passes" select="msxsl:node-set($pipeParam)/*"/> </xsl:call-template> </xsl:template> <!-- Your template1 --> <xsl:template match="*[namespace-uri() = 'myPass1']"> <xsl:param name="input" select="/.."/> <xsl:param name="params" select="/.."/> <!-- Perform any necessary transformation here --> <!-- $params/param contains all "param" elements specified for this instantiation --> </xsl:template> <!-- Your template2 --> <xsl:template match="*[namespace-uri() = 'myPass2']"> <xsl:param name="input" select="/.."/> <xsl:param name="params" select="/.."/> <!-- Perform any necessary transformation here --> <!-- $params/param contains all "param" elements specified for this instantiation --> </xsl:template> I think I answered your question completely and in detail. You can also read my explanation of generic templates in: http://lists.fourthought.com/pipermail/exslt/2001-May/000169.html 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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
[xsl] Re: parameter problems, Dimitre Novatchev | Thread | Re: [xsl] Re: Re: A Generic templat, Chris Nolte |
RE: [xsl] need an "&" in my text!!!, Michael Kay | Date | Re: [xsl] result tree fragments and, David Carlisle |
Month |