<!-- * http://cm.bell-labs.com/cm/cs/doc/76/tbl.ps.gz -->
<!-- * http://www.snake.net/software/troffcvt/tbl.html -->
- <!-- ==================================================================== -->
-
<xsl:template match="table|informaltable">
<!-- * We first process the table by applying templates to the whole -->
<!-- * thing; because we don’t override any of the <row>, <entry>, -->
<xsl:param name="contents">
<xsl:apply-templates/>
</xsl:param>
- <!-- * put first-pass transformed output into a node-set so that -->
+
+ <!-- * ============================================================== -->
+ <!-- * Get all the table contents and restructure them -->
+ <!-- * ============================================================== -->
+
+ <!-- * Put first-pass transformed output into a node-set so that -->
<!-- * we can walk through it again and do further transformation -->
<!-- * to generate correct markup for tbl(1) -->
<xsl:param name="table" select="exsl:node-set($contents)/table"/>
- <xsl:param name="total-rows" select="count($table//tr)"/>
+ <!-- * Flatten the structure into just a set of rows without any -->
+ <!-- * thead, tbody, or tfoot parents. And reorder the rows in -->
+ <!-- * such a way that the tfoot rows are at the end, -->
<xsl:variable name="rows-set">
<xsl:copy-of select="$table/thead/tr"/>
<xsl:copy-of select="$table/tbody/tr|$table/tr"/>
<xsl:copy-of select="$table/tfoot/tr"/>
</xsl:variable>
-
<xsl:variable name="rows" select="exsl:node-set($rows-set)"/>
- <xsl:variable name="cells">
+ <!-- * Now we flatten the structure further into just a set of -->
+ <!-- * cells without the row parents. This basically creates a -->
+ <!-- * copy of the entire contents of the original table, but -->
+ <!-- * restructured in such a way that we can more easily generate -->
+ <!-- * the corresponding roff markup we need to output. -->
+ <xsl:variable name="cells-set">
<xsl:call-template name="build.cell.list">
<xsl:with-param name="rows" select="$rows"/>
</xsl:call-template>
</xsl:variable>
+ <xsl:variable name="cells" select="exsl:node-set($cells-set)"/>
+
+ <!-- * ============================================================== -->
+ <!-- * Output the table. -->
+ <!-- * ============================================================== -->
<!-- * .TS = "Table Start" -->
<xsl:text>.TS </xsl:text>
<!-- * put box around table and between all cells -->
<xsl:text>allbox; </xsl:text>
- <!-- * create the table "format" spec, which tells tbl(1) how to -->
+ <!-- * Output the table "format" spec, which tells tbl(1) how to -->
<!-- * format each row and column -->
<xsl:call-template name="create.table.format">
- <xsl:with-param name="cells" select="exsl:node-set($cells)"/>
+ <xsl:with-param name="cells" select="$cells"/>
</xsl:call-template>
- <xsl:for-each select="$rows/tr">
- <xsl:call-template name="output.row">
- <xsl:with-param name="cells" select="exsl:node-set($cells)"/>
- <xsl:with-param name="row" select="position()"/>
- </xsl:call-template>
+ <!--* Output the formatted contents of each cell. -->
+ <xsl:for-each select="$cells/cell">
+ <xsl:call-template name="output.cell"/>
</xsl:for-each>
<xsl:text> </xsl:text>
<xsl:text>.sp </xsl:text>
</xsl:template>
- <!-- ==================================================================== -->
-
- <xsl:template name="output.row">
- <xsl:param name="cells"/>
- <xsl:param name="row"/>
- <xsl:param name="total-columns" select="count(td|th)"/>
- <xsl:text> </xsl:text>
- <!-- * embed a comment to show where each row starts -->
- <xsl:text>.\" ============================================== </xsl:text>
- <xsl:text>.\" ROW </xsl:text>
- <xsl:value-of select="$row"/>
- <xsl:text> </xsl:text>
- <xsl:for-each select="td|th">
- <xsl:call-template name="output.cell">
- <xsl:with-param name="cells" select="exsl:node-set($cells)"/>
- <xsl:with-param name="row" select="$row"/>
- <xsl:with-param name="slot" select="position()"/>
- <xsl:with-param name="total-columns" select="$total-columns"/>
- </xsl:call-template>
- </xsl:for-each>
- <xsl:text> </xsl:text>
- </xsl:template>
-
+ <!-- * ============================================================== -->
+ <!-- * Output the actual cell contents and roff row/cell markup -->
+ <!-- * ============================================================== -->
<xsl:template name="output.cell">
- <xsl:param name="cells"/>
- <xsl:param name="row"/>
- <xsl:param name="slot"/>
- <xsl:param name="total-columns"/>
- <xsl:param name="format-letter">
- <xsl:value-of
- select="$cells//cell[@row = $row and @slot = $slot]/@type"/>
- </xsl:param>
<xsl:choose>
- <xsl:when test="contains($format-letter,'^')">
- <xsl:text>	</xsl:text>
- <xsl:call-template name="output.cell">
- <xsl:with-param name="cells" select="exsl:node-set($cells)"/>
- <xsl:with-param name="row" select="$row"/>
- <xsl:with-param name="slot" select="$slot + 1"/>
- <xsl:with-param name="total-columns" select="$total-columns"/>
- </xsl:call-template>
+ <xsl:when test="preceding-sibling::cell[1]/@row != @row or
+ not(preceding-sibling::cell)">
+ <!-- * If the value of the row attribute on this cell is -->
+ <!-- * different from the value of that on the previous cell, it -->
+ <!-- * means we have a new row. So output a line break (as long -->
+ <!-- * as this isn’t the first cell in the table -->
+ <xsl:text> </xsl:text>
</xsl:when>
<xsl:otherwise>
- <!-- * the "T{" and "T}" stuff are delimiters to tell tbl(1) that -->
- <!-- * the delimited contents are "text blocks" that groff(1) -->
- <!-- * needs to process -->
- <xsl:text>T{ </xsl:text>
- <xsl:apply-templates/>
- <xsl:text> T}</xsl:text>
+ <!-- * Otherwise we are not at the start of a new row, so we -->
+ <!-- * output a tab character to delmit the contents of this -->
+ <!-- * cell from the contents of the next one. -->
+ <xsl:text>⌂</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="@type = '^'">
+ <!-- * If this is a dummy cell resulting from the presence of -->
+ <!-- * rowpan attribute in the source, it has no contents, so -->
+ <!-- * we need to handle it differently. -->
<xsl:if test="@colspan and @colspan > 1">
+ <!-- * If there is a colspan attribute on this dummy row, then -->
+ <!-- * we need to output a tab character for each column that -->
+ <!-- * it spans. -->
<xsl:call-template name="copy-string">
- <xsl:with-param name="string">	</xsl:with-param>
+ <xsl:with-param name="string">⌂</xsl:with-param>
<xsl:with-param name="count">
- <xsl:value-of select="@colspan"/>
+ <xsl:value-of select="@colspan - 1"/>
</xsl:with-param>
</xsl:call-template>
</xsl:if>
- <xsl:choose>
- <xsl:when test="$slot = $total-columns"/> <!-- do nothing -->
- <xsl:otherwise>
- <!-- * tbl(1) treats tab characters as delimiters between -->
- <!-- * cells; so we need to output a tab after each <td> except -->
- <!-- * the last one in the row -->
- <xsl:text>	</xsl:text>
- </xsl:otherwise>
- </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- * Otherwise, we have a "real" cell (not a dummy one) with -->
+ <!-- * contents that we need to output, -->
+ <!-- * -->
+ <!-- * The "T{" and "T}" stuff are delimiters to tell tbl(1) that -->
+ <!-- * the delimited contents are "text blocks" that groff(1) -->
+ <!-- * needs to process -->
+ <xsl:text>T{ </xsl:text>
+ <xsl:copy-of select="."/>
+ <xsl:text> T}</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
- <!-- ==================================================================== -->
-
+ <!-- * ============================================================== -->
+ <!-- * Build a restructured "cell list" copy of the table -->
+ <!-- * ============================================================== -->
<xsl:template name="build.cell.list">
<xsl:param name="rows"/>
- <xsl:variable name="cell-data-unsorted">
+ <xsl:param name="cell-data-unsorted">
+ <!-- * This gets all the "real" cells from the table along with -->
+ <!-- * "dummy" rows that we generate for keeping track of Rowspan -->
+ <!-- * instances. -->
<xsl:apply-templates select="$rows" mode="cell.list"/>
- </xsl:variable>
- <xsl:variable name="cell-data-sorted">
+ </xsl:param>
+ <xsl:param name="cell-data-sorted">
+ <!-- * Sort the cells so that the dummy cells get put where we -->
+ <!-- * need them in the structure. -->
<xsl:for-each select="exsl:node-set($cell-data-unsorted)/cell">
<xsl:sort select="@row"/>
<xsl:sort select="@slot"/>
<xsl:copy-of select="."/>
</xsl:for-each>
- </xsl:variable>
+ </xsl:param>
<xsl:copy-of select="$cell-data-sorted"/>
</xsl:template>
<xsl:param name="slot">
<xsl:value-of select="position()"/>
</xsl:param>
+ <!-- * For each real cell, create a Cell instance; its contents are -->
+ <!-- * the roff-formatted contents of the corresponding original table -->
+ <!-- * cell. -->
<cell row="{$row}" slot="{$slot}" type="l" colspan="{@colspan}">
<xsl:apply-templates/>
</cell>
<xsl:if test="@rowspan and @rowspan > 0">
- <xsl:call-template name="process.rowspan">
+ <!-- * For each instance of a rowspan attribute found, we create N -->
+ <!-- * dummy cells, where N is equal to the value of the rowspan. -->
+ <xsl:call-template name="create.dummy.cells">
<xsl:with-param name="row" select="$row + 1"/>
<xsl:with-param name="slot" select="$slot"/>
<xsl:with-param name="colspan" select="@colspan"/>
</xsl:if>
</xsl:template>
- <xsl:template name="process.rowspan">
+ <xsl:template name="create.dummy.cells">
<xsl:param name="row"/>
<xsl:param name="slot"/>
<xsl:param name="colspan"/>
<xsl:param name="rowspan"/>
<xsl:choose>
<xsl:when test="$rowspan > 1">
+ <!-- * Tail recurse until we have no more rowspans, creating an -->
+ <!-- * empty dummy cell each time -->
<cell row="{$row}" slot="{$slot}" type="^" colspan="{@colspan}"/>
- <xsl:call-template name="process.rowspan">
+ <xsl:call-template name="create.dummy.cells">
<xsl:with-param name="row" select="$row + 1"/>
<xsl:with-param name="slot" select="$slot"/>
<xsl:with-param name="colspan" select="$colspan"/>
</xsl:choose>
</xsl:template>
- <!-- ==================================================================== -->
+ <!-- * ============================================================== -->
+ <!-- * Build the "format section" for the table -->
+ <!-- * ============================================================== -->
<xsl:template name="create.table.format">
<xsl:param name="cells"/>
</xsl:template>
<xsl:template match="cell" mode="table.format">
- <xsl:if test="preceding-sibling::cell[1]/@row != @row">
- <xsl:text>
</xsl:text>
- </xsl:if>
+ <xsl:choose>
+ <xsl:when test="preceding-sibling::cell[1]/@row != @row">
+ <xsl:text>
</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:if test="position() != 1">
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:otherwise>
+ </xsl:choose>
<xsl:choose>
<xsl:when test="@type = '^'">
<xsl:text>^</xsl:text>
<xsl:template name="process.colspan">
<xsl:param name="colspan"/>
<xsl:param name="type"/>
+ <xsl:text> </xsl:text>
<xsl:choose>
<xsl:when test="$type = '^'">
<xsl:text>^</xsl:text>