table.xsl 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. <?xml version="1.0"?>
  2. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3. xmlns:exsl="http://exslt.org/common"
  4. exclude-result-prefixes="exsl"
  5. version='1.0'>
  6. <!-- ********************************************************************
  7. $Id: table.xsl 8400 2009-04-08 07:44:54Z bobstayton $
  8. ********************************************************************
  9. This file is part of the XSL DocBook Stylesheet distribution.
  10. See ../README or http://docbook.sf.net/release/xsl/current/ for
  11. copyright and other information.
  12. ******************************************************************** -->
  13. <!--
  14. <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
  15. <xsl:param name="tbl.font.title">B</xsl:param>
  16. <xsl:param name="tbl.font.headings">B</xsl:param>
  17. -->
  18. <xsl:param name="tbl.running.header.from.thead" select="0"/>
  19. <xsl:param name="tbl.column.separator.char">:</xsl:param>
  20. <!-- ==================================================================== -->
  21. <!-- * This stylesheet transforms DocBook and HTML table source into -->
  22. <!-- * tbl(1) markup. -->
  23. <!-- * -->
  24. <!-- * For details on tbl(1) and its markup syntaxt, see M. E. Lesk,-->
  25. <!-- * "Tbl - A Program to Format Tables": -->
  26. <!-- * -->
  27. <!-- * http://cm.bell-labs.com/7thEdMan/vol2/tbl -->
  28. <!-- * http://cm.bell-labs.com/cm/cs/doc/76/tbl.ps.gz -->
  29. <!-- * http://www.snake.net/software/troffcvt/tbl.html -->
  30. <xsl:template match="table|informaltable" mode="to.tbl">
  31. <!--* the "source" param is an optional param; it can be any -->
  32. <!--* string you want to use that gives some indication of the -->
  33. <!--* source context for a table; it gets passed down to the named -->
  34. <!--* templates that do the actual table processing; this -->
  35. <!--* stylesheet currently uses the "source" information for -->
  36. <!--* logging purposes -->
  37. <xsl:param name="source"/>
  38. <xsl:param name="title">
  39. <xsl:if test="local-name(.) = 'table'">
  40. <xsl:apply-templates select="." mode="object.title.markup.textonly"/>
  41. </xsl:if>
  42. </xsl:param>
  43. <!-- * ============================================================== -->
  44. <!-- * Set global table parameters -->
  45. <!-- * ============================================================== -->
  46. <!-- * First, set a few parameters based on attributes specified in -->
  47. <!-- * the table source. -->
  48. <xsl:param name="allbox">
  49. <xsl:if test="not(@frame = 'none') and not(@border = '0')">
  50. <!-- * By default, put a box around table and between all cells, -->
  51. <!-- * unless frame="none" or border="0" -->
  52. <xsl:text>allbox </xsl:text>
  53. </xsl:if>
  54. </xsl:param>
  55. <xsl:param name="center">
  56. <!-- * If align="center", center the table. Otherwise, tbl(1) -->
  57. <!-- * left-aligns it by default; note that there is no support -->
  58. <!-- * in tbl(1) for specifying right alignment. -->
  59. <xsl:if test="@align = 'center' or tgroup/@align = 'center'">
  60. <xsl:text>center </xsl:text>
  61. </xsl:if>
  62. </xsl:param>
  63. <xsl:param name="expand">
  64. <!-- * If pgwide="1" or width="100%", then "expand" the table by -->
  65. <!-- * making it "as wide as the current line length" (to quote -->
  66. <!-- * the tbl(1) guide). -->
  67. <xsl:if test="@pgwide = '1' or @width = '100%'">
  68. <xsl:text>expand </xsl:text>
  69. </xsl:if>
  70. </xsl:param>
  71. <!-- * ============================================================== -->
  72. <!-- * Convert table to HTML -->
  73. <!-- * ============================================================== -->
  74. <!-- * Process the table by applying the HTML templates from the -->
  75. <!-- * DocBook XSL stylesheets to the whole thing; because we don't -->
  76. <!-- * override any of the <row>, <entry>, <tr>, <td>, etc. templates, -->
  77. <!-- * the templates in the HTML stylesheets (which we import) are -->
  78. <!-- * used to process those. -->
  79. <xsl:param name="html-table-output">
  80. <xsl:choose>
  81. <xsl:when test=".//tr">
  82. <!-- * If this table has a TR child, it means that it's an -->
  83. <!-- * HTML table in the DocBook source, instead of a CALS -->
  84. <!-- * table. So we just copy it as-is, while wrapping it -->
  85. <!-- * in an element with same name as its original parent. -->
  86. <xsl:for-each select="descendant-or-self::table|descendant-or-self::informaltable">
  87. <xsl:element name="{local-name(..)}">
  88. <table>
  89. <xsl:copy-of select="*"/>
  90. </table>
  91. </xsl:element>
  92. </xsl:for-each>
  93. </xsl:when>
  94. <xsl:otherwise>
  95. <!-- * Otherwise, this is a CALS table in the DocBook source, -->
  96. <!-- * so we need to apply the templates in the HTML -->
  97. <!-- * stylesheets to transform it into HTML before we do -->
  98. <!-- * any further processing of it. -->
  99. <xsl:apply-templates/>
  100. </xsl:otherwise>
  101. </xsl:choose>
  102. </xsl:param>
  103. <xsl:param name="contents" select="exsl:node-set($html-table-output)"/>
  104. <!-- ==================================================================== -->
  105. <!-- * Output the table -->
  106. <!-- ==================================================================== -->
  107. <!-- * -->
  108. <!-- * This is the "driver" part of the code; it calls a series of named
  109. * templates (further below) to generate the actual tbl(1) markup, -->
  110. <!-- * including the optional "options line", required "format section", -->
  111. <!-- * and then the actual contents of the table. -->
  112. <!-- * -->
  113. <!-- ==================================================================== -->
  114. <xsl:for-each select="$contents//table">
  115. <!-- * ============================================================== -->
  116. <!-- * Output table title -->
  117. <!-- * ============================================================== -->
  118. <xsl:if test="$title != '' or parent::td">
  119. <xsl:text>.sp&#10;</xsl:text>
  120. <xsl:call-template name="pinch.together"/>
  121. <xsl:text>.</xsl:text>
  122. <xsl:value-of select="$tbl.font.title"/>
  123. <xsl:text> </xsl:text>
  124. <xsl:if test="parent::td">
  125. <xsl:text>*[nested&#x2580;table]</xsl:text>
  126. </xsl:if>
  127. <xsl:value-of select="normalize-space($title)"/>
  128. <xsl:text>&#10;</xsl:text>
  129. </xsl:if>
  130. <!-- * mark the start of the table -->
  131. <!-- * "TS" = "table start" -->
  132. <xsl:text>.TS</xsl:text>
  133. <xsl:if test="thead and $tbl.running.header.from.thead">
  134. <!-- * H = "has header" -->
  135. <xsl:text> H</xsl:text>
  136. </xsl:if>
  137. <xsl:text>&#10;</xsl:text>
  138. <!-- * ============================================================== -->
  139. <!-- * Output "options line" -->
  140. <!-- * ============================================================== -->
  141. <xsl:variable name="options-line">
  142. <xsl:value-of select="$allbox"/>
  143. <xsl:value-of select="$center"/>
  144. <xsl:value-of select="$expand"/>
  145. <xsl:text>tab(</xsl:text>
  146. <xsl:value-of select="$tbl.column.separator.char"/>
  147. <xsl:text>)</xsl:text>
  148. </xsl:variable>
  149. <xsl:if test="normalize-space($options-line) != ''">
  150. <xsl:value-of select="normalize-space($options-line)"/>
  151. <xsl:text>;&#10;</xsl:text>
  152. </xsl:if>
  153. <!-- * ============================================================== -->
  154. <!-- * Output table header rows -->
  155. <!-- * ============================================================== -->
  156. <xsl:if test="thead">
  157. <xsl:call-template name="output.rows">
  158. <xsl:with-param name="rows" select="thead/tr"/>
  159. </xsl:call-template>
  160. <xsl:text>&#10;</xsl:text>
  161. <!-- * mark the end of table-header rows -->
  162. <xsl:choose>
  163. <xsl:when test="$tbl.running.header.from.thead">
  164. <!-- * "TH" = "table header end" -->
  165. <xsl:text>.TH&#10;</xsl:text>
  166. </xsl:when>
  167. <xsl:otherwise>
  168. <!-- * "T&" = "table continuation" and is meant just as a kind -->
  169. <!-- * of convenience macro and is sorta equivalent to a "TE" -->
  170. <!-- * (table end) followed immediately by a "TS" (table start); -->
  171. <!-- * in this case, it marks the end of a table "subsection" -->
  172. <!-- * with header rows, and the start of a subsection with body -->
  173. <!-- * rows. It's necessary to output it here because the "TH" -->
  174. <!-- * macro is not being output, so there's otherwise no way -->
  175. <!-- * for tbl(1) to know we have the table "sectioned". -->
  176. <xsl:text>.T&amp;&#10;</xsl:text>
  177. </xsl:otherwise>
  178. </xsl:choose>
  179. </xsl:if>
  180. <!-- * ============================================================== -->
  181. <!-- * Output table body rows -->
  182. <!-- * ============================================================== -->
  183. <!-- * First create node set with all non-thead rows (tbody+tfoot), -->
  184. <!-- * but reordered with the tfoot rows at the end of the node set -->
  185. <xsl:variable name="rows-set">
  186. <xsl:copy-of select="tbody/tr|tr"/>
  187. <xsl:copy-of select="tfoot/tr"/>
  188. </xsl:variable>
  189. <xsl:call-template name="output.rows">
  190. <xsl:with-param name="source" select="$source"/>
  191. <xsl:with-param name="rows" select="exsl:node-set($rows-set)"/>
  192. </xsl:call-template>
  193. <!-- * mark the end of the table -->
  194. <xsl:text>&#10;</xsl:text>
  195. <!-- * .TE = "Table End" -->
  196. <xsl:text>.TE&#10;</xsl:text>
  197. <!-- * put a blank line of space below the table -->
  198. <xsl:text>.sp 1&#10;</xsl:text>
  199. </xsl:for-each>
  200. </xsl:template>
  201. <!-- ==================================================================== -->
  202. <!-- * named templates -->
  203. <!-- ==================================================================== -->
  204. <!-- * -->
  205. <!-- * All of the following are named templates that get called directly -->
  206. <!-- * or indirectly by the main "driver" part of the code (above) -->
  207. <!-- * -->
  208. <!-- ==================================================================== -->
  209. <xsl:template name="output.rows">
  210. <xsl:param name="source"/>
  211. <xsl:param name="rows"/>
  212. <!-- * ============================================================== -->
  213. <!-- * Flatten row set into simple list of cells -->
  214. <!-- * ============================================================== -->
  215. <!-- * Now we flatten the structure further into just a set of -->
  216. <!-- * cells without the row parents. This basically creates a -->
  217. <!-- * copy of the entire contents of the original table, but -->
  218. <!-- * restructured in such a way that we can more easily generate -->
  219. <!-- * the corresponding tbl(1) markup we need to output. -->
  220. <xsl:variable name="cells-list">
  221. <xsl:call-template name="build.cell.list">
  222. <xsl:with-param name="source" select="$source"/>
  223. <xsl:with-param name="rows" select="$rows"/>
  224. </xsl:call-template>
  225. </xsl:variable>
  226. <xsl:variable name="cells" select="exsl:node-set($cells-list)"/>
  227. <!-- * Output the table "format section", which tells tbl(1) how to -->
  228. <!-- * format each row and column -->
  229. <xsl:call-template name="create.table.format">
  230. <xsl:with-param name="cells" select="$cells"/>
  231. </xsl:call-template>
  232. <!--* Output the formatted contents of each cell. -->
  233. <xsl:for-each select="$cells/cell">
  234. <xsl:call-template name="output.cell"/>
  235. </xsl:for-each>
  236. </xsl:template>
  237. <!-- * ============================================================== -->
  238. <!-- * Output the tbl(1)-formatted contents of each cell. -->
  239. <!-- * ============================================================== -->
  240. <xsl:template name="output.cell">
  241. <xsl:choose>
  242. <xsl:when test="preceding-sibling::cell[1]/@row != @row or
  243. not(preceding-sibling::cell)">
  244. <!-- * If the value of the "row" attribute on this cell is -->
  245. <!-- * different from the value of that on the previous cell, it -->
  246. <!-- * means we have a new row. So output a line break (as long -->
  247. <!-- * as this isn't the first cell in the table) -->
  248. <xsl:text>&#10;</xsl:text>
  249. </xsl:when>
  250. <xsl:otherwise>
  251. <!-- * Otherwise we are not at the start of a new row, so we -->
  252. <!-- * output a tab character to delimit the contents of this -->
  253. <!-- * cell from the contents of the next one. -->
  254. <xsl:value-of select="$tbl.column.separator.char"/>
  255. </xsl:otherwise>
  256. </xsl:choose>
  257. <xsl:choose>
  258. <xsl:when test="@type = '^'">
  259. <!-- * If this is a dummy cell resulting from the presence of -->
  260. <!-- * rowpan attribute in the source, it has no contents, so -->
  261. <!-- * we need to handle it differently. -->
  262. <xsl:if test="@colspan and @colspan > 1">
  263. <!-- * If there is a colspan attribute on this dummy row, then -->
  264. <!-- * we need to output a tab character for each column that -->
  265. <!-- * it spans. -->
  266. <xsl:call-template name="copy-string">
  267. <xsl:with-param name="string" select="$tbl.column.separator.char"/>
  268. <xsl:with-param name="count">
  269. <xsl:value-of select="@colspan - 1"/>
  270. </xsl:with-param>
  271. </xsl:call-template>
  272. </xsl:if>
  273. </xsl:when>
  274. <xsl:otherwise>
  275. <!-- * Otherwise, we have a "real" cell (not a dummy one) with -->
  276. <!-- * contents that we need to output, -->
  277. <!-- * -->
  278. <!-- * The "T{" and "T}" stuff are delimiters to tell tbl(1) that -->
  279. <!-- * the delimited contents are "text blocks" that roff -->
  280. <!-- * needs to process -->
  281. <xsl:text>T{&#10;</xsl:text>
  282. <xsl:copy-of select="."/>
  283. <xsl:text>&#10;T}</xsl:text>
  284. </xsl:otherwise>
  285. </xsl:choose>
  286. </xsl:template>
  287. <!-- * ============================================================== -->
  288. <!-- * Build a restructured "cell list" copy of the entire table -->
  289. <!-- * ============================================================== -->
  290. <xsl:template name="build.cell.list">
  291. <xsl:param name="source"/>
  292. <xsl:param name="rows"/>
  293. <xsl:param name="cell-data-unsorted">
  294. <!-- * This param collects all the "real" cells from the table, -->
  295. <!-- * along with "dummy" rows that we generate for keeping -->
  296. <!-- * track of Rowspan instances. -->
  297. <xsl:apply-templates select="$rows" mode="cell.list">
  298. <xsl:with-param name="source" select="$source"/>
  299. </xsl:apply-templates>
  300. </xsl:param>
  301. <xsl:param name="cell-data-sorted">
  302. <!-- * Sort the cells so that the dummy cells get put where we -->
  303. <!-- * need them in the structure. Note that we need to specify -->
  304. <!-- * data-type="number" here because the default sorting method -->
  305. <!-- * for xsl:sort is "text" (alphabetical). -->
  306. <xsl:for-each select="exsl:node-set($cell-data-unsorted)/cell">
  307. <xsl:sort select="@row" data-type="number"/>
  308. <xsl:sort select="@slot" data-type="number"/>
  309. <xsl:copy-of select="."/>
  310. </xsl:for-each>
  311. </xsl:param>
  312. <!-- * Return the sorted cell list -->
  313. <xsl:copy-of select="$cell-data-sorted"/>
  314. </xsl:template>
  315. <xsl:template match="tr" mode="cell.list">
  316. <xsl:param name="source"/>
  317. <xsl:variable name="row">
  318. <xsl:value-of select="count(preceding-sibling::tr) + 1"/>
  319. </xsl:variable>
  320. <xsl:for-each select="td|th">
  321. <xsl:call-template name="cell">
  322. <xsl:with-param name="source" select="$source"/>
  323. <xsl:with-param name="row" select="$row"/>
  324. <!-- * pass on the element name so we can select the appropriate -->
  325. <!-- * roff font for styling the cell contents -->
  326. <xsl:with-param name="class" select="name(.)"/>
  327. </xsl:call-template>
  328. </xsl:for-each>
  329. </xsl:template>
  330. <xsl:template name="cell">
  331. <xsl:param name="source"/>
  332. <xsl:param name="row"/>
  333. <xsl:param name="class"/>
  334. <xsl:param name="slot">
  335. <!-- * The "slot" is the horizontal position of this cell (usually -->
  336. <!-- * just the same as its column, but not so when it is preceded -->
  337. <!-- * by cells that have colspans or cells in preceding rows that -->
  338. <!-- * that have rowspans). -->
  339. <xsl:value-of select="position()"/>
  340. </xsl:param>
  341. <!-- * For each real TD cell, create a Cell instance; contents will -->
  342. <!-- * be the roff-formatted contents of its original table cell. -->
  343. <cell type=""
  344. row="{$row}"
  345. slot="{$slot}"
  346. class="{$class}"
  347. colspan="{@colspan}"
  348. align="{@align}"
  349. valign="{@valign}"
  350. >
  351. <xsl:choose>
  352. <xsl:when test=".//tr">
  353. <xsl:call-template name="log.message">
  354. <xsl:with-param name="level">Warn</xsl:with-param>
  355. <xsl:with-param name="source" select="$source"/>
  356. <xsl:with-param name="context-desc">tbl convert</xsl:with-param>
  357. <xsl:with-param name="message">
  358. <xsl:text>Extracted a nested table</xsl:text>
  359. </xsl:with-param>
  360. </xsl:call-template>
  361. <xsl:text>[\fInested&#x2580;table\fR]*&#10;</xsl:text>
  362. </xsl:when>
  363. <xsl:otherwise>
  364. <!-- * Apply templates to the child contents of this cell, to -->
  365. <!-- * transform them into marked-up roff. -->
  366. <xsl:variable name="contents">
  367. <xsl:apply-templates/>
  368. </xsl:variable>
  369. <!-- * We now have the contents in roff (plain-text) form, -->
  370. <!-- * but we may also still have unnecessary whitespace at -->
  371. <!-- * the beginning and/or end of it, so trim it off. -->
  372. <xsl:call-template name="trim.text">
  373. <xsl:with-param name="contents" select="$contents"/>
  374. </xsl:call-template>
  375. </xsl:otherwise>
  376. </xsl:choose>
  377. </cell>
  378. <!-- * For each instance of a rowspan attribute found, we create N -->
  379. <!-- * dummy cells, where N is equal to the value of the rowspan. -->
  380. <xsl:if test="@rowspan and @rowspan > 0">
  381. <!-- * If this cell is preceded in the same row by cells that -->
  382. <!-- * have colspan attributes, then we need to calculate the -->
  383. <!-- * "offset" caused by those colspan instances; the formula -->
  384. <!-- * is to (1) check for all the preceding cells that have -->
  385. <!-- * colspan attributes that are not empty and which have a -->
  386. <!-- * value greater than 1, then (2) take the sum of the values -->
  387. <!-- * of all those colspan attributes, and subtract from that -->
  388. <!-- * the number of such colspan instances found. -->
  389. <xsl:variable name="colspan-offset">
  390. <xsl:value-of
  391. select="sum(preceding-sibling::td[@colspan != ''
  392. and @colspan > 1]/@colspan) -
  393. count(preceding-sibling::td[@colspan != ''
  394. and @colspan > 1]/@colspan)"/>
  395. </xsl:variable>
  396. <xsl:call-template name="create.dummy.cells">
  397. <xsl:with-param name="row" select="$row + 1"/>
  398. <!-- * The slot value on each dummy cell must be offset by the -->
  399. <!-- * value of $colspan-offset to adjust for preceding colpans -->
  400. <xsl:with-param name="slot" select="$slot + $colspan-offset"/>
  401. <xsl:with-param name="colspan" select="@colspan"/>
  402. <xsl:with-param name="rowspan" select="@rowspan"/>
  403. </xsl:call-template>
  404. </xsl:if>
  405. </xsl:template>
  406. <xsl:template name="create.dummy.cells">
  407. <xsl:param name="row"/>
  408. <xsl:param name="slot"/>
  409. <xsl:param name="colspan"/>
  410. <xsl:param name="rowspan"/>
  411. <xsl:choose>
  412. <xsl:when test="$rowspan > 1">
  413. <!-- * Tail recurse until we have no more rowspans, creating -->
  414. <!-- * an empty dummy cell each time. The type value, '^' -->
  415. <!-- * is the marker that tbl(1) uses to indicate a -->
  416. <!-- * "vertically spanned heading". -->
  417. <cell row="{$row}" slot="{$slot}" type="^" colspan="{@colspan}"/>
  418. <xsl:call-template name="create.dummy.cells">
  419. <xsl:with-param name="row" select="$row + 1"/>
  420. <xsl:with-param name="slot" select="$slot"/>
  421. <xsl:with-param name="colspan" select="$colspan"/>
  422. <xsl:with-param name="rowspan" select="$rowspan - 1"/>
  423. </xsl:call-template>
  424. </xsl:when>
  425. </xsl:choose>
  426. </xsl:template>
  427. <!-- * ============================================================== -->
  428. <!-- * Build the "format section" for the table -->
  429. <!-- * ============================================================== -->
  430. <!-- * Description from the tbl(1) guide: -->
  431. <!-- * -->
  432. <!-- * "The format section of the table specifies the layout of the -->
  433. <!-- * columns. Each line in this section corresponds to one line of -->
  434. <!-- * the table... and each line contains a key-letter for each -->
  435. <!-- * column of the table." -->
  436. <xsl:template name="create.table.format">
  437. <xsl:param name="cells"/>
  438. <xsl:apply-templates mode="table.format" select="$cells"/>
  439. <!-- * last line of table format section must end with a dot -->
  440. <xsl:text>.</xsl:text>
  441. </xsl:template>
  442. <xsl:template match="cell" mode="table.format">
  443. <xsl:choose>
  444. <xsl:when test="preceding-sibling::cell[1]/@row != @row">
  445. <!-- * If the value of the row attribute on this cell is -->
  446. <!-- * different from the value of that on the previous cell, it -->
  447. <!-- * means we have a new row. So output a line break. -->
  448. <xsl:text>&#xa;</xsl:text>
  449. </xsl:when>
  450. <xsl:otherwise>
  451. <!-- * If this isn't the first cell, output a space before it to -->
  452. <!-- * separate it from the preceding key letter. -->
  453. <xsl:if test="position() != 1">
  454. <xsl:text> </xsl:text>
  455. </xsl:if>
  456. </xsl:otherwise>
  457. </xsl:choose>
  458. <!-- * Select an appropriate "alignment" key letter based on this -->
  459. <!-- * cell's attributes. -->
  460. <xsl:choose>
  461. <xsl:when test="@type = '^'">
  462. <xsl:text>^</xsl:text>
  463. </xsl:when>
  464. <xsl:when test="@align = 'center'">
  465. <xsl:text>c</xsl:text>
  466. </xsl:when>
  467. <xsl:when test="@align = 'right'">
  468. <xsl:text>r</xsl:text>
  469. </xsl:when>
  470. <xsl:when test="@align = 'char'">
  471. <xsl:text>n</xsl:text>
  472. </xsl:when>
  473. <xsl:otherwise>
  474. <!-- * Default to left alignment. -->
  475. <xsl:text>l</xsl:text>
  476. </xsl:otherwise>
  477. </xsl:choose>
  478. <!-- * By default, tbl(1) vertically centers cell contents within -->
  479. <!-- * their cells; the "t" key latter tells it to top-align the -->
  480. <!-- * contents instead. Note that tbl(1) has no options for -->
  481. <!-- * bottom or baseline alignment. -->
  482. <xsl:if test="@valign = 'top'">
  483. <xsl:text>t</xsl:text>
  484. </xsl:if>
  485. <xsl:if test="@class = 'th'">
  486. <!-- * If this is a heading row, generate a font indicator (B or I), -->
  487. <!-- * or if the value of $tbl.font.headings is empty, nothing. -->
  488. <xsl:value-of select="$tbl.font.headings"/>
  489. </xsl:if>
  490. <!-- * We only need to deal with colspans whose value is greater -->
  491. <!-- * than one (a colspan="1" is the same as having no colspan -->
  492. <!-- * attribute at all). -->
  493. <xsl:if test="@colspan > 1">
  494. <xsl:call-template name="process.colspan">
  495. <xsl:with-param name="colspan" select="@colspan - 1"/>
  496. <xsl:with-param name="type" select="@type"/>
  497. </xsl:call-template>
  498. </xsl:if>
  499. </xsl:template>
  500. <xsl:template name="process.colspan">
  501. <xsl:param name="colspan"/>
  502. <xsl:param name="type"/>
  503. <!-- * Output a space to separate this key letter from preceding one. -->
  504. <xsl:text> </xsl:text>
  505. <xsl:choose>
  506. <xsl:when test="$type = '^'">
  507. <!-- * A '^' ("vertically spanned heading" marker) indicates -->
  508. <!-- * that the "parent" of this spanned cell is a dummy cell; -->
  509. <!-- * in this case, we need to generate a '^' instead of the -->
  510. <!-- * normal 's'. -->
  511. <xsl:text>^</xsl:text>
  512. </xsl:when>
  513. <xsl:otherwise>
  514. <!-- * s = 'spanned heading' -->
  515. <xsl:text>s</xsl:text>
  516. </xsl:otherwise>
  517. </xsl:choose>
  518. <xsl:if test="$colspan > 1">
  519. <!-- * Tail recurse until we have no more colspans, outputting -->
  520. <!-- * another marker each time. -->
  521. <xsl:call-template name="process.colspan">
  522. <xsl:with-param name="colspan" select="$colspan - 1"/>
  523. <xsl:with-param name="type" select="$type"/>
  524. </xsl:call-template>
  525. </xsl:if>
  526. </xsl:template>
  527. <!-- * ============================================================== -->
  528. <!-- * colgroup and col -->
  529. <!-- * ============================================================== -->
  530. <!-- * We currently don't do anything with colgroup. Not sure if it -->
  531. <!-- * is widely used enough to bother adding support for it -->
  532. <xsl:template match="colgroup"/>
  533. <xsl:template match="col"/>
  534. <!-- * ============================================================== -->
  535. <!-- * table footnotes -->
  536. <!-- * ============================================================== -->
  537. <xsl:template match="footnote" mode="table.footnote.mode">
  538. <xsl:variable name="footnotes" select=".//footnote"/>
  539. <xsl:variable name="table.footnotes"
  540. select=".//tgroup//footnote"/>
  541. <xsl:value-of select="$man.table.footnotes.divider"/>
  542. <xsl:text>&#10;</xsl:text>
  543. <xsl:text>.br&#10;</xsl:text>
  544. <xsl:apply-templates select="*[1]" mode="footnote.body.number"/>
  545. <xsl:apply-templates select="*[position() &gt; 1]"/>
  546. </xsl:template>
  547. <!-- * The following template for footnote.body.number mode was just -->
  548. <!-- * lifted from the HTML stylesheets with some minor adjustments -->
  549. <xsl:template match="*" mode="footnote.body.number">
  550. <xsl:variable name="name">
  551. <xsl:text>ftn.</xsl:text>
  552. <xsl:call-template name="object.id">
  553. <xsl:with-param name="object" select="ancestor::footnote"/>
  554. </xsl:call-template>
  555. </xsl:variable>
  556. <xsl:variable name="href">
  557. <xsl:text>#</xsl:text>
  558. <xsl:call-template name="object.id">
  559. <xsl:with-param name="object" select="ancestor::footnote"/>
  560. </xsl:call-template>
  561. </xsl:variable>
  562. <xsl:variable name="footnote.mark">
  563. <xsl:text>[</xsl:text>
  564. <xsl:apply-templates select="ancestor::footnote"
  565. mode="footnote.number"/>
  566. <xsl:text>]&#10;</xsl:text>
  567. </xsl:variable>
  568. <xsl:variable name="html">
  569. <xsl:apply-templates select="."/>
  570. </xsl:variable>
  571. <xsl:choose>
  572. <xsl:when test="$exsl.node.set.available != 0">
  573. <xsl:variable name="html-nodes" select="exsl:node-set($html)"/>
  574. <xsl:choose>
  575. <xsl:when test="$html-nodes//p">
  576. <xsl:apply-templates select="$html-nodes" mode="insert.html.p">
  577. <xsl:with-param name="mark" select="$footnote.mark"/>
  578. </xsl:apply-templates>
  579. </xsl:when>
  580. <xsl:otherwise>
  581. <xsl:apply-templates select="$html-nodes" mode="insert.html.text">
  582. <xsl:with-param name="mark" select="$footnote.mark"/>
  583. </xsl:apply-templates>
  584. </xsl:otherwise>
  585. </xsl:choose>
  586. </xsl:when>
  587. <xsl:otherwise>
  588. <xsl:copy-of select="$html"/>
  589. </xsl:otherwise>
  590. </xsl:choose>
  591. </xsl:template>
  592. <!-- * The HTML stylesheets output <sup><a>...</a></sup> around -->
  593. <!-- * footnote markers in tables -->
  594. <xsl:template match="th/sup">
  595. <xsl:apply-templates/>
  596. </xsl:template>
  597. <xsl:template match="a">
  598. <xsl:apply-templates/>
  599. </xsl:template>
  600. </xsl:stylesheet>