- Split tabular handling into a separate module.
1 parent 5f9e7d0 commit b0b537e6661888cd1c66a0c2fcae6829ef565347
nstanger authored on 26 Sep 2011
Showing 2 changed files
View
1026
format-master.xml
<strong style="border: 1px solid black;">!!<xsl:apply-templates />!!</strong>
</common>
</template>
 
 
<!--
Tabular structures (LaTeX {tabular}, HTML <table>).
@align: The alignment of the table as a whole.
'left' [default]
'center' | 'centre'
'right'
@valign (LaTeX only): Vertical alignment of the tabular within
the paragraph.
'top'
'center' | 'centre' [default]
'bottom'
@border: Width of cell border for HTML tables.
@scale (LaTeX only): Scaling factor for the tabular.
@rotate (LaTeX only): Rotation angle of tabular in degrees
anti-clockwise.
-->
<template name="tabular" match="tabular">
<common formats="/latex/xelatex/">
<!-- spacing -->
<xsl:text>
</xsl:text>
<!-- Overall tabular alignment. -->
<xsl:if test="@align">
<xsl:text>\begin{</xsl:text>
<xsl:choose>
<xsl:when test="(@align = 'left') or (@align = 'right')">
<xsl:text>flush</xsl:text><xsl:value-of select="@align" />
</xsl:when>
<xsl:when test="(@align = 'center') or (@align = 'centre')">
<xsl:text>center</xsl:text>
</xsl:when>
</xsl:choose>
<xsl:text>}</xsl:text>
</xsl:if>
 
<!-- tabular rotation -->
<xsl:if test="@rotate">
<xsl:text>\rotatebox{</xsl:text>
<xsl:value-of select="@rotate" />
<xsl:text>}{</xsl:text>
</xsl:if>
 
<!-- tabular scaling -->
<xsl:if test="@scale">
<xsl:text>\scalebox{</xsl:text>
<xsl:value-of select="@scale" />
<xsl:text>}{</xsl:text>
</xsl:if>
 
<xsl:text>\begin{tabular}</xsl:text>
<!-- vertical alignment -->
<xsl:if test="@valign = 'top' or @valign = 'bottom'">
<xsl:text>[</xsl:text>
<xsl:value-of select="substring(@valign, 1, 1)" />
<xsl:text>]</xsl:text>
</xsl:if>
<xsl:text>{</xsl:text>
<xsl:apply-templates select="tabular-columns" />
<xsl:text>}</xsl:text>
<xsl:apply-templates select="tabular-header" />
<xsl:apply-templates select="tabular-body" />
<xsl:apply-templates select="tabular-footer" />
<xsl:text>\end{tabular}</xsl:text>
 
<xsl:if test="@scale"><xsl:text>}</xsl:text></xsl:if>
 
<xsl:if test="@rotate"><xsl:text>}</xsl:text></xsl:if>
 
<xsl:if test="@align">
<xsl:text>\end{</xsl:text>
<xsl:choose>
<xsl:when test="(@align = 'left') or (@align = 'right')">
<xsl:text>flush</xsl:text><xsl:value-of select="@align" />
</xsl:when>
<xsl:when test="(@align = 'center') or (@align = 'centre')">
<xsl:text>center</xsl:text>
</xsl:when>
</xsl:choose>
<xsl:text>}</xsl:text>
</xsl:if>
 
<!-- spacing -->
<xsl:text>
 
</xsl:text>
</common>
<common formats="/html/xhtml/">
<table>
<xsl:attribute name="border">
<xsl:value-of select="@border" />
<xsl:if test="not(@border)">0</xsl:if>
</xsl:attribute>
<xsl:attribute name="cellspacing">0</xsl:attribute>
<xsl:attribute name="style">
<xsl:text>border-collapse: collapse; </xsl:text>
<xsl:choose>
<xsl:when test="@align='center'">
<xsl:text>margin-left:auto; margin-right: auto; </xsl:text>
</xsl:when>
<xsl:when test="@align='right'">
<xsl:text>margin-left:auto; </xsl:text>
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:attribute>
<!--
Note different ordering of tabular components:
HTML requires THEAD and TFOOT to precede TBODY.
-->
<xsl:apply-templates select="tabular-header" />
<xsl:apply-templates select="tabular-footer" />
<xsl:apply-templates select="tabular-body" />
</table>
</common>
</template>
<!--
Specify column formatting, mainly for LaTeX, although
HTML does get <td> ALIGN values from here.
@align: The alignment of this particular column.
'left' [default]
'center' | 'centre'
'right'
@left-border: Set to '|' to include a column separator to the
left of this column.
 
