RE: [xsl] Use of moded templates?

Subject: RE: [xsl] Use of moded templates?
From: "M. David Peterson" <m.david@xxxxxxxxxx>
Date: Wed, 7 Apr 2004 10:55:00 -0600
Once you have the node-set specified in your XPath running through the
system the easiest way is to create a template for each element whos
output needs to be different than any other element e.g. the <xyz>
element needs to be output as <123> while the rest of the elements need
to be output the same as there input e.g. <b> is output as <b> and <p>
is output as <p>.  Once you have that setup then use the match condition
of your templates to match the proper elements.  e.g. <xsl:template
match="p | b | i">

Using the "|" to join the elements (not to be confused with "or" because
that is not what "|" does in XSLT) will ensure that, in the above case,
the p, b, and i elements will match to that template and be processed
accordingly.  Then using <xsl:apply-templates/> without the select
attribute will recursively process the elements that are contained
within the current matching element, for example if the element that
matched was <p> and within that element was the following Result Tree
Fragement... 

this is a paragraph text <b> this is bold <i> this is bold italic
</i></b></p>

then using apply-templates would do the following...

- deposit the leading text before the next element, in this case " this
is a paragraph text" into the output stream.  This is an important thing
to remember as if you use <xsl:value-of..> to gain access to the inner
text value of <p> then you will see it twice in the output.

- match the next element, in this case <b> to the proper template, in
this case its the same template.

- process the element accordingly and then when it reaches the
apply-templates again the same process will begin again.
apply-templates will continue to pass the element to the correct
matching template (with the remaining RTF as along with it) each time it
runs into another element contained within the RTF of the current
matching element.  So if you were to use apply-templates in each of your
templates that would ensure that every node that matches a template will
be processed.  

A complete example of the above template that matched p, b, and i is as
follows...

<xsl:template match="p | b | i ">
	<xsl:element name="{name()}">
		<xsl:apply-templates/>
	</xsl:element>
<xsl:template>

This above template will match p, b, and i and in each pass will create
an element in the output that has the same name, so lets say "b", and
then within that element output any text in the RTF that comes before
the next element, and then pass this RTF (minus the text it just output)
to the correct template.  Keep in mind that recursion takes place within
the context of its parent and will continue to do so until the recursion
process no longer matches any of the tests or there is no more data to
process.  So when the first <p> tag is matched then any and all element
that are contained within the RTF it brought along with it will be
processed within the structure of this template (and as long as you put
the apply-templates between the begin and end xsl:element it will be
output within the context of the <p> open and close tags.

I hope I haven't made this more confusing as it can tend to be that way
when you are trying to think from the standpoint of a functional
language processor.  But when you get it you get it and, like riding a
bike, you never forget it.

Best of luck!

<M:D/>

-----Original Message-----
From: Mark Lundquist [mailto:ml@xxxxxxxxxxxxxx] 
Sent: Wednesday, April 07, 2004 9:43 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] Use of moded templates?

Hi,

I've got a node set that's selected by an ugly, gnarly Xpath 
expression... let's call that the "outer" node set.  Those nodes, in 
turn, contain the nodes that  I need to transform - let's call those 
the "inner" node set.  Everything else is to be filtered out of my 
transformation.

I don't want to have to repeat the hairy Xpath expression in the 
template that matches the "inner" nodes, so I used a mode that lets me 
match these nodes just by their name.  The mode keeps the template from 
being applied to nodes that would otherwise match, i.e. nodes outside 
the "outer" nodes.

For example (XHTML):

	<xsl:template match="really-hair-xpath-expresssion">	<!--
outer -->
		.
		.
		<xsl:apply-templates select="li" mode="process" />
<!-- inner -->
		.
		.
	</xsl:template>

	<!-- inner -->
	<xsl:template match="li" mode="process">
		.
		.
	</xsl:template>

Once again, the idea here is to avoid having to write the second 
template with

	match="really-hairy-xpath-expression/li"

I get the feeling that this situation must come up all the time, but... 
(a) This is the first time I recall having to solve this problem, and 
(b) I haven't seen it mentioned as a typical application in 
explanations of moded templates.  All that makes me feel like I'm 
missing something, or like I've solved this before in some different 
way.  Is there a "right way" to do this?  Is this a normal use for 
moded templates?

Thanks,
mark

Current Thread