xsl-list
[Top] [All Lists]

Re: Noob: hmm using nested templates, how do i get the nodes within

2003-09-23 06:58:11
Thnks Wendell,

For your explanation, gonna read it a couple of times and read up on:

"Barry, I suggest you might spend a bit of time researching the XSLT 
 processing model." 

I thought i knew the basics, i am used to parse an xml for a flashed site.

Guess i made the wrong assumptions,

Grtz

----- Original Message ----- 
From: "Wendell Piez" <wapiez(_at_)mulberrytech(_dot_)com>
To: <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
Sent: Thursday, September 18, 2003 7:07 PM
Subject: Re: [xsl] Noob: hmm using nested templates, how do i get the nodes 
within 


Barry,

Two problems here. One is the one you asked about ... how you pass a node 
to a named template as a parameter. The other is that either you haven't 
quite understood the notion of a "context node" (a critical notion in 
XSLT), or you haven't explained/described your problem (since it doesn't 
match your approach).

The second problem is the deeper one, and if we address it the first one 
will just go away.

At 04:38 AM 9/18/2003, you wrote:
so now i heard i could use nested template, like
-------------------------------------------------
<xsl:template match="//Row">
<fo:table-row>
<fo:table-cell border="solid black 1 px" border-collapse="collapse">
<fo:block>
<xsl:value-of select="TT"/>
</fo:block>
</fo:table-cell>
<xsl:call-template name="cell"/>
</fo:table-row>
</xsl:template>

Correct. Calling the "cell" template with no parameters, it nonetheless 
takes the context node as its context node. So if in your source data you have

<Row>
   <aaa>Total</aaa>
   <TdD>null</TdD>
   <NA>45678</NA>
   <FR>45644</FR>
</Row>

when you evaluate this (or any) Row, the template above gives you an 
fo:table-row containing a cell with the value of the Row's TT child (hey! 
you don't have any! so what do you want in that cell?), followed by 
whatever the "cell" template does, with the matched node of the calling 
template (the row) as its context node.

But when you call the "cell" template

<xsl:template name="cell">
<fo:table-cell border="solid black 1 px" border-collapse="collapse">
<fo:block>
<xsl:variable name="cell" select="//Row/[*]"/> <---------------Here's 
where i think i go wrong, how do i select the nodes

Right -- you're stuck. How, from a "Row" (the context node) do you pick 
each one of the nodes in turn?

Actually, it can be done, wrapping it all in a for-each -- but this 
technique isn't actually the most efficient way XSLT offers to address your 
requirement.

Better would be not to pick these nodes up from the Row, but to *change* 
the context node to each of these. This is very simply done by applying its 
own template to each them, using a match. Then the context node changes by 
itself:

<xsl:template match="TdD | NA | FR">
   <fo:table-cell border="solid black 1 px" border-collapse="collapse">
     <fo:block>
     <!-- we don't need to bind any nodes to the variable: rather, the
          node we're interested in is whatever node we matched:
          our context node -->
       <xsl:choose>
         <xsl:when test="not(self::node() = 'null')">
            <xsl:value-of select="self::node()"/>
         </xsl:when>
       </xsl:choose>
     </fo:block>
   </fo:table-cell>
</xsl:template>

Which could be simplified and abbreviated to

<xsl:template match="TdD | NA | FR">
   <fo:table-cell border="solid black 1 px" border-collapse="collapse">
     <fo:block>
       <xsl:value-of select="self::node()[not(.='null')]"/>
     </fo:block>
   </fo:table-cell>
</xsl:template>

But to call this template for each of those nodes, we need to change our 
calling template:

<xsl:template match="Row">
   <fo:table-row>
     <fo:table-cell border="solid black 1 px" border-collapse="collapse">
       <fo:block>
         <xsl:value-of select="child::TT"/>
         <!-- whatever that is... I think you mean select="aaa" -->
       </fo:block>
     </fo:table-cell>
     <xsl:apply-templates name="child::TdD | child::NA | child::FR"/>
   </fo:table-row>
</xsl:template>

"TdD | NA | FR" is short for "child::TdD | child::NA | child::FR", just to 
be perfectly clear.

Barry, I suggest you might spend a bit of time researching the XSLT 
processing model. Basically an XSLT processor starts by matching a root 
node, and is set up by default to traverse down through the tree 
(depth-first traversal in "document order"), matching templates as it goes. 
Each of these templates has the opportunity to create nodes in the output, 
nodes which in each case end up "wrapping" or "containing" the nodes 
generated by templates "lower" in the tree (its children and descendants). 
You simply need to match at two levels -- the row (which generates a row, 
surprisingly) and the item within the row (which generates a cell). The 
XSLT Processor can take care of this traversal for you, if you let it.

Note that although this is "natural", there are times when other 
complications -- such as, one might want two of your three nodes grouped 
together in a single cell -- make it very useful to do it with a named 
template after all. Such as

<xsl:template match="Row">
   <fo:table-row>
     <fo:table-cell border="solid black 1 px" border-collapse="collapse">
       <fo:block>
         <xsl:value-of select="child::TT"/>
         <!-- whatever that is... I think you mean select="aaa" -->
       </fo:block>
     </fo:table-cell>
     <xsl:call-template name="cell">
       <xsl:with-param name="contents" select="TdD | NA"/>
     </xsl:call-template>
     <xsl:call-template name="cell">
       <xsl:with-param name="contents" select="FR"/>
     </xsl:call-template>
   </fo:table-row>
</xsl:template>

<xsl:template name="cell">
   <xsl:param name="contents" select="."/>
   <xsl:variable name="string-value">
     <xsl:apply-templates select="contents"/>
   </xsl:variable>
   <fo:table-cell border="solid black 1 px" border-collapse="collapse">
     <xsl:for-each select="$contents[not(.='null')">
       <fo:block>
         <xsl:value-of select="."/>
       </fo:block>
     </xsl:for-each>
   </fo:table-cell>
</xsl:template>

I hope this is helpful. If it's confusing, study up on templates and the 
processing model.

Cheers,
Wendell






Any more suggestions.


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

___&&__&_&___&_&__&&&__&_&__&__&&____&&_&___&__&_&&_____&__&__&&_____&_&&_
     "Thus I make my own use of the telegraph, without consulting
      the directors, like the sparrows, which I perceive use it
      extensively for a perch." -- Thoreau


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



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