@right-border: Set to '|' to include a column separator to the
right of this column.
Careful: including a right-border on a cell and a left-border on
the next cell will produce '||', not '|'. BUT, when doing
multi-column or multi-row cells, always include both borders if
required, because \multicolumn overrides the default border
specification.
-->
<template name="aligned-tabular-column" match="tabular-columns/column[@align]">
<common formats="/latex/xelatex/">
<xsl:value-of select="@left-border" />
<xsl:value-of select="substring(@align, 1, 1)" />
<xsl:value-of select="@right-border" />
</common>
</template>
 
<template name="unaligned-tabular-column" match="tabular-columns/column[not(@align)]">
<common formats="/latex/xelatex/">
<xsl:value-of select="@left-border" />
<xsl:text>l</xsl:text>
<xsl:value-of select="@right-border" />
</common>
</template>
<template name="tabular-header" match="tabular-header">
<common formats="/latex/xelatex/"><xsl:apply-templates /></common>
<common formats="/html/xhtml/">
<thead>
<xsl:apply-templates />
</thead>
</common>
</template>
 
<template name="tabular-footer" match="tabular-footer">
<common formats="/latex/xelatex/"><xsl:apply-templates /></common>
<common formats="/html/xhtml/">
<tfoot>
<xsl:apply-templates />
</tfoot>
</common>
</template>
 
<template name="tabular-body" match="tabular-body">
<common formats="/latex/xelatex/"><xsl:apply-templates /></common>
<common formats="/html/xhtml/">
<tbody>
<xsl:apply-templates />
</tbody>
</common>
</template>
 
<!--
@no-page-break: Inhibit page breaks after this row (LaTeX only).
-->
<template name="row" match="row">
<common formats="/latex/xelatex/">
<xsl:apply-templates />
<!-- TODO: Don't put a \\ on the last row of a tabular. -->
<xsl:text> \\</xsl:text>
<xsl:if test="@no-page-break = 'yes'">*</xsl:if>
<xsl:text> </xsl:text>
</common>
<common formats="/html/xhtml/">
<tr>
<xsl:if test="@valign">
<xsl:attribute name="valign"><xsl:value-of select="@valign" /></xsl:attribute>
</xsl:if>
<xsl:apply-templates />
</tr>
</common>
</template>
 
<!--
Horizontal rules (LaTeX only).
@columns: The column range to draw the rule across. Specify as
you would for a \cline in LaTeX, e.g., '3-5'. If omitted, the
rule is drawn across all columns.
@weight: The weight of the rule. Note that double weight isn't
available for partial rules in LaTeX, because repeated \cline
macros simply draw over the top of each other.
'single' [default]
'double' = a double rule
-->
<template name="row-rule-full" match="row-rule[not(@columns)]">
<common formats="/latex/xelatex/">
<xsl:text>\hline</xsl:text>
<xsl:if test="@weight = 'double'"><xsl:text>\hline</xsl:text></xsl:if>
<xsl:text> </xsl:text>
</common>
<common formats="/html/xhtml/">
<tr>
<td>
<xsl:attribute name="style">
<xsl:text>border-bottom: 1px solid black; </xsl:text>
<!--
This is a bit of a hack to get a double border,
as some browsers don't support the "double" border
style yet. It looks slightly ugly, but works.
-->
<xsl:if test="@weight = 'double'">
<xsl:text>border-top: 1px solid black; </xsl:text>
</xsl:if>
</xsl:attribute>
<xsl:attribute name="colspan">
<xsl:value-of select="count(ancestor::tabular/tabular-columns/column)" />
</xsl:attribute>
</td>
</tr>
</common>
</template>
 
