Re: [xsl] Referencing nodes from an out-of-scope xsl:for-each loop

Subject: Re: [xsl] Referencing nodes from an out-of-scope xsl:for-each loop
From: "Joel P Thornton" <joelt@xxxxxxxxxxxxx>
Date: Fri, 18 May 2001 10:57:18 -0700
Adam Turoff wrote:
---
[excellent solution here]
(I suppose you could do the same thing matching on <row> with a lot
of ancestor hacking, but I only thought of that after I got this pair
of templates working.) Z.
---

Adam - Thanks for your thoughtful response.  It still isn't quite there yet,
though; when you mentioned the <B> style information within the <column>
tags being a problem, you were right.

I gave this as a relatively simple example of what I'm hoping to achieve:

  <display-columns>
    <column label="Name"><B><sql-field name="title"/></B></column>
    <column label="Location"><sql-field name="location"/></column>
  </display-columns>

But I am really wanting to do more complex stuff, such as this:

  <display-columns>
    <column label="Name">
      <link>
        <label>
          <B><sql-field name="title"/></B>
        </label>
        <href>
          /viewarea.asp?where=<sql-field name="location"/>
        </href>
     </link>
    </column>
  </display-columns>

.. in this way permitting versatile display formatting options while
minimizing xsl work.

Can this be done?  I'd love to hear suggestions .. and thanks for those so
far :)

joel




=======================================
---------------------------------------
> I have this xml:
>
> --
> <sql-recordset>
>   <row title="Sunshine Home" location="Seattle WA"/>
>   <row title="Value Village" location="Seattle WA"/>
>   <row title="Salvation Army" location="Tacoma WA"/>
>
>   <display-columns>
>     <column label="Name"><B><sql-field name="title"/></B></column>
>     <column label="Location"><sql-field name="location"/></column>
>   </display-columns>
> </sql-recordset>
> --
>
> And I want to write an XSL which will transform this into:
>
> --
> <table>
>   <th>Name</th>
>   <th>Location</th>
>
>   <tr>
>     <td><b>Sunshine Home</b></td><td>Seattle WA</td>
>   </tr> ... > </table>
> --
>
>
> Currently, I <xsl:for-each> through the collection of <row> nodes, and
then
> <xsl:for-each> through each of the <column>s for each row.  The problem
is,
> I have a <xsl:template match="sql-field"> template which matches the
> <sql-field> tags within the <column> tags.  But I don't know how to get
that
> template to "know" which row it is currently on.  I tried using
> <xsl:variable> but I'm being told that, within the sql-field template, the
> variable is out of scope.
>
> Ideas? First you need to get into a state where you have the tree fragment
of
rows as well as the tree fragment of columns.  This can be done using
<xsl:call-template> for <row>, passing a tree fragment for <display-columns>
as a parameter. Once you've cracked that nut, it's a simple case of
referring to both
nodesets at the same time.  :-) The really tricky part is respecting the
bolding with
     <column label="Name"><B><sql-field name="title"/></B></column>
as well as no formatting
     <column label="Location"><sql-field name="location"/></column> It took
some trickery to get that working.  You should consider a different
way for specifying HTML styles to be output, such as putting a style=''
attribute on <column> and passing it through to <td>. <xsl:template
match="sql-recordset">
 <xsl:variable name="display-columns" select="display-columns"/>

 <!-- table header (simple) -->
 <table>
  <tr>
   <xsl:for-each select="display-columns/column/@label">
    <th><xsl:value-of select="."/></th>
   </xsl:for-each>
  </tr>   <!-- table rows (passing the display format as a parameter -->
<xsl:for-each select="row">
   <xsl:call-template name="display-row">
    <xsl:with-param name="display-columns" select="$display-columns"/>
   </xsl:call-template>
  </xsl:for-each>
 </table>
</xsl:template> <!-- Emit the current <row/> as specified -->
<xsl:template name="display-row">
 <xsl:param name="display-columns"/>  <!-- save the tree fragment for the
row we're processing -->
 <xsl:variable name="row" select="."/>
 <tr>   <!-- now loop over the column display order -->
  <xsl:for-each select="$display-columns/column//sql-field">
   <xsl:variable name="column" select="@name"/>
   <td>     <!-- HACK: Respect <b> surrounding <sql-field> -->
    <xsl:choose>
     <xsl:when test="name(..) != 'column'">
      <xsl:element name="{name(..)}">
       <xsl:value-of select="$row/attribute::*[name()=$column]"/>
      </xsl:element>
     </xsl:when>
     <xsl:otherwise>       <!-- standard case: just emit the data -->
      <xsl:value-of select="$row/attribute::*[name()=$column]"/>
     </xsl:otherwise>
    </xsl:choose>
   </td>
  </xsl:for-each>
 </tr>
</xsl:template> (I suppose you could do the same thing matching on <row>
with a lot
of ancestor hacking, but I only thought of that after I got this pair
of templates working.) Z.

---------------------------------------
=======================================


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


Current Thread