[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: ordering and iteration problem

Subject: Re: ordering and iteration problem
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 16 Nov 2001 10:40:18 +0000
circuit breaker id
Hi Hector,

> How would you modify your solution to accomodate Mark's XML file
> modified as follows:
[snip]
> ..the difference is that now there could be a nested table of
> Circuit Breakers. Using the "key" function in your stylesheet does
> not provide that kind of output. I'm looking to still do recursion
> within a cell to look for a nested table there (N levels down)

If I understand you correctly, each circuit-breaker-panel creates its
own table containing just its child circuit-breaker elements. Some of
the cells in that table might contain other tables for the nested
circuit-breaker-panels.

As you've seen, the keys will access *all* the circuit-breaker
elements, no matter what circuit-breaker-panel they're on, so you need
to change the keys so that you can quickly access only those within a
particular circuit-breaker-panel. Since the circuit-breaker-panel
elements don't have any kind of ID that you could use to identify them
with, you have to make up an ID for them, which you can do with the
generate-id() function.

So I'd adapt the keys to include information about the parent
circuit-breaker-panel of the circuit-breaker, as follows:

<xsl:key name="breakers-by-column" match="b:circuit-breaker"
         use="concat(generate-id(parent::b:circuit-breaker-panel),
                     ':', @column)" />
<xsl:key name="breakers" match="b:circuit-breaker"
         use="concat(generate-id(parent::b:circuit-breaker-panel),
                     @row, ':', @column)" />

If a circuit-breaker-panel was given an ID of 'abc' then you could get
the circuit breaker in the first cell in the first row with:

  key('breakers', 'abc:1:1')

Then I'd change the arrangement of the templates slightly so that the
template matched the circuit-breaker-panel in order to create the
table, and so that it uses the new keys:

<xsl:template match="b:circuit-breaker-panel">
  <!-- store the ID of the panel -->
  <xsl:variable name="panel" select="generate-id()" />
  
  <!-- work out the maximum rows for this table -->
  <xsl:variable name="max-rows">...</xsl:variable>
  <!-- work out the maximum columns for this table -->
  <xsl:variable name="max-cols">...</xsl:variable>
  <!-- store the right number of nodes for the rows in a variable -->
  <xsl:variable name="rows"
                select="$random-nodes[position() &lt;= $max-row]" />
  <!-- store the right number of nodes for the columns in a variable
       -->
  <xsl:variable name="columns"
                select="$random-nodes[position() &lt;= $max-col]" />

  <!-- create the table -->
  <table>
  
    <!-- iterate over the right set of nodes to get the rows -->
    <xsl:for-each select="$rows">
      <!-- store the row number -->
      <xsl:variable name="row" select="position()" />
      <!-- create the row -->
      <tr>

        <!-- iterate over the right set of nodes to get the columns
             -->
        <xsl:for-each select="$columns">
          <!-- store the column number -->
          <xsl:variable name="col" select="position()" />

          <!-- change the current node so that the key works -->
          <xsl:for-each select="$data">
            <!-- identify the relevant circuit breaker -->
            <xsl:variable name="breaker"
               select="key('breakers',
                           concat($panel, ':', $row, ':', $col))" />
            <xsl:choose>
              <!-- if there is one, apply templates to get the table
                   cell -->
              <xsl:when test="$breaker">
                <xsl:apply-templates select="$breaker" />
              </xsl:when>
              <xsl:otherwise>
                <!-- find other breakers that start higher in the
                     column -->
                <xsl:variable name="column-breakers"
                  select="key('breakers-by-column',
                              concat($panel, ':', $col))
                            [@row &lt; $row]" />
                <!-- output an empty cell if there isn't one that
                     overlaps -->
                <xsl:if test="not($column-breakers
                                    [@row + @height > $row])">
                  <td />
                </xsl:if>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each>
        </xsl:for-each>
      </tr>
    </xsl:for-each>
  </table>
</xsl:template>

The template that gives the cell for the circuit breaker also needs to
be different. I don't know whether you still want it to contain the
value of the amps child of the circuit-breaker, but it needs to go on
to process the circuit-breaker-panel child to create the nested table:

<!-- template to give the cell for the circuit breaker -->
<xsl:template match="b:circuit-breaker">
  <td rowspan="{@height}">
    <xsl:value-of select="b:amps" />
    <!-- generate the nested table -->
    <xsl:apply-templates select="b:circuit-breaker-panel" />
  </td>
</xsl:template>

I hope that helps,

Jeni

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


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


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.