<template name="row-rule-partial" match="row-rule[@columns]">
<common formats="/latex/xelatex/">
<!-- Tokenise the column specifications for later reference. -->
<xsl:variable name="column-specs" select="tokenize(@columns, ',')" />
<xsl:for-each select="$column-specs">
<xsl:text>\cline{</xsl:text>
<xsl:value-of select="." />
<!-- Normalise the value to a range if necessary. -->
<xsl:if test="not(contains(., '-'))">
<xsl:text>-</xsl:text>
<xsl:value-of select="." />
</xsl:if>
<xsl:text>}</xsl:text>
</xsl:for-each>
</common>
<common formats="/html/xhtml/">
<!-- Tokenise the column specifications for later reference. -->
<xsl:variable name="column-specs" select="tokenize(@columns, '[-,]')" />
<!--
We need to store the value of @weight, because the context will
be changed by the for-each loop below. Default to "single" in
any case.
-->
<xsl:variable name="weight">
<xsl:value-of select="@weight" />
<xsl:if test="not(@weight)">
<xsl:text>single</xsl:text>
</xsl:if>
</xsl:variable>
<tr>
<!--
Loop through all of the columns in the table, testing to
see whether the column index exists in $column-specs. If
so, add a border to the cell. Note that this loop changes
the current context!
-->
<xsl:for-each select="1 to count(ancestor::tabular/tabular-columns/column)">
<td>
<xsl:if test="exists(index-of($column-specs, . cast as xs:string))">
<xsl:attribute name="style">
<xsl:text>border-bottom: 1px solid black; </xsl:text>
<xsl:if test="$weight = 'double'">
<xsl:text>border-top: 1px solid black; </xsl:text>
</xsl:if>
</xsl:attribute>
</xsl:if>
</td>
</xsl:for-each>
</tr>
</common>
</template>
<!--
Hmm, the multi-row stuff is somewhat broken in LaTeX, oops.
Need to insert missing columns (as was done in the calendar
XSL) when a multi-row cell is encountered.
Also need to sort out \hlines in the presence of multi-row cells
and also what happens to vertical cell borders :(
This probably needs reworking.
-->
<!--
Multi-row cells (LaTeX only, as this is pretty trivial to
achieve in HTML).
@rows: The number of rows this cell spans.
@header: Is this a header cell? [yes, NO]
-->
<template name="multirow-cell" match="cell" mode="latex-multi-row">
<common formats="/latex/xelatex/">
<xsl:text>\multirow{</xsl:text>
<xsl:value-of select="@rows" />
<xsl:text>}{*}{</xsl:text>
<xsl:if test="@header = 'yes'"><xsl:text>\textbf{</xsl:text></xsl:if>
 
<!-- check for embedded line breaks, if so, embed another tabular inside this one -->
<xsl:if test="count(child::br) != 0">
<xsl:text>\begin{tabular}{@{}</xsl:text>
<xsl:choose>
<xsl:when test="@align">
<xsl:value-of select="substring(@align, 1, 1)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>l</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>@{}}</xsl:text>
</xsl:if>
 
<xsl:apply-templates />
 
<xsl:if test="count(child::br) != 0">
<xsl:text>\end{tabular}
</xsl:text></xsl:if>
<xsl:if test="@header = 'yes'"><xsl:text>}</xsl:text></xsl:if>
<xsl:text>}</xsl:text>
</common>
</template>
<!--
Multi-column cells (LaTeX only, as this is pretty trivial to
achieve in HTML).
$num-columns: The number of rows this cell spans.
@header: Is this a header cell? [yes, NO]
-->
<template name="multicolumn-cell" match="cell" mode="latex-multi-column">
<common formats="/latex/xelatex/">
<xsl:param name="num-columns">1</xsl:param>
<xsl:text>\multicolumn{</xsl:text>
<xsl:value-of select="$num-columns" />
<xsl:text>}{</xsl:text>
<xsl:value-of select="@left-border" />
<xsl:choose>
<xsl:when test="@align">
<xsl:value-of select="substring(@align, 1, 1)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>l</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="@right-border" />
<xsl:text>}{</xsl:text>
<xsl:choose>
<xsl:when test="@rows">
<xsl:apply-templates select="." mode="multi-row" />
</xsl:when>
<xsl:otherwise>
<xsl:if test="@header = 'yes'"><xsl:text>\textbf{</xsl:text></xsl:if>
 
<!-- check for embedded line breaks, if so, embed another tabular inside this one -->
<xsl:if test="count(child::br) != 0">
<xsl:text>\begin{tabular}{@{}</xsl:text>
<xsl:choose>
<xsl:when test="@align">
<xsl:value-of select="substring(@align, 1, 1)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>l</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>@{}}</xsl:text>
</xsl:if>
 
<xsl:apply-templates />
 
<xsl:if test="count(child::br) != 0">
<xsl:text>\end{tabular}
</xsl:text></xsl:if>
<xsl:if test="@header = 'yes'"><xsl:text>}</xsl:text></xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:text>}</xsl:text>
</common>
</template>
<!--
Top-level template for generating cells.
@columns: The number of columns this cell spans.
@rows: The number of rows this cell spans.
@align: The alignment of this cell. [LEFT, center, right]
@header: Is this a header cell? [yes, NO]
-->
<template match="cell">
<common>
<!-- position() doesn't seem to work very well in this context. -->
<xsl:variable name="column-no"><xsl:number /></xsl:variable>
</common>
<!--
Doing this sensibly for LaTeX is actually pretty ugly,
because different attribute combinations produce different
code :(
This is the sort of algorithm that can only really be
clearly described by a flow chart :)
-->
<common formats="/latex/xelatex/">
<xsl:choose>
<xsl:when test="@columns">
<xsl:apply-templates select="." mode="latex-multi-column">
<xsl:with-param name="num-columns" select="@columns" />
</xsl:apply-templates>
</xsl:when>
<xsl:when test="@align">
<xsl:apply-templates select="." mode="latex-multi-column" />
</xsl:when>
<xsl:when test="@rows">
<xsl:apply-templates select="." mode="latex-multi-row" />
</xsl:when>
<xsl:otherwise>
<xsl:if test="@header = 'yes'"><xsl:text>\textbf{</xsl:text></xsl:if>
 
<!-- check for embedded line breaks, if so, embed another tabular inside this one -->
<xsl:if test="count(child::br) != 0">
<xsl:text>\begin{tabular}{@{}</xsl:text>
<xsl:choose>
<xsl:when test="@align">
<xsl:value-of select="substring(@align, 1, 1)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>l</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>@{}}</xsl:text>
</xsl:if>
 
<xsl:apply-templates />
 
<xsl:if test="count(child::br) != 0">
<xsl:text>\end{tabular}
</xsl:text></xsl:if>
<xsl:if test="@header = 'yes'"><xsl:text>}</xsl:text></xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$column-no != last()"> &amp; </xsl:if>
</common>
<!--
It's much easier in HTML, because a <td> is a <td> is a
<td>, regardless of the attributes supplied.
-->
<common formats="/html/xhtml/">
<!--
Hmm, how to generate either a TD or TH as required,
including attributes, without repeating code?
Aha, the answer is attribute value templates!
-->
<xsl:variable name="celltype">
<xsl:choose>
<xsl:when test="@header = 'yes'">th</xsl:when>
<xsl:otherwise>td</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$celltype}">
<xsl:attribute name="align">
<xsl:value-of select="@align" />
<xsl:if test="not(@align)">
<xsl:value-of select="ancestor::tabular/tabular-columns/column[position() = $column-no]/@align" />
<xsl:if test="not(ancestor::tabular/tabular-columns/column[position() = $column-no]/@align)">left</xsl:if>
</xsl:if>
</xsl:attribute>
<xsl:attribute name="valign">
<xsl:value-of select="@valign" />
<xsl:if test="not(@valign)">middle</xsl:if>
</xsl:attribute>
<xsl:attribute name="colspan">
<xsl:value-of select="@columns" />
<xsl:if test="not(@columns)">1</xsl:if>
</xsl:attribute>
<xsl:attribute name="rowspan">
<xsl:value-of select="@rows" />
<xsl:if test="not(@rows)">1</xsl:if>
</xsl:attribute>
<xsl:apply-templates />
</xsl:element>
</common>
</template>
<!-- Tabular structures (LaTeX {tabular}, HTML <table>). -->
<include href="modules/tabular.xml" />
<!--
Hyperlinks. The content of the element is the hyperlink text.
View
516
modules/tabular.xml 0 → 100755
<?xml version="1.0" encoding="utf-8"?>
 
<!--
Tabular structures (LaTeX {tabular}, HTML <table>). Note that this is distinct from "tables" in general, which correspond to the {table} environment in LaTeX (i.e., floating).
-->
 
<stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 
 
<!--
Tabular structures (LaTeX {tabular}, HTML <table>).
@align: The alignment of the table as a whole.
'left' [default]
'center' | 'centre'
'right'
@valign (LaTeX only): Vertical alignment of the tabular within the paragraph.
'top'
'center' | 'centre' [default]
'bottom'
@border: Width of cell border for HTML tables.
@scale (LaTeX only): Scaling factor for the tabular.
@rotate (LaTeX only): Rotation angle of tabular in degrees anti-clockwise.
-->
<template name="tabular" match="tabular">
<common formats="/latex/xelatex/">
<!-- spacing -->
<xsl:text>
</xsl:text>
<!-- Overall tabular alignment. -->
<xsl:if test="@align">
<xsl:text>\begin{</xsl:text>
<xsl:choose>
<xsl:when test="(@align = 'left') or (@align = 'right')">
<xsl:text>flush</xsl:text><xsl:value-of select="@align" />
</xsl:when>
<xsl:when test="(@align = 'center') or (@align = 'centre')">
<xsl:text>center</xsl:text>
</xsl:when>
</xsl:choose>
<xsl:text>}</xsl:text>
</xsl:if>
 
<!-- tabular rotation -->
<xsl:if test="@rotate">
<xsl:text>\rotatebox{</xsl:text>
<xsl:value-of select="@rotate" />
<xsl:text>}{</xsl:text>
</xsl:if>
 
<!-- tabular scaling -->
<xsl:if test="@scale">
<xsl:text>\scalebox{</xsl:text>
<xsl:value-of select="@scale" />
<xsl:text>}{</xsl:text>
</xsl:if>
 
<xsl:text>\begin{tabular}</xsl:text>
<!-- vertical alignment -->
<xsl:if test="@valign = 'top' or @valign = 'bottom'">
<xsl:text>[</xsl:text>
<xsl:value-of select="substring(@valign, 1, 1)" />
<xsl:text>]</xsl:text>
</xsl:if>
<xsl:text>{</xsl:text>
<xsl:apply-templates select="tabular-columns" />
<xsl:text>}</xsl:text>
<xsl:apply-templates select="tabular-header" />
<xsl:apply-templates select="tabular-body" />
<xsl:apply-templates select="tabular-footer" />
<xsl:text>\end{tabular}</xsl:text>
 
<xsl:if test="@scale"><xsl:text>}</xsl:text></xsl:if>
 
<xsl:if test="@rotate"><xsl:text>}</xsl:text></xsl:if>
 
<xsl:if test="@align">
<xsl:text>\end{</xsl:text>
<xsl:choose>
<xsl:when test="(@align = 'left') or (@align = 'right')">
<xsl:text>flush</xsl:text><xsl:value-of select="@align" />
</xsl:when>
<xsl:when test="(@align = 'center') or (@align = 'centre')">
<xsl:text>center</xsl:text>
</xsl:when>
</xsl:choose>
<xsl:text>}</xsl:text>
</xsl:if>
 
<!-- spacing -->
<xsl:text>
 
</xsl:text>
</common>
<common formats="/html/xhtml/">
<table>
<xsl:attribute name="border">
<xsl:value-of select="@border" />
<xsl:if test="not(@border)">0</xsl:if>
</xsl:attribute>
<xsl:attribute name="cellspacing">0</xsl:attribute>
<xsl:attribute name="style">
<xsl:text>border-collapse: collapse; </xsl:text>
<xsl:choose>
<xsl:when test="@align='center'">
<xsl:text>margin-left:auto; margin-right: auto; </xsl:text>
</xsl:when>
<xsl:when test="@align='right'">
<xsl:text>margin-left:auto; </xsl:text>
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:attribute>
<!--
Note different ordering of tabular components: HTML requires THEAD and TFOOT to precede TBODY.
-->
<xsl:apply-templates select="tabular-header" />
<xsl:apply-templates select="tabular-footer" />
<xsl:apply-templates select="tabular-body" />
</table>
</common>
</template>
<!--
Specify column formatting, mainly for LaTeX, although HTML does get <td> ALIGN values from here.
@align: The alignment of this particular column.
'left' [default]
'center' | 'centre'
'right'
@left-border: Set to '|' to include a column separator to the left of this column.
 
@right-border: Set to '|' to include a column separator to the right of this column.
Careful: including a right-border on a cell and a left-border on the next cell will produce '||', not '|'. BUT, when doing multi-column or multi-row cells, always include both borders if required, because \multicolumn overrides the default border specification.
-->
<template name="aligned-tabular-column" match="tabular-columns/column[@align]">
<common formats="/latex/xelatex/">
<xsl:value-of select="@left-border" />
<xsl:value-of select="substring(@align, 1, 1)" />
<xsl:value-of select="@right-border" />
</common>
</template>
 
<template name="unaligned-tabular-column" match="tabular-columns/column[not(@align)]">
<common formats="/latex/xelatex/">
<xsl:value-of select="@left-border" />
<xsl:text>l</xsl:text>
<xsl:value-of select="@right-border" />
</common>
</template>
<!-- Tabular header. -->
<template name="tabular-header" match="tabular-header">
<common formats="/latex/xelatex/"><xsl:apply-templates /></common>
<common formats="/html/xhtml/">
<thead>
<xsl:apply-templates />
</thead>
</common>
</template>
<!-- Tabular footer. -->
<template name="tabular-footer" match="tabular-footer">
<common formats="/latex/xelatex/"><xsl:apply-templates /></common>
<common formats="/html/xhtml/">
<tfoot>
<xsl:apply-templates />
</tfoot>
</common>
</template>
<!-- Tabular main body. -->
<template name="tabular-body" match="tabular-body">
<common formats="/latex/xelatex/"><xsl:apply-templates /></common>
<common formats="/html/xhtml/">
<tbody>
<xsl:apply-templates />
</tbody>
</common>
</template>
<!--
A single row of a tabular.
@no-page-break: Inhibit page breaks after this row (LaTeX only).
-->
<template name="row" match="row">
<common formats="/latex/xelatex/">
<xsl:apply-templates />
<!-- TODO: Don't put a \\ on the last row of a tabular. -->
<xsl:text> \\</xsl:text>
<xsl:if test="@no-page-break = 'yes'">*</xsl:if>
<xsl:text> </xsl:text>
</common>
<common formats="/html/xhtml/">
<tr>
<xsl:if test="@valign">
<xsl:attribute name="valign"><xsl:value-of select="@valign" /></xsl:attribute>
</xsl:if>
<xsl:apply-templates />
</tr>
</common>
</template>
<!--
Horizontal rules (LaTeX only).
@columns: The column range to draw the rule across. Specify as you would for a \cline in LaTeX, e.g., '3-5'. If omitted, the rule is drawn across all columns.
@weight: The weight of the rule. Note that double weight isn't available for partial rules in LaTeX, because repeated \cline macros simply draw over the top of each other.
'single' [default]
'double' = a double rule
-->
<template name="row-rule-full" match="row-rule[not(@columns)]">
<common formats="/latex/xelatex/">
<xsl:text>\hline</xsl:text>
<xsl:if test="@weight = 'double'"><xsl:text>\hline</xsl:text></xsl:if>
<xsl:text> </xsl:text>
</common>
<common formats="/html/xhtml/">
<tr>
<td>
<xsl:attribute name="style">
<xsl:text>border-bottom: 1px solid black; </xsl:text>
<!--
This is a bit of a hack to get a double border,
as some browsers don't support the "double" border
style yet. It looks slightly ugly, but works.
-->
<xsl:if test="@weight = 'double'">
<xsl:text>border-top: 1px solid black; </xsl:text>
</xsl:if>
</xsl:attribute>
<xsl:attribute name="colspan">
<xsl:value-of select="count(ancestor::tabular/tabular-columns/column)" />
</xsl:attribute>
</td>
</tr>
</common>
</template>
 
<template name="row-rule-partial" match="row-rule[@columns]">
<common formats="/latex/xelatex/">
<!-- Tokenise the column specifications for later reference. -->
<xsl:variable name="column-specs" select="tokenize(@columns, ',')" />
<xsl:for-each select="$column-specs">
<xsl:text>\cline{</xsl:text>
<xsl:value-of select="." />
<!-- Normalise the value to a range if necessary. -->
<xsl:if test="not(contains(., '-'))">
<xsl:text>-</xsl:text>
<xsl:value-of select="." />
</xsl:if>
<xsl:text>}</xsl:text>
</xsl:for-each>
</common>
<common formats="/html/xhtml/">
<!-- Tokenise the column specifications for later reference. -->
<xsl:variable name="column-specs" select="tokenize(@columns, '[-,]')" />
<!--
We need to store the value of @weight, because the context will be changed by the for-each loop below. Default to "single" in any case.
-->
<xsl:variable name="weight">
<xsl:value-of select="@weight" />
<xsl:if test="not(@weight)">
<xsl:text>single</xsl:text>
</xsl:if>
</xsl:variable>
<tr>
<!--
Loop through all of the columns in the table, testing to see whether the column index exists in $column-specs. If so, add a border to the cell. Note that this loop changes the current context!
-->
<xsl:for-each select="1 to count(ancestor::tabular/tabular-columns/column)">
<td>
<xsl:if test="exists(index-of($column-specs, . cast as xs:string))">
<xsl:attribute name="style">
<xsl:text>border-bottom: 1px solid black; </xsl:text>
<xsl:if test="$weight = 'double'">
<xsl:text>border-top: 1px solid black; </xsl:text>
</xsl:if>
</xsl:attribute>
</xsl:if>
</td>
</xsl:for-each>
</tr>
</common>
</template>
<!--
Multi-row cells (LaTeX only, as this is pretty trivial to achieve in HTML).
@rows: The number of rows this cell spans.
@header: Is this a header cell? [yes, NO]
-->
<!--
Hmm, the multi-row stuff is somewhat broken in LaTeX, oops. Need to insert missing columns (as was done in the calendar XSL) when a multi-row cell is encountered.
Also need to sort out \hlines in the presence of multi-row cells and also what happens to vertical cell borders :(.
This probably needs reworking.
-->
<template name="multirow-cell" match="cell" mode="latex-multi-row">
<common formats="/latex/xelatex/">
<xsl:text>\multirow{</xsl:text>
<xsl:value-of select="@rows" />
<xsl:text>}{*}{</xsl:text>
<xsl:if test="@header = 'yes'"><xsl:text>\textbf{</xsl:text></xsl:if>
 
<!-- check for embedded line breaks, if so, embed another tabular inside this one -->
<xsl:if test="count(child::br) != 0">
<xsl:text>\begin{tabular}{@{}</xsl:text>
<xsl:choose>
<xsl:when test="@align">
<xsl:value-of select="substring(@align, 1, 1)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>l</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>@{}}</xsl:text>
</xsl:if>
 
<xsl:apply-templates />
 
<xsl:if test="count(child::br) != 0">
<xsl:text>\end{tabular}
</xsl:text></xsl:if>
<xsl:if test="@header = 'yes'"><xsl:text>}</xsl:text></xsl:if>
<xsl:text>}</xsl:text>
</common>
</template>
<!--
Multi-column cells (LaTeX only, as this is pretty trivial to achieve in HTML).
$num-columns: The number of columns this cell spans.
@header: Is this a header cell? [yes, NO]
-->
<template name="multicolumn-cell" match="cell" mode="latex-multi-column">
<common formats="/latex/xelatex/">
<!--
TODO: Not quite sure why the number of columns is a parameter rather than just using the @columns attribute? Something to do with defaults perhaps?
-->
<xsl:param name="num-columns">1</xsl:param>
<xsl:text>\multicolumn{</xsl:text>
<xsl:value-of select="$num-columns" />
<xsl:text>}{</xsl:text>
<xsl:value-of select="@left-border" />
<xsl:choose>
<xsl:when test="@align">
<xsl:value-of select="substring(@align, 1, 1)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>l</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="@right-border" />
<xsl:text>}{</xsl:text>
<xsl:choose>
<xsl:when test="@rows">
<xsl:apply-templates select="." mode="multi-row" />
</xsl:when>
<xsl:otherwise>
<xsl:if test="@header = 'yes'"><xsl:text>\textbf{</xsl:text></xsl:if>
 
<!-- check for embedded line breaks, if so, embed another tabular inside this one -->
<xsl:if test="count(child::br) != 0">
<xsl:text>\begin{tabular}{@{}</xsl:text>
<xsl:choose>
<xsl:when test="@align">
<xsl:value-of select="substring(@align, 1, 1)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>l</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>@{}}</xsl:text>
</xsl:if>
 
<xsl:apply-templates />
 
<xsl:if test="count(child::br) != 0">
<xsl:text>\end{tabular}
</xsl:text></xsl:if>
<xsl:if test="@header = 'yes'"><xsl:text>}</xsl:text></xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:text>}</xsl:text>
</common>
</template>
<!--
Top-level template for generating cells.
@columns: The number of columns this cell spans.
@rows: The number of rows this cell spans.
@align: The alignment of this cell. [LEFT, center, right]
@header: Is this a header cell? [yes, NO]
-->
<template match="cell">
<common>
<!-- position() doesn't seem to work very well in this context. -->
<xsl:variable name="column-no"><xsl:number /></xsl:variable>
</common>
<!--
Doing this sensibly for LaTeX is actually pretty ugly, because different attribute combinations produce different code :(.
This is the sort of algorithm that can only really be clearly described by a flow chart :).
-->
<common formats="/latex/xelatex/">
<xsl:choose>
<xsl:when test="@columns">
<xsl:apply-templates select="." mode="latex-multi-column">
<xsl:with-param name="num-columns" select="@columns" />
</xsl:apply-templates>
</xsl:when>
<xsl:when test="@align">
<xsl:apply-templates select="." mode="latex-multi-column" />
</xsl:when>
<xsl:when test="@rows">
<xsl:apply-templates select="." mode="latex-multi-row" />
</xsl:when>
<xsl:otherwise>
<xsl:if test="@header = 'yes'"><xsl:text>\textbf{</xsl:text></xsl:if>
 
<!-- check for embedded line breaks, if so, embed another tabular inside this one -->
<xsl:if test="count(child::br) != 0">
<xsl:text>\begin{tabular}{@{}</xsl:text>
<xsl:choose>
<xsl:when test="@align">
<xsl:value-of select="substring(@align, 1, 1)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>l</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>@{}}</xsl:text>
</xsl:if>
 
<xsl:apply-templates />
 
<xsl:if test="count(child::br) != 0">
<xsl:text>\end{tabular}
</xsl:text></xsl:if>
<xsl:if test="@header = 'yes'"><xsl:text>}</xsl:text></xsl:if>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$column-no != last()"> &amp; </xsl:if>
</common>
<!--
It's much easier in HTML, because a <td> is a <td> is a <td>, regardless of the attributes supplied.
-->
<common formats="/html/xhtml/">
<!--
Hmm, how to generate either a TD or TH as required, including attributes, without repeating code?
Aha, the answer is attribute value templates!
-->
<xsl:variable name="celltype">
<xsl:choose>
<xsl:when test="@header = 'yes'">th</xsl:when>
<xsl:otherwise>td</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$celltype}">
<xsl:attribute name="align">
<xsl:value-of select="@align" />
<xsl:if test="not(@align)">
<xsl:value-of select="ancestor::tabular/tabular-columns/column[position() = $column-no]/@align" />
<xsl:if test="not(ancestor::tabular/tabular-columns/column[position() = $column-no]/@align)">left</xsl:if>
</xsl:if>
</xsl:attribute>
<xsl:attribute name="valign">
<xsl:value-of select="@valign" />
<xsl:if test="not(@valign)">middle</xsl:if>
</xsl:attribute>
<xsl:attribute name="colspan">
<xsl:value-of select="@columns" />
<xsl:if test="not(@columns)">1</xsl:if>
</xsl:attribute>
<xsl:attribute name="rowspan">
<xsl:value-of select="@rows" />
<xsl:if test="not(@rows)">1</xsl:if>
</xsl:attribute>
<xsl:apply-templates />
</xsl:element>
</common>
</template>
 
 
</stylesheet>