Leo,
Looking at your data again, I see you have the harder case:
At 03:49 PM 2/12/2004, you wrote:
<data columnid="01" name="Actual"/>
<data columnid="11" name="Budget"/>
<data columnid="21" name="Fav/(Unfav) $"/>
<data columnid="31" name="Fav/(Unfav) %"/>
<data columnid="41" name="Actual"/>
<data columnid="51" name="Budget"/>
<data columnid="61" name="Fav/(Unfav) $"/>
<data columnid="71" name="Fav/(Unfav) %"/>
...so things get trickier.
Comparing this with the last template I posted:
<xsl:template match="data">
<xsl:variable name="thisname" select="@name"/>
<!-- first be sure we emit cells only for the first data element
with a given name -->
<xsl:if test="not($thisname = preceding-sibling::data/@name)">
<!-- the colspan is the count of data children of the parent with the
same name -->
<td colspan="{count(../data[@name = $thisname)}">
<xsl:apply-templates select="@name"/>
<!-- the built-in default template for attributes will emit its
value -->
</td>
</xsl:if>
</xsl:template>
There are two problems. First, we emit cells not for the first data element
with a given @name, but for any data element that doesn't have an
immediately preceding sibling with the same name. That's not so hard:
<xsl:if test="not($thisname = preceding-sibling::data[1]/@name)">
The trickier bit is counting the following siblings with the same name that
belong with this one. Really tricky, since the preceding-sibling and
following-sibling axes look at *all* the siblings. Extra points to any
XSLTer who can suggest how to do this count without a counter! (You're
right, we don't like counters.)
We can implement a counter as follows, using a recursive "tiptoe forward"
technique:
<xsl:template match="data" mode="gimme-count">
<xsl:parameter name="so-far" select="1"/>
<xsl:choose>
<xsl:when test="not(following-sibling::data[1]/@name = current()/@name)">
<!-- if our next data sibling doesn't have the same name, we're done -->
<xsl:value-of select="$so-far"/>
</xsl:when>
<xsl:otherwise>
<!-- if it does, we apply this same template to it, incrementing our
counter -->
<xsl:apply-templates select="following-sibling::data[1]"
mode="gimme-count">
<xsl:with-param name="so-far" select="$so-far + 1"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
You would invoke this by binding it to a variable in your template matching
the data element:
<xsl:variable name="count">
<xsl:apply-templates select="." mode="gimme-count"/>
</xsl:variable>
so, all together:
<xsl:template match="data">
<xsl:if test="not(@name = preceding-sibling::data[1]/@name)">
<xsl:variable name="count">
<xsl:apply-templates select="." mode="gimme-count"/>
</xsl:variable>
<td colspan="{$count}">
<xsl:apply-templates select="@name"/>
<!-- the built-in default template for attributes will emit its
value -->
</td>
</xsl:if>
</xsl:template>
Note: untested!
I hope it works ...
Cheers,
Wendell
======================================================================
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