Subject: Re: Grouping, Counting, and Sorting
From: "Thomas F. O'Connell" <tfo@xxxxxxxxxxxxxx>
Date: Fri, 04 Jun 2004 16:45:41 -0500
|
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() <= 100]" />
</table>
<xsl:for-each select="node[valid = 1 and position() mod 100=1 and position() >
100]">
<table cellpadding="0" cellspacing="0" border="0">
<xsl:apply-templates
select=".|following-sibling::node[valid = 1 and position() < 100]" />
</table>
</xsl:for-each>
<xsl:for-each select="node[not(valid = 1) and position() mod 100=1 and position() >
100]">
<table cellpadding="0" cellspacing="0" border="0">
<xsl:apply-templates
select=".|following-sibling::node[not(valid = 1) and position() < 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() <= 100]">
> <xsl:sort select="valid" />
> </xsl:apply-templates>
> </table>
>
> <xsl:for-each select="node[position() mod 100=1 and position() >
> 100]">
> <table cellpadding="0" cellspacing="0" border="0">
> <xsl:apply-templates
> select=".|following-sibling::node[position()<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
|