Re: [xsl] Hopefully not a terribly silly question

Subject: Re: [xsl] Hopefully not a terribly silly question
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Thu, 03 Jan 2002 13:42:17 -0500
Morgan,

At 12:21 PM 1/3/02, you wrote:
I am trying to iterate through each of the rows, then each of the columns. If I am not in the first column then I want to get a hold of the name attribute from the first row and apply it.
...
Unfortunately, I get a the literal string result of the concat() function, instead of the actual data value. Is there some sort of eval() function that I need to use? Am I approaching this incorrectly?

Yes, unfortunately you are. You can't construct an XPath dynamically and then evaluate it within your stylesheet. (See other threads ongoing about whether exactly this feature should be added to the language in a later version.)


There are several other ways to do what you want, however. The one I'd use, since it's fairly neat and clean and efficient, is to use keys (and it looks like whatever the solution is you adopt, you may be reusing it alot in your ODBC-thing).

You use a key by setting it up with a declaration, then calling the key() function. The function returns you a set of nodes based on the key name and value you pass to it.

In your case, you want to be able to get the value of the name attribute on a column element in your first row, in cases where a subsequent column element has no name. The column element you want back is the one in the corresponding location among its siblings to that of the unnamed column element among its siblings.

So:
<xsl:key name="named-columns" match="/result/row[1]/column"  use="position()"/>

This will allow you to get columns from the first row, using the count of its preceding column siblings as its key value. (Caveat: I would actually use count(preceding-sibling::column) here instead of position(), since it's more robust and less likely to introduce hard-to-spot bugs when you do template-based processing.)

Then when you generate your output:

<xsl:template name="print_name">
  <xsl:choose>
    <xsl:when test="@name">
     Name = <xsl:value-of select="@name"/>
   </xsl:when>
   <xsl:otherwise>
     Name <xsl:value-of select="position()"/>=

     <xsl:value-of select="key('named-columns', position())/@name"/>
      <!-- this retrieves the @name attribute from the corresponding
           named column -->

     Value <xsl:value-of select="position()"/>=
      <xsl:value-of select="."/>
   </xsl:otherwise>
  </xsl:choose>
</xsl:template>

I hope that helps! Personally I'd drive this through templates: easier to set up and manage once you get the hang of them. I'd also avoid position(), as I said: it can be tricky, and beginners often think it's saying something it's not. (Hint: it's *NOT* saying what the position of an element is among its siblings.) Replacing it with the expression count(preceding-sibling::column) will work as well (better) in this case.

Cheers,
Wendell

"For every complex problem, there is a solution that is simple, neat, and wrong."
-- H.L. Mencken (1880-1956)

... and it's usually position() ...




======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


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



Current Thread