634 lines
28 KiB
XML
634 lines
28 KiB
XML
|
<?xml version="1.0"?>
|
||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||
|
xmlns:exsl="http://exslt.org/common"
|
||
|
exclude-result-prefixes="exsl"
|
||
|
version='1.0'>
|
||
|
|
||
|
<!-- ********************************************************************
|
||
|
$Id: table.xsl 8400 2009-04-08 07:44:54Z bobstayton $
|
||
|
********************************************************************
|
||
|
|
||
|
This file is part of the XSL DocBook Stylesheet distribution.
|
||
|
See ../README or http://docbook.sf.net/release/xsl/current/ for
|
||
|
copyright and other information.
|
||
|
|
||
|
******************************************************************** -->
|
||
|
<!--
|
||
|
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
|
||
|
<xsl:param name="tbl.font.title">B</xsl:param>
|
||
|
<xsl:param name="tbl.font.headings">B</xsl:param>
|
||
|
-->
|
||
|
<xsl:param name="tbl.running.header.from.thead" select="0"/>
|
||
|
<xsl:param name="tbl.column.separator.char">:</xsl:param>
|
||
|
|
||
|
<!-- ==================================================================== -->
|
||
|
|
||
|
<!-- * This stylesheet transforms DocBook and HTML table source into -->
|
||
|
<!-- * tbl(1) markup. -->
|
||
|
<!-- * -->
|
||
|
<!-- * For details on tbl(1) and its markup syntaxt, see M. E. Lesk,-->
|
||
|
<!-- * "Tbl - A Program to Format Tables": -->
|
||
|
<!-- * -->
|
||
|
<!-- * http://cm.bell-labs.com/7thEdMan/vol2/tbl -->
|
||
|
<!-- * 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" mode="to.tbl">
|
||
|
<!--* the "source" param is an optional param; it can be any -->
|
||
|
<!--* string you want to use that gives some indication of the -->
|
||
|
<!--* source context for a table; it gets passed down to the named -->
|
||
|
<!--* templates that do the actual table processing; this -->
|
||
|
<!--* stylesheet currently uses the "source" information for -->
|
||
|
<!--* logging purposes -->
|
||
|
<xsl:param name="source"/>
|
||
|
<xsl:param name="title">
|
||
|
<xsl:if test="local-name(.) = 'table'">
|
||
|
<xsl:apply-templates select="." mode="object.title.markup.textonly"/>
|
||
|
</xsl:if>
|
||
|
</xsl:param>
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Set global table parameters -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * First, set a few parameters based on attributes specified in -->
|
||
|
<!-- * the table source. -->
|
||
|
<xsl:param name="allbox">
|
||
|
<xsl:if test="not(@frame = 'none') and not(@border = '0')">
|
||
|
<!-- * By default, put a box around table and between all cells, -->
|
||
|
<!-- * unless frame="none" or border="0" -->
|
||
|
<xsl:text>allbox </xsl:text>
|
||
|
</xsl:if>
|
||
|
</xsl:param>
|
||
|
<xsl:param name="center">
|
||
|
<!-- * If align="center", center the table. Otherwise, tbl(1) -->
|
||
|
<!-- * left-aligns it by default; note that there is no support -->
|
||
|
<!-- * in tbl(1) for specifying right alignment. -->
|
||
|
<xsl:if test="@align = 'center' or tgroup/@align = 'center'">
|
||
|
<xsl:text>center </xsl:text>
|
||
|
</xsl:if>
|
||
|
</xsl:param>
|
||
|
<xsl:param name="expand">
|
||
|
<!-- * If pgwide="1" or width="100%", then "expand" the table by -->
|
||
|
<!-- * making it "as wide as the current line length" (to quote -->
|
||
|
<!-- * the tbl(1) guide). -->
|
||
|
<xsl:if test="@pgwide = '1' or @width = '100%'">
|
||
|
<xsl:text>expand </xsl:text>
|
||
|
</xsl:if>
|
||
|
</xsl:param>
|
||
|
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Convert table to HTML -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Process the table by applying the HTML templates from the -->
|
||
|
<!-- * DocBook XSL stylesheets to the whole thing; because we don't -->
|
||
|
<!-- * override any of the <row>, <entry>, <tr>, <td>, etc. templates, -->
|
||
|
<!-- * the templates in the HTML stylesheets (which we import) are -->
|
||
|
<!-- * used to process those. -->
|
||
|
<xsl:param name="html-table-output">
|
||
|
<xsl:choose>
|
||
|
<xsl:when test=".//tr">
|
||
|
<!-- * If this table has a TR child, it means that it's an -->
|
||
|
<!-- * HTML table in the DocBook source, instead of a CALS -->
|
||
|
<!-- * table. So we just copy it as-is, while wrapping it -->
|
||
|
<!-- * in an element with same name as its original parent. -->
|
||
|
<xsl:for-each select="descendant-or-self::table|descendant-or-self::informaltable">
|
||
|
<xsl:element name="{local-name(..)}">
|
||
|
<table>
|
||
|
<xsl:copy-of select="*"/>
|
||
|
</table>
|
||
|
</xsl:element>
|
||
|
</xsl:for-each>
|
||
|
</xsl:when>
|
||
|
<xsl:otherwise>
|
||
|
<!-- * Otherwise, this is a CALS table in the DocBook source, -->
|
||
|
<!-- * so we need to apply the templates in the HTML -->
|
||
|
<!-- * stylesheets to transform it into HTML before we do -->
|
||
|
<!-- * any further processing of it. -->
|
||
|
<xsl:apply-templates/>
|
||
|
</xsl:otherwise>
|
||
|
</xsl:choose>
|
||
|
</xsl:param>
|
||
|
<xsl:param name="contents" select="exsl:node-set($html-table-output)"/>
|
||
|
|
||
|
<!-- ==================================================================== -->
|
||
|
<!-- * Output the table -->
|
||
|
<!-- ==================================================================== -->
|
||
|
<!-- * -->
|
||
|
<!-- * This is the "driver" part of the code; it calls a series of named
|
||
|
* templates (further below) to generate the actual tbl(1) markup, -->
|
||
|
<!-- * including the optional "options line", required "format section", -->
|
||
|
<!-- * and then the actual contents of the table. -->
|
||
|
<!-- * -->
|
||
|
<!-- ==================================================================== -->
|
||
|
|
||
|
<xsl:for-each select="$contents//table">
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Output table title -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<xsl:if test="$title != '' or parent::td">
|
||
|
<xsl:text>.sp </xsl:text>
|
||
|
<xsl:call-template name="pinch.together"/>
|
||
|
<xsl:text>.</xsl:text>
|
||
|
<xsl:value-of select="$tbl.font.title"/>
|
||
|
<xsl:text> </xsl:text>
|
||
|
<xsl:if test="parent::td">
|
||
|
<xsl:text>*[nested▀table]</xsl:text>
|
||
|
</xsl:if>
|
||
|
<xsl:value-of select="normalize-space($title)"/>
|
||
|
<xsl:text> </xsl:text>
|
||
|
</xsl:if>
|
||
|
|
||
|
<!-- * mark the start of the table -->
|
||
|
<!-- * "TS" = "table start" -->
|
||
|
<xsl:text>.TS</xsl:text>
|
||
|
<xsl:if test="thead and $tbl.running.header.from.thead">
|
||
|
<!-- * H = "has header" -->
|
||
|
<xsl:text> H</xsl:text>
|
||
|
</xsl:if>
|
||
|
<xsl:text> </xsl:text>
|
||
|
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Output "options line" -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<xsl:variable name="options-line">
|
||
|
<xsl:value-of select="$allbox"/>
|
||
|
<xsl:value-of select="$center"/>
|
||
|
<xsl:value-of select="$expand"/>
|
||
|
<xsl:text>tab(</xsl:text>
|
||
|
<xsl:value-of select="$tbl.column.separator.char"/>
|
||
|
<xsl:text>)</xsl:text>
|
||
|
</xsl:variable>
|
||
|
<xsl:if test="normalize-space($options-line) != ''">
|
||
|
<xsl:value-of select="normalize-space($options-line)"/>
|
||
|
<xsl:text>; </xsl:text>
|
||
|
</xsl:if>
|
||
|
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Output table header rows -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<xsl:if test="thead">
|
||
|
<xsl:call-template name="output.rows">
|
||
|
<xsl:with-param name="rows" select="thead/tr"/>
|
||
|
</xsl:call-template>
|
||
|
<xsl:text> </xsl:text>
|
||
|
|
||
|
<!-- * mark the end of table-header rows -->
|
||
|
<xsl:choose>
|
||
|
<xsl:when test="$tbl.running.header.from.thead">
|
||
|
<!-- * "TH" = "table header end" -->
|
||
|
<xsl:text>.TH </xsl:text>
|
||
|
</xsl:when>
|
||
|
<xsl:otherwise>
|
||
|
<!-- * "T&" = "table continuation" and is meant just as a kind -->
|
||
|
<!-- * of convenience macro and is sorta equivalent to a "TE" -->
|
||
|
<!-- * (table end) followed immediately by a "TS" (table start); -->
|
||
|
<!-- * in this case, it marks the end of a table "subsection" -->
|
||
|
<!-- * with header rows, and the start of a subsection with body -->
|
||
|
<!-- * rows. It's necessary to output it here because the "TH" -->
|
||
|
<!-- * macro is not being output, so there's otherwise no way -->
|
||
|
<!-- * for tbl(1) to know we have the table "sectioned". -->
|
||
|
<xsl:text>.T& </xsl:text>
|
||
|
</xsl:otherwise>
|
||
|
</xsl:choose>
|
||
|
</xsl:if>
|
||
|
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Output table body rows -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * First create node set with all non-thead rows (tbody+tfoot), -->
|
||
|
<!-- * but reordered with the tfoot rows at the end of the node set -->
|
||
|
<xsl:variable name="rows-set">
|
||
|
<xsl:copy-of select="tbody/tr|tr"/>
|
||
|
<xsl:copy-of select="tfoot/tr"/>
|
||
|
</xsl:variable>
|
||
|
<xsl:call-template name="output.rows">
|
||
|
<xsl:with-param name="source" select="$source"/>
|
||
|
<xsl:with-param name="rows" select="exsl:node-set($rows-set)"/>
|
||
|
</xsl:call-template>
|
||
|
|
||
|
<!-- * mark the end of the table -->
|
||
|
<xsl:text> </xsl:text>
|
||
|
<!-- * .TE = "Table End" -->
|
||
|
<xsl:text>.TE </xsl:text>
|
||
|
<!-- * put a blank line of space below the table -->
|
||
|
<xsl:text>.sp 1 </xsl:text>
|
||
|
</xsl:for-each>
|
||
|
</xsl:template>
|
||
|
|
||
|
<!-- ==================================================================== -->
|
||
|
<!-- * named templates -->
|
||
|
<!-- ==================================================================== -->
|
||
|
<!-- * -->
|
||
|
<!-- * All of the following are named templates that get called directly -->
|
||
|
<!-- * or indirectly by the main "driver" part of the code (above) -->
|
||
|
<!-- * -->
|
||
|
<!-- ==================================================================== -->
|
||
|
|
||
|
<xsl:template name="output.rows">
|
||
|
<xsl:param name="source"/>
|
||
|
<xsl:param name="rows"/>
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Flatten row set into simple list of 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 tbl(1) markup we need to output. -->
|
||
|
<xsl:variable name="cells-list">
|
||
|
<xsl:call-template name="build.cell.list">
|
||
|
<xsl:with-param name="source" select="$source"/>
|
||
|
<xsl:with-param name="rows" select="$rows"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:variable>
|
||
|
<xsl:variable name="cells" select="exsl:node-set($cells-list)"/>
|
||
|
|
||
|
<!-- * Output the table "format section", which tells tbl(1) how to -->
|
||
|
<!-- * format each row and column -->
|
||
|
<xsl:call-template name="create.table.format">
|
||
|
<xsl:with-param name="cells" select="$cells"/>
|
||
|
</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:template>
|
||
|
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Output the tbl(1)-formatted contents of each cell. -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<xsl:template name="output.cell">
|
||
|
<xsl:choose>
|
||
|
<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>
|
||
|
<!-- * Otherwise we are not at the start of a new row, so we -->
|
||
|
<!-- * output a tab character to delimit the contents of this -->
|
||
|
<!-- * cell from the contents of the next one. -->
|
||
|
<xsl:value-of select="$tbl.column.separator.char"/>
|
||
|
</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" select="$tbl.column.separator.char"/>
|
||
|
<xsl:with-param name="count">
|
||
|
<xsl:value-of select="@colspan - 1"/>
|
||
|
</xsl:with-param>
|
||
|
</xsl:call-template>
|
||
|
</xsl:if>
|
||
|
</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 roff -->
|
||
|
<!-- * 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 entire table -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<xsl:template name="build.cell.list">
|
||
|
<xsl:param name="source"/>
|
||
|
<xsl:param name="rows"/>
|
||
|
<xsl:param name="cell-data-unsorted">
|
||
|
<!-- * This param collects 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:with-param name="source" select="$source"/>
|
||
|
</xsl:apply-templates>
|
||
|
</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. Note that we need to specify -->
|
||
|
<!-- * data-type="number" here because the default sorting method -->
|
||
|
<!-- * for xsl:sort is "text" (alphabetical). -->
|
||
|
<xsl:for-each select="exsl:node-set($cell-data-unsorted)/cell">
|
||
|
<xsl:sort select="@row" data-type="number"/>
|
||
|
<xsl:sort select="@slot" data-type="number"/>
|
||
|
<xsl:copy-of select="."/>
|
||
|
</xsl:for-each>
|
||
|
</xsl:param>
|
||
|
<!-- * Return the sorted cell list -->
|
||
|
<xsl:copy-of select="$cell-data-sorted"/>
|
||
|
</xsl:template>
|
||
|
|
||
|
<xsl:template match="tr" mode="cell.list">
|
||
|
<xsl:param name="source"/>
|
||
|
<xsl:variable name="row">
|
||
|
<xsl:value-of select="count(preceding-sibling::tr) + 1"/>
|
||
|
</xsl:variable>
|
||
|
<xsl:for-each select="td|th">
|
||
|
<xsl:call-template name="cell">
|
||
|
<xsl:with-param name="source" select="$source"/>
|
||
|
<xsl:with-param name="row" select="$row"/>
|
||
|
<!-- * pass on the element name so we can select the appropriate -->
|
||
|
<!-- * roff font for styling the cell contents -->
|
||
|
<xsl:with-param name="class" select="name(.)"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:for-each>
|
||
|
</xsl:template>
|
||
|
|
||
|
<xsl:template name="cell">
|
||
|
<xsl:param name="source"/>
|
||
|
<xsl:param name="row"/>
|
||
|
<xsl:param name="class"/>
|
||
|
<xsl:param name="slot">
|
||
|
<!-- * The "slot" is the horizontal position of this cell (usually -->
|
||
|
<!-- * just the same as its column, but not so when it is preceded -->
|
||
|
<!-- * by cells that have colspans or cells in preceding rows that -->
|
||
|
<!-- * that have rowspans). -->
|
||
|
<xsl:value-of select="position()"/>
|
||
|
</xsl:param>
|
||
|
<!-- * For each real TD cell, create a Cell instance; contents will -->
|
||
|
<!-- * be the roff-formatted contents of its original table cell. -->
|
||
|
<cell type=""
|
||
|
row="{$row}"
|
||
|
slot="{$slot}"
|
||
|
class="{$class}"
|
||
|
colspan="{@colspan}"
|
||
|
align="{@align}"
|
||
|
valign="{@valign}"
|
||
|
>
|
||
|
<xsl:choose>
|
||
|
<xsl:when test=".//tr">
|
||
|
<xsl:call-template name="log.message">
|
||
|
<xsl:with-param name="level">Warn</xsl:with-param>
|
||
|
<xsl:with-param name="source" select="$source"/>
|
||
|
<xsl:with-param name="context-desc">tbl convert</xsl:with-param>
|
||
|
<xsl:with-param name="message">
|
||
|
<xsl:text>Extracted a nested table</xsl:text>
|
||
|
</xsl:with-param>
|
||
|
</xsl:call-template>
|
||
|
<xsl:text>[\fInested▀table\fR]* </xsl:text>
|
||
|
</xsl:when>
|
||
|
<xsl:otherwise>
|
||
|
<!-- * Apply templates to the child contents of this cell, to -->
|
||
|
<!-- * transform them into marked-up roff. -->
|
||
|
<xsl:variable name="contents">
|
||
|
<xsl:apply-templates/>
|
||
|
</xsl:variable>
|
||
|
<!-- * We now have the contents in roff (plain-text) form, -->
|
||
|
<!-- * but we may also still have unnecessary whitespace at -->
|
||
|
<!-- * the beginning and/or end of it, so trim it off. -->
|
||
|
<xsl:call-template name="trim.text">
|
||
|
<xsl:with-param name="contents" select="$contents"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:otherwise>
|
||
|
</xsl:choose>
|
||
|
</cell>
|
||
|
|
||
|
<!-- * For each instance of a rowspan attribute found, we create N -->
|
||
|
<!-- * dummy cells, where N is equal to the value of the rowspan. -->
|
||
|
<xsl:if test="@rowspan and @rowspan > 0">
|
||
|
<!-- * If this cell is preceded in the same row by cells that -->
|
||
|
<!-- * have colspan attributes, then we need to calculate the -->
|
||
|
<!-- * "offset" caused by those colspan instances; the formula -->
|
||
|
<!-- * is to (1) check for all the preceding cells that have -->
|
||
|
<!-- * colspan attributes that are not empty and which have a -->
|
||
|
<!-- * value greater than 1, then (2) take the sum of the values -->
|
||
|
<!-- * of all those colspan attributes, and subtract from that -->
|
||
|
<!-- * the number of such colspan instances found. -->
|
||
|
<xsl:variable name="colspan-offset">
|
||
|
<xsl:value-of
|
||
|
select="sum(preceding-sibling::td[@colspan != ''
|
||
|
and @colspan > 1]/@colspan) -
|
||
|
count(preceding-sibling::td[@colspan != ''
|
||
|
and @colspan > 1]/@colspan)"/>
|
||
|
</xsl:variable>
|
||
|
<xsl:call-template name="create.dummy.cells">
|
||
|
<xsl:with-param name="row" select="$row + 1"/>
|
||
|
<!-- * The slot value on each dummy cell must be offset by the -->
|
||
|
<!-- * value of $colspan-offset to adjust for preceding colpans -->
|
||
|
<xsl:with-param name="slot" select="$slot + $colspan-offset"/>
|
||
|
<xsl:with-param name="colspan" select="@colspan"/>
|
||
|
<xsl:with-param name="rowspan" select="@rowspan"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:if>
|
||
|
</xsl:template>
|
||
|
|
||
|
<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. The type value, '^' -->
|
||
|
<!-- * is the marker that tbl(1) uses to indicate a -->
|
||
|
<!-- * "vertically spanned heading". -->
|
||
|
<cell row="{$row}" slot="{$slot}" type="^" colspan="{@colspan}"/>
|
||
|
<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:with-param name="rowspan" select="$rowspan - 1"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:when>
|
||
|
</xsl:choose>
|
||
|
</xsl:template>
|
||
|
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Build the "format section" for the table -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * Description from the tbl(1) guide: -->
|
||
|
<!-- * -->
|
||
|
<!-- * "The format section of the table specifies the layout of the -->
|
||
|
<!-- * columns. Each line in this section corresponds to one line of -->
|
||
|
<!-- * the table... and each line contains a key-letter for each -->
|
||
|
<!-- * column of the table." -->
|
||
|
<xsl:template name="create.table.format">
|
||
|
<xsl:param name="cells"/>
|
||
|
<xsl:apply-templates mode="table.format" select="$cells"/>
|
||
|
<!-- * last line of table format section must end with a dot -->
|
||
|
<xsl:text>.</xsl:text>
|
||
|
</xsl:template>
|
||
|
|
||
|
<xsl:template match="cell" mode="table.format">
|
||
|
<xsl:choose>
|
||
|
<xsl:when test="preceding-sibling::cell[1]/@row != @row">
|
||
|
<!-- * 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. -->
|
||
|
<xsl:text>
</xsl:text>
|
||
|
</xsl:when>
|
||
|
<xsl:otherwise>
|
||
|
<!-- * If this isn't the first cell, output a space before it to -->
|
||
|
<!-- * separate it from the preceding key letter. -->
|
||
|
<xsl:if test="position() != 1">
|
||
|
<xsl:text> </xsl:text>
|
||
|
</xsl:if>
|
||
|
</xsl:otherwise>
|
||
|
</xsl:choose>
|
||
|
<!-- * Select an appropriate "alignment" key letter based on this -->
|
||
|
<!-- * cell's attributes. -->
|
||
|
<xsl:choose>
|
||
|
<xsl:when test="@type = '^'">
|
||
|
<xsl:text>^</xsl:text>
|
||
|
</xsl:when>
|
||
|
<xsl:when test="@align = 'center'">
|
||
|
<xsl:text>c</xsl:text>
|
||
|
</xsl:when>
|
||
|
<xsl:when test="@align = 'right'">
|
||
|
<xsl:text>r</xsl:text>
|
||
|
</xsl:when>
|
||
|
<xsl:when test="@align = 'char'">
|
||
|
<xsl:text>n</xsl:text>
|
||
|
</xsl:when>
|
||
|
<xsl:otherwise>
|
||
|
<!-- * Default to left alignment. -->
|
||
|
<xsl:text>l</xsl:text>
|
||
|
</xsl:otherwise>
|
||
|
</xsl:choose>
|
||
|
<!-- * By default, tbl(1) vertically centers cell contents within -->
|
||
|
<!-- * their cells; the "t" key latter tells it to top-align the -->
|
||
|
<!-- * contents instead. Note that tbl(1) has no options for -->
|
||
|
<!-- * bottom or baseline alignment. -->
|
||
|
<xsl:if test="@valign = 'top'">
|
||
|
<xsl:text>t</xsl:text>
|
||
|
</xsl:if>
|
||
|
<xsl:if test="@class = 'th'">
|
||
|
<!-- * If this is a heading row, generate a font indicator (B or I), -->
|
||
|
<!-- * or if the value of $tbl.font.headings is empty, nothing. -->
|
||
|
<xsl:value-of select="$tbl.font.headings"/>
|
||
|
</xsl:if>
|
||
|
<!-- * We only need to deal with colspans whose value is greater -->
|
||
|
<!-- * than one (a colspan="1" is the same as having no colspan -->
|
||
|
<!-- * attribute at all). -->
|
||
|
<xsl:if test="@colspan > 1">
|
||
|
<xsl:call-template name="process.colspan">
|
||
|
<xsl:with-param name="colspan" select="@colspan - 1"/>
|
||
|
<xsl:with-param name="type" select="@type"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:if>
|
||
|
</xsl:template>
|
||
|
|
||
|
<xsl:template name="process.colspan">
|
||
|
<xsl:param name="colspan"/>
|
||
|
<xsl:param name="type"/>
|
||
|
<!-- * Output a space to separate this key letter from preceding one. -->
|
||
|
<xsl:text> </xsl:text>
|
||
|
<xsl:choose>
|
||
|
<xsl:when test="$type = '^'">
|
||
|
<!-- * A '^' ("vertically spanned heading" marker) indicates -->
|
||
|
<!-- * that the "parent" of this spanned cell is a dummy cell; -->
|
||
|
<!-- * in this case, we need to generate a '^' instead of the -->
|
||
|
<!-- * normal 's'. -->
|
||
|
<xsl:text>^</xsl:text>
|
||
|
</xsl:when>
|
||
|
<xsl:otherwise>
|
||
|
<!-- * s = 'spanned heading' -->
|
||
|
<xsl:text>s</xsl:text>
|
||
|
</xsl:otherwise>
|
||
|
</xsl:choose>
|
||
|
<xsl:if test="$colspan > 1">
|
||
|
<!-- * Tail recurse until we have no more colspans, outputting -->
|
||
|
<!-- * another marker each time. -->
|
||
|
<xsl:call-template name="process.colspan">
|
||
|
<xsl:with-param name="colspan" select="$colspan - 1"/>
|
||
|
<xsl:with-param name="type" select="$type"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:if>
|
||
|
</xsl:template>
|
||
|
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * colgroup and col -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * We currently don't do anything with colgroup. Not sure if it -->
|
||
|
<!-- * is widely used enough to bother adding support for it -->
|
||
|
<xsl:template match="colgroup"/>
|
||
|
<xsl:template match="col"/>
|
||
|
|
||
|
<!-- * ============================================================== -->
|
||
|
<!-- * table footnotes -->
|
||
|
<!-- * ============================================================== -->
|
||
|
<xsl:template match="footnote" mode="table.footnote.mode">
|
||
|
<xsl:variable name="footnotes" select=".//footnote"/>
|
||
|
<xsl:variable name="table.footnotes"
|
||
|
select=".//tgroup//footnote"/>
|
||
|
<xsl:value-of select="$man.table.footnotes.divider"/>
|
||
|
<xsl:text> </xsl:text>
|
||
|
<xsl:text>.br </xsl:text>
|
||
|
<xsl:apply-templates select="*[1]" mode="footnote.body.number"/>
|
||
|
<xsl:apply-templates select="*[position() > 1]"/>
|
||
|
</xsl:template>
|
||
|
|
||
|
<!-- * The following template for footnote.body.number mode was just -->
|
||
|
<!-- * lifted from the HTML stylesheets with some minor adjustments -->
|
||
|
<xsl:template match="*" mode="footnote.body.number">
|
||
|
<xsl:variable name="name">
|
||
|
<xsl:text>ftn.</xsl:text>
|
||
|
<xsl:call-template name="object.id">
|
||
|
<xsl:with-param name="object" select="ancestor::footnote"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:variable>
|
||
|
<xsl:variable name="href">
|
||
|
<xsl:text>#</xsl:text>
|
||
|
<xsl:call-template name="object.id">
|
||
|
<xsl:with-param name="object" select="ancestor::footnote"/>
|
||
|
</xsl:call-template>
|
||
|
</xsl:variable>
|
||
|
<xsl:variable name="footnote.mark">
|
||
|
<xsl:text>[</xsl:text>
|
||
|
<xsl:apply-templates select="ancestor::footnote"
|
||
|
mode="footnote.number"/>
|
||
|
<xsl:text>] </xsl:text>
|
||
|
</xsl:variable>
|
||
|
<xsl:variable name="html">
|
||
|
<xsl:apply-templates select="."/>
|
||
|
</xsl:variable>
|
||
|
<xsl:choose>
|
||
|
<xsl:when test="$exsl.node.set.available != 0">
|
||
|
<xsl:variable name="html-nodes" select="exsl:node-set($html)"/>
|
||
|
<xsl:choose>
|
||
|
<xsl:when test="$html-nodes//p">
|
||
|
<xsl:apply-templates select="$html-nodes" mode="insert.html.p">
|
||
|
<xsl:with-param name="mark" select="$footnote.mark"/>
|
||
|
</xsl:apply-templates>
|
||
|
</xsl:when>
|
||
|
<xsl:otherwise>
|
||
|
<xsl:apply-templates select="$html-nodes" mode="insert.html.text">
|
||
|
<xsl:with-param name="mark" select="$footnote.mark"/>
|
||
|
</xsl:apply-templates>
|
||
|
</xsl:otherwise>
|
||
|
</xsl:choose>
|
||
|
</xsl:when>
|
||
|
<xsl:otherwise>
|
||
|
<xsl:copy-of select="$html"/>
|
||
|
</xsl:otherwise>
|
||
|
</xsl:choose>
|
||
|
</xsl:template>
|
||
|
|
||
|
<!-- * The HTML stylesheets output <sup><a>...</a></sup> around -->
|
||
|
<!-- * footnote markers in tables -->
|
||
|
<xsl:template match="th/sup">
|
||
|
<xsl:apply-templates/>
|
||
|
</xsl:template>
|
||
|
<xsl:template match="a">
|
||
|
<xsl:apply-templates/>
|
||
|
</xsl:template>
|
||
|
|
||
|
</xsl:stylesheet>
|