[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

RE: [xsl] converting empty nodes to col/rowspan values


Subject: RE: [xsl] converting empty nodes to col/rowspan values
From: "Jacoby, Peter R." <PJACOBY@xxxxxxxxxxxx>
Date: Tue, 13 Apr 2004 17:37:52 -0400

Michael,

Here is one solution to your problem.  I think it takes into account all of
your requirements.  It uses the preceding-sibling and following-sibling
access to look forward and backward to create the count.

The tricky part about this is the XPath, so I'll break down the one that
does the colspan as an explanation (the rowspan is the same idea just using
a different context node)

First we add one for itself:
1 + 

Then we need to count how many cells after it are empty:
count(following-sibling::cell[not(normalize-space(.))])

But we don't want the entire following-sibling axis, only those whose most
recent cell with any content is the current node.  To do this, we use the
trick of the union operator that tests node identity:
[count(current() | preceding-sibling::cell[normalize-space(.)][1]) = 1])

Put that all together and you have the XPath to create the colspan
attribute:
1 + count(following-sibling::cell[not(normalize-space(.))][count(current() |
preceding-sibling::cell[normalize-space(.)][1]) = 1])


The full stylesheet is below.  I have a feeling this could be done more
simply, but this is the way that makes the most sense to me.  Don't hesitate
to ask if you have any questions.

-Peter


<xsl:template match="table">
	<xsl:copy>
		<xsl:apply-templates select="row" />
	</xsl:copy>
</xsl:template>

<xsl:template match="row">
	<tr>
		<xsl:apply-templates select="cell[normalize-space(.)]" /> 
	</tr>
</xsl:template>

<xsl:template match="cell">
	<xsl:variable name="curPos" select="count(preceding-sibling::cell) +
1" />
	<td>
		<xsl:if
test="following-sibling::cell[1][not(normalize-space(.))]">
			<xsl:attribute name="colspan">
				<xsl:value-of select="1 +
count(following-sibling::cell[not(normalize-space(.))][count(current() |
preceding-sibling::cell[normalize-space(.)][1]) = 1])" />
			</xsl:attribute>
		</xsl:if>
		<xsl:if
test="../following-sibling::row[1]/cell[$curPos][not(normalize-space(.))]">
			<xsl:attribute name="rowspan">
				<xsl:value-of select="1 +
count(../following-sibling::row[cell[$curPos][not(normalize-space(.))]][coun
t(current()/parent::row |
preceding-sibling::row[cell[$curPos][normalize-space(.)]][1]) = 1])" />
			</xsl:attribute>
			
		</xsl:if>
		
		<xsl:value-of select="." />
	</td>
</xsl:template>



-----Original Message-----
From: Reece, Michael Clark [mailto:REECEM@xxxxxxxxxxxx]
Sent: Tuesday, April 13, 2004 4:40 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] converting empty nodes to col/rowspan values


I am try to format an html with colspan and rowspan values for empty nodes.
For example with:
 
<?xml version="1.0"?>
<table>
  <row>
    <cell>Sample Table</cell>
    <cell></cell>
    <cell></cell>
    <cell></cell>
    <cell></cell>
  </row>
  <row>
    <cell>A</cell>
    <cell>B</cell>
    <cell></cell>
    <cell>C</cell>
    <cell></cell>
  </row>
  <row>
    <cell></cell>
    <cell>D</cell>
    <cell>E</cell>
    <cell>F</cell>
    <cell>G</cell>
  </row>
  <row>
    <cell>H</cell>
    <cell>I</cell>
    <cell>J</cell>
    <cell>K</cell>
    <cell></cell>
  </row>
</table>
 
I want the first row to be:
  <tr><td colspan=5>Sample Table</td></tr>
And the second row to be:
  <tr><td rowspan=2>A</td><td colspan=2>B</td><td colspan=2>C</td></tr>
 
And so forth...
 
This is my template:
 
<?xml version='1.0'?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform
<http://www.w3.org/1999/XSL/Transform> ">
<xsl:template match="/">
      <html>
      <table border="1">
      <xsl:apply-templates/>
      </table>
      </html>
</xsl:template>
<xsl:template match="table">
      <xsl:for-each select="row">
            <tr><xsl:apply-templates/></tr>
      </xsl:for-each>
</xsl:template>
<xsl:template match="cell">
      <td><xsl:value-of select="."/></td>
</xsl:template>
</xsl:stylesheet>
 
I have tried many iterations but cannot figure this out.  Thanks...
 
Michael Reece


Current Thread
Keywords