functions.xsl 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--
  3. This file is part of the DITA Open Toolkit project.
  4. Copyright 2016 Eero Helenius
  5. See the accompanying LICENSE file for applicable license.
  6. -->
  7. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  8. xmlns:xs="http://www.w3.org/2001/XMLSchema"
  9. xmlns:dita-ot="http://dita-ot.sourceforge.net/ns/201007/dita-ot"
  10. xmlns:table="http://dita-ot.sourceforge.net/ns/201007/dita-ot/table"
  11. xmlns:simpletable="http://dita-ot.sourceforge.net/ns/201007/dita-ot/simpletable"
  12. version="2.0"
  13. exclude-result-prefixes="xs dita-ot table">
  14. <xsl:variable name="HTML_ID_SEPARATOR" select="'__'"/>
  15. <xsl:function name="dita-ot:generate-html-id" as="xs:string">
  16. <xsl:param name="element" as="element()"/>
  17. <xsl:sequence
  18. select="if (exists($element/@id))
  19. then dita-ot:get-prefixed-id($element, $element/@id)
  20. else dita-ot:generate-stable-id($element)"/>
  21. </xsl:function>
  22. <xsl:function name="dita-ot:generate-id" as="xs:string">
  23. <xsl:param name="topic" as="xs:string?"/>
  24. <xsl:param name="element" as="xs:string?"/>
  25. <xsl:value-of select="string-join(($topic, $element), $HTML_ID_SEPARATOR)"/>
  26. </xsl:function>
  27. <xsl:function name="dita-ot:get-prefixed-id" as="xs:string">
  28. <xsl:param name="element" as="element()"/>
  29. <xsl:param name="id" as="xs:string"/>
  30. <xsl:choose>
  31. <xsl:when test="contains($element/@class, ' topic/topic')">
  32. <xsl:value-of select="$element/@id"/>
  33. </xsl:when>
  34. <xsl:otherwise>
  35. <xsl:sequence select="dita-ot:generate-id($element/ancestor::*[contains(@class, ' topic/topic ')][1]/@id, $id)"/>
  36. </xsl:otherwise>
  37. </xsl:choose>
  38. </xsl:function>
  39. <xsl:function name="dita-ot:generate-stable-id" as="xs:string">
  40. <xsl:param name="element" as="element()"/>
  41. <xsl:variable name="topic" select="$element/ancestor-or-self::*[contains(@class, ' topic/topic ')][1]" as="element()"/>
  42. <xsl:variable name="parent-element" select="$element/ancestor-or-self::*[@id][1][not(. is $topic)]" as="element()?"/>
  43. <xsl:variable name="closest" select="($parent-element, $topic)[1]" as="element()"/>
  44. <xsl:variable name="index" select="count($closest/descendant::*[local-name() = local-name($element)][. &lt;&lt; $element]) + 1" as="xs:integer"/>
  45. <xsl:sequence select="dita-ot:generate-id($topic/@id, string-join(($parent-element/@id, local-name($element), string($index)), $HTML_ID_SEPARATOR))"/>
  46. </xsl:function>
  47. <xsl:function name="table:is-tbody-entry" as="xs:boolean">
  48. <xsl:param name="el" as="element()"/>
  49. <xsl:sequence select="
  50. contains($el/@class, ' topic/entry ') and contains($el/../../@class, ' topic/tbody ')
  51. "/>
  52. </xsl:function>
  53. <xsl:function name="table:is-thead-entry" as="xs:boolean">
  54. <xsl:param name="el" as="element()"/>
  55. <xsl:sequence select="
  56. contains($el/@class, ' topic/entry ') and contains($el/../../@class, ' topic/thead ')
  57. "/>
  58. </xsl:function>
  59. <xsl:function name="table:get-current-table" as="element()">
  60. <xsl:param name="node" as="node()"/>
  61. <xsl:sequence select="
  62. $node/ancestor-or-self::*[contains(@class, ' topic/table ')][1]
  63. "/>
  64. </xsl:function>
  65. <xsl:function name="table:get-current-tgroup" as="element()">
  66. <xsl:param name="node" as="node()"/>
  67. <xsl:sequence select="
  68. $node/ancestor-or-self::*[contains(@class, ' topic/tgroup ')][1]
  69. "/>
  70. </xsl:function>
  71. <xsl:function name="table:is-row-header" as="xs:boolean">
  72. <xsl:param name="entry" as="element()"/>
  73. <xsl:sequence select="
  74. table:get-current-table($entry)/@rowheader eq 'firstcol'
  75. and xs:integer($entry/@dita-ot:x) eq 1
  76. "/>
  77. </xsl:function>
  78. <xsl:function name="table:get-entry-colspec" as="element()?">
  79. <xsl:param name="entry" as="element()"/>
  80. <xsl:sequence select="
  81. table:get-current-tgroup($entry)/*[contains(@class, ' topic/colspec ')]
  82. [@colname eq $entry/@colname]
  83. "/>
  84. </xsl:function>
  85. <xsl:function name="table:get-ending-colspec" as="element()?">
  86. <xsl:param name="entry" as="element()"/>
  87. <xsl:sequence select="
  88. table:get-current-tgroup($entry)/*[contains(@class, ' topic/colspec ')]
  89. [@colname eq $entry/@nameend]
  90. "/>
  91. </xsl:function>
  92. <xsl:function name="table:get-entry-align" as="attribute(align)?">
  93. <xsl:param name="el" as="element()"/>
  94. <xsl:sequence select="
  95. ($el/@align,
  96. table:get-current-tgroup($el)/@align,
  97. table:get-entry-colspec($el)/@align)[1]
  98. "/>
  99. </xsl:function>
  100. <xsl:function name="table:get-entry-colsep" as="attribute(colsep)?">
  101. <xsl:param name="el" as="element()"/>
  102. <xsl:sequence select="
  103. ($el/@colsep,
  104. table:get-entry-colspec($el)/@colsep,
  105. table:get-current-table($el)/@colsep,
  106. table:get-current-tgroup($el)/@colsep)[1]
  107. "/>
  108. </xsl:function>
  109. <xsl:function name="table:get-entry-rowsep" as="attribute(rowsep)?">
  110. <xsl:param name="el" as="element()"/>
  111. <xsl:sequence select="
  112. ($el/@rowsep,
  113. table:get-entry-colspec($el)/@rowsep,
  114. table:get-current-table($el)/@rowsep,
  115. table:get-current-tgroup($el)/@rowsep)[1]
  116. "/>
  117. </xsl:function>
  118. <xsl:function name="table:find-entry-end-column" as="xs:integer">
  119. <xsl:param name="ctx" as="element()"/>
  120. <xsl:choose>
  121. <xsl:when test="$ctx/@nameend">
  122. <xsl:sequence select="xs:integer(table:get-ending-colspec($ctx)/@colnum)"/>
  123. </xsl:when>
  124. <xsl:otherwise>
  125. <xsl:sequence select="xs:integer($ctx/@dita-ot:x)"/>
  126. </xsl:otherwise>
  127. </xsl:choose>
  128. </xsl:function>
  129. <!-- Return true if an entry is entirely within the X or Y span of the header.
  130. If entry ends before the header, or starts after the header, no match, otherwise there is overlap. -->
  131. <xsl:function name="table:entry-within-range" as="xs:boolean">
  132. <xsl:param name="entrystart" as="xs:integer"/>
  133. <xsl:param name="entryend" as="xs:integer"/>
  134. <xsl:param name="headerstart" as="xs:integer"/>
  135. <xsl:param name="headerend" as="xs:integer"/>
  136. <xsl:sequence select="not($entryend lt $headerstart or $entrystart gt $headerend)"/>
  137. </xsl:function>
  138. <xsl:function name="table:get-matching-thead-headers" as="xs:string*">
  139. <xsl:param name="ctx" as="element()"/>
  140. <xsl:variable name="startposition" select="xs:integer($ctx/@dita-ot:x)"/>
  141. <xsl:variable name="endposition" select="table:find-entry-end-column($ctx)"/>
  142. <xsl:for-each select="$ctx/../../../*[contains(@class,' topic/thead ')]/*[contains(@class,' topic/row ')]/*[contains(@class,' topic/entry ')]">
  143. <xsl:variable name="headstart" select="xs:integer(@dita-ot:x)"/>
  144. <xsl:variable name="headend" select="table:find-entry-end-column(.)"/>
  145. <xsl:if test="table:entry-within-range($startposition, $endposition, $headstart, $headend)">
  146. <xsl:value-of select="dita-ot:generate-html-id(.)"/>
  147. </xsl:if>
  148. </xsl:for-each>
  149. </xsl:function>
  150. <xsl:function name="table:get-matching-row-headers" as="xs:string*">
  151. <xsl:param name="ctx" as="element()"/>
  152. <xsl:if test="table:get-current-table($ctx)/@rowheader='firstcol' and
  153. $ctx/@dita-ot:x != '1' and
  154. not(table:is-thead-entry($ctx))">
  155. <xsl:variable name="startposition" select="xs:integer($ctx/@dita-ot:y)"/>
  156. <xsl:variable name="endposition" select="if ($ctx/@morerows) then ($startposition + xs:integer($ctx/@morerows)) else $startposition"/>
  157. <xsl:choose>
  158. <xsl:when test="($startposition = $endposition) and $ctx/preceding-sibling::*[contains(@class,' topic/entry ')][@dita-ot:x = '1']">
  159. <!-- Quick result for common simplest case: no spanning and first-col row header is in this row -->
  160. <xsl:value-of select="dita-ot:generate-html-id($ctx/preceding-sibling::*[contains(@class,' topic/entry ')][@dita-ot:x ='1'])"/>
  161. </xsl:when>
  162. <xsl:otherwise>
  163. <xsl:for-each select="$ctx/../../*[contains(@class,' topic/row ')]/*[contains(@class,' topic/entry ')][@dita-ot:x='1']">
  164. <xsl:variable name="headstart" select="xs:integer(@dita-ot:y)"/>
  165. <xsl:variable name="headend" select="if (@morerows) then ($headstart + xs:integer(@morerows)) else $headstart"/>
  166. <xsl:if test="table:entry-within-range($startposition, $endposition, $headstart, $headend)">
  167. <xsl:value-of select="dita-ot:generate-html-id(.)"/>
  168. </xsl:if>
  169. </xsl:for-each>
  170. </xsl:otherwise>
  171. </xsl:choose>
  172. </xsl:if>
  173. </xsl:function>
  174. <xsl:function name="simpletable:is-body-entry" as="xs:boolean">
  175. <xsl:param name="el" as="element()"/>
  176. <xsl:sequence select="
  177. contains($el/@class, ' topic/stentry ') and contains($el/../@class, ' topic/strow ')
  178. "/>
  179. </xsl:function>
  180. <xsl:function name="simpletable:is-head-entry" as="xs:boolean">
  181. <xsl:param name="el" as="element()"/>
  182. <xsl:sequence select="
  183. contains($el/@class, ' topic/stentry ') and contains($el/../@class, ' topic/sthead ')
  184. "/>
  185. </xsl:function>
  186. <xsl:function name="simpletable:get-current-table" as="element()">
  187. <xsl:param name="node" as="node()"/>
  188. <xsl:sequence select="
  189. $node/ancestor-or-self::*[contains(@class, ' topic/simpletable ')][1]
  190. "/>
  191. </xsl:function>
  192. <xsl:function name="simpletable:is-keycol-entry" as="xs:boolean">
  193. <xsl:param name="entry" as="element()"/>
  194. <xsl:variable name="table" as="element()"
  195. select="simpletable:get-current-table($entry)"/>
  196. <xsl:sequence select="
  197. $table/@keycol and xs:integer($table/@keycol) eq count($entry/preceding-sibling::*) + 1
  198. "/>
  199. </xsl:function>
  200. <xsl:function name="dita-ot:normalize-href" as="xs:string?">
  201. <xsl:param name="href" as="xs:string"/>
  202. <xsl:value-of select="replace(translate($href, '\', '/'), ' ', '%20')"/>
  203. </xsl:function>
  204. </xsl:stylesheet>