xsl-list
[Top] [All Lists]

Re: making trees/lists during execution (dynamically)

2004-02-09 11:12:49
Hi Peter,

OK, there are (at least) two ways that you could approach this.

The first is to do a two-step transformation in the way that you
describe. You could do that using two stylesheets, or you could use
result tree fragments and a node-set() extension function within a
single stylesheet. If you want to do the latter, then you need to
create the result tree fragment in a variable, using something like:

<xsl:template match="ford">
  <xsl:variable name="info">
    <car>
      <title>A FORD CAR</title>
      <information>
        <row>
          <title>Ford specific A</title>
          <text><xsl:value-of select="fordA"></text>
        </row>
        <row>..</row>
      </information>
    </car>
  </xsl:variable>
  ...
</xsl:template>

Then, transform the result tree fragment in the $info into a node-set
using a node-set() extension function, and apply templates to it in a
different mode (e.g. 'html') in order to process it into HTML:

<xsl:template match="ford">
  <xsl:variable name="info">
    <car>
      <title>A FORD CAR</title>
      <information>
        <row>
          <title>Ford specific A</title>
          <text><xsl:value-of select="fordA"></text>
        </row>
        <row>..</row>
      </information>
    </car>
  </xsl:variable>
  <xsl:apply-templates select="exsl:node-set($info)" mode="html" />
</xsl:template>

The template that matches <car> elements in 'html' mode can then
process the content of the <information> element in order to create
the relevant HTML table, for example:

<xsl:template match="car" mode="html">
  <table>
    <tbody>
      <tr>
        <td colspan="2"><xsl:value-of select="title" /></td>
      </tr>
      <xsl:for-each select="information/row">
        <tr>
          <td><xsl:value-of select="title" /></td>
          <td><xsl:value-of select="text" /></td>
        </tr>
      </xsl:for-each>
    </tbody>
  </table>
</xsl:template>

I would use this approach if the HTML for the table was very long and
complicated, or if the intermediate format was useful elsewhere (for
example if you wanted to produce XSL-FO from the same data).

A second approach would be to use moded templates to map elements onto
titles and so on within the table. Have a template that matches all
elements within <cars> elements and produces the general HTML. Within
that template, apply templates to the relevant elements in a 'title'
or 'data' mode to produce the content of the table. Then have
templates in 'title' mode to produce the car-specific titles.
Something like the following:

<xsl:template match="cars/*">
  <table>
    <tbody>
      <tr>
        <td colspan="2">
          <xsl:apply-templates select="." mode="title" />
        </td>
      </tr>
      <xsl:for-each select="*">
        <tr>
          <td><xsl:apply-templates select="." mode="title" /></td>
          <td><xsl:value-of select="." mode="text" /></td>
        </tr>
      </xsl:for-each>
    </tbody>
  </table>
</xsl:template>

<xsl:template match="*" mode="data">
  <xsl:value-of select="." />
</xsl:template>

<xsl:template match="ford" mode="title">A FORD CAR</xsl:template>
<xsl:template match="fordA" mode="title">
  <xsl:text>Ford specific A</xsl:text>
</xsl:template>
... and so on ...

I'd use this approach if the HTML for the table was long or complex,
but an intermediate format wasn't useful elsewhere, or if I wanted to
avoid using an extension function to retain portability.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


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



<Prev in Thread] Current Thread [Next in Thread>