RE: [xsl] Normalize / Simplify HTML-Tables with row-span / col-span

Subject: RE: [xsl] Normalize / Simplify HTML-Tables with row-span / col-span
From: "Andrew Welch" <AWelch@xxxxxxxxxxxxxxx>
Date: Tue, 10 Feb 2004 17:02:34 -0000

> Hi,
> 
> I'm looking for an XSL-Stylesheet which normalizes complex 
> html-tables with col-span row-span to simple tables.
> 
> for example
>  ___________
> |  |__|_____|
> |__|__|__|__|
> 
> to
>  ___________
> |__|__|__|__|
> |__|__|__|__|
> 
> I think someone had a similar problem two years ago, but he 
> got no solution. Subject was: Tranforming a table with 
> colspan and rowspan attributes to another more complex table


This is quite tricky... The rowspan causes most of the problems :)

Ive got a solution here that works first by sorting out the colspans,
then by processing the RTF produced from that vertically.  The second
stage produces lots of <td>'s in the form:

<td row="1" col="1">.</td>
<td row="2" col="2">.</td>
<td row="1" col="2">.</td>

The final stage then outputs the table grouping the td's by row and
sorting by column number.

Apologies for the lack of comments/structure in the code, but it should
be pretty obvious from the variables copied to the output whats going
on.

So for this input:

<table border="1">
  <tr>
    <td colspan="2">.</td>
    <td>.</td>
    <td rowspan="3">.</td>
  </tr>
  <tr>
    <td>.</td>
    <td>.</td>
    <td rowspan="2">.</td>
  </tr>
  <tr>
    <td>.</td>
    <td>.</td>
  </tr>
</table>

With this stylesheet:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

<xsl:variable name="table_with_no_colspans">
    <xsl:apply-templates mode="colspan"/>
</xsl:variable>

<xsl:variable name="table_with_no_rowspan">
  <xsl:for-each select="$table_with_no_colspans">
    <xsl:apply-templates mode="rowspan"/>
  </xsl:for-each>
</xsl:variable>

<xsl:template match="@*|*" mode="colspan">
  <xsl:copy>
    <xsl:apply-templates select="@*|*" mode="colspan"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="td" mode="colspan">
  <xsl:choose>
    <xsl:when test="@colspan">
      <xsl:call-template name="give_me_tds">
        <xsl:with-param name="number-of-tds" select="@colspan"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <td><xsl:copy-of select="@*"/>.</td>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="give_me_tds">
  <xsl:param name="number-of-tds"/>
  <xsl:choose>
    <xsl:when test="$number-of-tds &gt; 1">
      <td>.</td>
      <xsl:call-template name="give_me_tds">
        <xsl:with-param name="number-of-tds" select="$number-of-tds -
1"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <td>.</td>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="/">
  <div>
    <AAAAA><xsl:copy-of select="."/></AAAAA>
    <XXXXX><xsl:copy-of select="$table_with_no_colspans"/></XXXXX>
    <YYYYY><xsl:copy-of select="$table_with_no_rowspan"/></YYYYY>
    <table border="1">
      <xsl:for-each select="/table/tr">
        <tr>
          <xsl:variable name="pos" select="position()"/>
          <xsl:apply-templates select="$table_with_no_rowspan/td[@row =
$pos]" mode="final">
            <xsl:sort select="@col"/>
          </xsl:apply-templates>
        </tr>
      </xsl:for-each>
    </table>
  </div>
</xsl:template>

<xsl:template match="td" mode="final">
  <xsl:copy-of select="."/>
</xsl:template>


<xsl:template match="tr" mode="rowspan">
  <xsl:apply-templates mode="rowspan">
    <xsl:with-param name="rownum" select="position()"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="td" mode="rowspan">
  <xsl:param name="rownum"/>
  <xsl:choose>
    <xsl:when test="@rowspan">
      <xsl:call-template name="rowspan_tds">
        <xsl:with-param name="rowspan" select="@rowspan"/>
        <xsl:with-param name="rownum" select="$rownum"/>
        <xsl:with-param name="colnum"
select="count(preceding-sibling::td|.)"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <td row="{$rownum}" col="{count(preceding-sibling::td|.)}">.</td>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template name="rowspan_tds">
  <xsl:param name="rowspan"/>
  <xsl:param name="rownum"/>
  <xsl:param name="colnum"/>
  <xsl:choose>
    <xsl:when test="$rowspan &gt; 1">
      <td row="{$rownum}" col="{$colnum}">.</td>
      <xsl:call-template name="rowspan_tds">
        <xsl:with-param name="rowspan" select="$rowspan - 1"/>
        <xsl:with-param name="rownum" select="$rownum + 1"/>
        <xsl:with-param name="colnum" select="$colnum"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <td row="{$rownum}" col="{$colnum}">.</td>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
</xsl:stylesheet>

Produces this output:

<?xml version="1.0" encoding="UTF-8"?>
<div>
	<AAAAA>
		<table border="1">
			<tr>
				<td colspan="2">.</td>
				<td>.</td>
				<td rowspan="3">.</td>
			</tr>
			<tr>
				<td>.</td>
				<td>.</td>
				<td rowspan="2">.</td>
			</tr>
			<tr>
				<td>.</td>
				<td>.</td>
			</tr>
		</table>
	</AAAAA>
	<XXXXX>
		<table border="1">
			<tr>
				<td>.</td>
				<td>.</td>
				<td>.</td>
				<td rowspan="3">.</td>
			</tr>
			<tr>
				<td>.</td>
				<td>.</td>
				<td rowspan="2">.</td>
			</tr>
			<tr>
				<td>.</td>
				<td>.</td>
			</tr>
		</table>
	</XXXXX>
	<YYYYY>
		<td row="1" col="1">.</td>
		<td row="1" col="2">.</td>
		<td row="1" col="3">.</td>
		<td row="1" col="4">.</td>
		<td row="2" col="4">.</td>
		<td row="3" col="4">.</td>
		<td row="2" col="1">.</td>
		<td row="2" col="2">.</td>
		<td row="2" col="3">.</td>
		<td row="3" col="3">.</td>
		<td row="3" col="1">.</td>
		<td row="3" col="2">.</td>
	</YYYYY>
	<table border="1">
		<tr>
			<td row="1" col="1">.</td>
			<td row="1" col="2">.</td>
			<td row="1" col="3">.</td>
			<td row="1" col="4">.</td>
		</tr>
		<tr>
			<td row="2" col="1">.</td>
			<td row="2" col="2">.</td>
			<td row="2" col="3">.</td>
			<td row="2" col="4">.</td>
		</tr>
		<tr>
			<td row="3" col="1">.</td>
			<td row="3" col="2">.</td>
			<td row="3" col="3">.</td>
			<td row="3" col="4">.</td>
		</tr>
	</table>
</div>


cheers
andrew  

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


Current Thread