xsl-list
[Top] [All Lists]

Re: Grouping, Counting, and Sorting

2004-06-04 14:45:41
Okay. I've reworked my original approach somewhat and am closer to a
satisfactory solution, but I'm still looking for a little deeper
understanding of a few concepts and, even better, a more complete
solution.

So, now, based on the same example XML provided below, I'm doing this:

<table>
        <th>Header</th>
        <xsl:apply-templates select="node[valid = 1 and position() &lt;= 100]" 
/>
</table>

<xsl:for-each select="node[valid = 1 and position() mod 100=1 and position() 
&gt;
100]">
        <table cellpadding="0" cellspacing="0" border="0">
        <xsl:apply-templates
select=".|following-sibling::node[valid = 1 and position() &lt; 100]" />
        </table>
</xsl:for-each>

<xsl:for-each select="node[not(valid = 1) and position() mod 100=1 and 
position() &gt;
100]">
        <table cellpadding="0" cellspacing="0" border="0">
        <xsl:apply-templates
select=".|following-sibling::node[not(valid = 1) and position() &lt; 100]" />
        </table>
</xsl:for-each>

<xsl:template match="node[valid=1]">
        <tr>
                <td class="valid">
                        <xsl:variable name="number">
                                <xsl:number 
value="count(preceding-sibling::output)+1" level="any"
format="1" />
                        </xsl:variable>
                        <xsl:value-of select="$number" />.
                        <xsl:value-of select="data" />
                </td>
        </tr>
</xsl:template>

<xsl:template match="node[not(valid=1)]">
        <tr>
                <td class="invalid">
                        <xsl:variable name="number">
                                <xsl:number 
value="count(preceding-sibling::output)+1" level="any"
format="1" />
                        </xsl:variable>
                        <xsl:value-of select="$number" />.
                        <xsl:value-of select="data" />
                </td>
        </tr>
</xsl:template>

The main difference here is that I'm doing selective template
application rather than sorting.

What I'm discovering, though, is that once all nodes that have a valid
node are output, my current method skips any nodes that are not valid
until the first complete set of 100 (I.e., where mod 100 = 1).

E.g., If I have 150 valid nodes and then 150 invalid nodes, this
stylesheet seems to output all 150 valid nodes, skips 50 invalid nodes
and then prints the final 100 invalid nodes.

I would've thought I could've overcome this by including something along
the lines of:

<xsl:for-each select="node[not(valid = 1) and position() =
count(node[valid = 1]) + 1]">
        <table cellpadding="0" cellspacing="0" border="0">
                <xsl:apply-templates 
select=".|following-sibling::node[not(valid = 1)
and not(position() mod 100 = 1)]" />
        </table>
</xsl:for-each>

As I understand the grouping, I would've thought this would start with
the node whose position was immediately after the last valid node and
then iterate until it hit a node with mod 100 = 1, but it doesn't seem
to be working.

Is my interpretation of how this grouping strategy works correct?

What can I do to output these interim nodes successfully (and most
appropriately)?

Thanks!

-tfo

I have some XML that looks like this:

<data>
      <node>
              <data>data</data>
              <valid>1</valid>
      </node>
      <node>
              <data>data</data>
      </node>
</data>

There can be any number and sequence of nodes. Some nodes are flagged
with a validity node.

I'm trying to transform it to HTML using XSL. Here are the conditions:

1. Group it by 100.
2. Sort it by whether or not the nodes have a "valid" node (descending
from valid to non-valid, which is just a binary existence check).
3. The output needs to be numbered sequentially.
4. The output needs to be formatted differently based on whether a
"valid" node is encountered.
5. The first chunk of the output needs to include a header.

Basically, I'm breaking it up into 100-row HTML tables.

Here's my current approach:

<table>
      <th>Header</th>
<xsl:apply-templates select="node[position() &lt;= 100]">
      <xsl:sort select="valid" />
</xsl:apply-templates>
</table>

<xsl:for-each select="node[position() mod 100=1 and position() &gt;
100]">
      <table cellpadding="0" cellspacing="0" border="0">
      <xsl:apply-templates
select=".|following-sibling::node[position()&lt;100]">
              <xsl:sort select="valid" />
      </xsl:apply-templates>
      </table>
</xsl:for-each>

<xsl:template match="node[valid=1]">
      <tr>
              <td class="valid">
                      <xsl:variable name="number">
                              <xsl:number 
value="count(preceding-sibling::*)+1" level="any"
format="1" />
                      </xsl:variable>
                      <xsl:value-of select="$number" />.
                      <xsl:value-of select="data" />
              </td>
      </tr>
</xsl:template>

<xsl:template match="node[not(valid=1)]">
      <tr>
              <td class="invalid">
                      <xsl:variable name="number">
                              <xsl:number 
value="count(preceding-sibling::*)+1" level="any"
format="1" />
                      </xsl:variable>
                      <xsl:value-of select="$number" />.
                      <xsl:value-of select="data" />
              </td>
      </tr>
</xsl:template>

Unfortunately, the result of this transformation neither sorts the
output, nor numbers the output sequentially. The grouping works, but I
was under the impression that the sort would apply to the nodes before
their positions were considered. What I understand less is why the sort
does not seem actually to order the nodes correctly in the output.

Any help is much appreciated.

Thanks!

-tfo



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