adorowset2ods.xsl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  3. xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
  4. xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
  5. xmlns:rs="urn:schemas-microsoft-com:rowset"
  6. xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
  7. xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
  8. xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
  9. xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
  10. xmlns:z="#RowsetSchema">
  11. <xsl:output indent="no" version="1.0" encoding="UTF-8" method="xml"/>
  12. <xsl:template match="/">
  13. <office:document office:mimetype="application/vnd.oasis.opendocument.spreadsheet" office:version="1.0">
  14. <xsl:element name="office:body">
  15. <xsl:element name="office:spreadsheet">
  16. <!-- Just a single table (sheet) with default name -->
  17. <xsl:element name="table:table">
  18. <!-- declare columns -->
  19. <xsl:for-each select="./xml/s:Schema/s:ElementType[@name='row']/s:AttributeType">
  20. <xsl:element name="table:table-column"/>
  21. </xsl:for-each>
  22. <!-- header row from Schema -->
  23. <xsl:element name="table:table-row">
  24. <xsl:for-each select="./xml/s:Schema/s:ElementType[@name='row']/s:AttributeType">
  25. <xsl:element name="table:table-cell">
  26. <xsl:attribute name="office:value-type">string</xsl:attribute>
  27. <xsl:attribute name="calcext:value-type">string</xsl:attribute>
  28. <xsl:element name="text:p">
  29. <!-- User-readable field name may be defined in optional @rs:name -->
  30. <xsl:choose>
  31. <xsl:when test="./@rs:name">
  32. <xsl:value-of select="./@rs:name"/>
  33. </xsl:when>
  34. <xsl:otherwise>
  35. <xsl:value-of select="./@name"/>
  36. </xsl:otherwise>
  37. </xsl:choose>
  38. </xsl:element>
  39. </xsl:element>
  40. </xsl:for-each>
  41. </xsl:element>
  42. <!-- Now add data itself -->
  43. <xsl:apply-templates select="./xml/rs:data"/>
  44. </xsl:element>
  45. <!-- Add autofilter to the whole range -->
  46. <xsl:element name="table:database-ranges">
  47. <xsl:element name="table:database-range">
  48. <xsl:attribute name="table:target-range-address">
  49. <xsl:call-template name="RangeName">
  50. <xsl:with-param name="rowStartNum" select="1"/>
  51. <xsl:with-param name="colStartNum" select="1"/>
  52. <xsl:with-param name="rowEndNum" select="count(/xml/rs:data/row)+1"/>
  53. <xsl:with-param name="colEndNum" select="count(/xml/s:Schema/s:ElementType[@name='row']/s:AttributeType)"/>
  54. </xsl:call-template>
  55. </xsl:attribute>
  56. <xsl:attribute name="table:display-filter-buttons">true</xsl:attribute>
  57. </xsl:element>
  58. </xsl:element>
  59. </xsl:element>
  60. </xsl:element>
  61. </office:document>
  62. </xsl:template>
  63. <xsl:template match="rs:data">
  64. <xsl:apply-templates select="./row"/>
  65. <xsl:apply-templates select="./z:row"/>
  66. </xsl:template>
  67. <xsl:template match="row|z:row">
  68. <xsl:element name="table:table-row">
  69. <!-- Store current row in a variable -->
  70. <xsl:variable name="thisRow" select="."/>
  71. <!-- Get column order from Schema -->
  72. <xsl:for-each select="/xml/s:Schema/s:ElementType[@name='row']/s:AttributeType">
  73. <xsl:element name="table:table-cell">
  74. <xsl:variable name="thisColName" select="./@name"/>
  75. <xsl:variable name="thisCellValue">
  76. <xsl:value-of select="$thisRow/@*[local-name()=$thisColName]"/>
  77. </xsl:variable>
  78. <xsl:if test="string-length($thisCellValue) &gt; 0">
  79. <xsl:variable name="thisColType">
  80. <xsl:call-template name="ValTypeFromAttributeType">
  81. <xsl:with-param name="AttributeTypeNode" select="."/>
  82. </xsl:call-template>
  83. </xsl:variable>
  84. <xsl:attribute name="office:value-type"><xsl:value-of select="$thisColType"/></xsl:attribute>
  85. <xsl:attribute name="calcext:value-type"><xsl:value-of select="$thisColType"/></xsl:attribute>
  86. <xsl:choose>
  87. <xsl:when test="$thisColType='float'">
  88. <xsl:attribute name="office:value"><xsl:value-of select="$thisCellValue"/></xsl:attribute>
  89. </xsl:when>
  90. <xsl:when test="$thisColType='date'">
  91. <!-- We need to convert '2017-04-06 00:40:40' to '2017-04-06T00:40:40', so replace space with 'T' -->
  92. <xsl:attribute name="office:date-value"><xsl:value-of select="translate($thisCellValue,' ','T')"/></xsl:attribute>
  93. </xsl:when>
  94. <xsl:when test="$thisColType='time'">
  95. <xsl:attribute name="office:time-value"><xsl:value-of select="$thisCellValue"/></xsl:attribute>
  96. </xsl:when>
  97. <xsl:when test="$thisColType='boolean'">
  98. <xsl:attribute name="office:boolean-value">
  99. <xsl:choose>
  100. <xsl:when test="$thisCellValue=0">false</xsl:when>
  101. <xsl:otherwise>true</xsl:otherwise>
  102. </xsl:choose>
  103. </xsl:attribute>
  104. </xsl:when>
  105. </xsl:choose>
  106. <xsl:element name="text:p">
  107. <xsl:value-of select="$thisCellValue"/>
  108. </xsl:element>
  109. </xsl:if>
  110. </xsl:element>
  111. </xsl:for-each>
  112. </xsl:element>
  113. </xsl:template>
  114. <!-- https://msdn.microsoft.com/en-us/library/ms675943 -->
  115. <xsl:template name="ValTypeFromAttributeType">
  116. <xsl:param name="AttributeTypeNode"/>
  117. <xsl:variable name="thisDataType">
  118. <xsl:choose>
  119. <xsl:when test="$AttributeTypeNode/@dt:type"><xsl:value-of select="$AttributeTypeNode/@dt:type"/></xsl:when>
  120. <xsl:when test="$AttributeTypeNode/s:datatype"><xsl:value-of select="$AttributeTypeNode/s:datatype/@dt:type"/></xsl:when>
  121. <xsl:otherwise>string</xsl:otherwise>
  122. </xsl:choose>
  123. </xsl:variable>
  124. <xsl:call-template name="XMLDataType2ValType">
  125. <xsl:with-param name="XMLDataType" select="$thisDataType"/>
  126. </xsl:call-template>
  127. </xsl:template>
  128. <!-- https://www.w3.org/TR/1998/NOTE-XML-data-0105/#API -->
  129. <xsl:template name="XMLDataType2ValType">
  130. <xsl:param name="XMLDataType"/>
  131. <xsl:choose>
  132. <xsl:when test="$XMLDataType='number'">float</xsl:when>
  133. <xsl:when test="$XMLDataType='int'">float</xsl:when>
  134. <xsl:when test="starts-with($XMLDataType, 'float')">float</xsl:when>
  135. <xsl:when test="starts-with($XMLDataType, 'fixed')">float</xsl:when>
  136. <xsl:when test="$XMLDataType='i1'">float</xsl:when>
  137. <xsl:when test="$XMLDataType='i2'">float</xsl:when>
  138. <xsl:when test="$XMLDataType='i4'">float</xsl:when>
  139. <xsl:when test="$XMLDataType='i8'">float</xsl:when>
  140. <xsl:when test="$XMLDataType='ui1'">float</xsl:when>
  141. <xsl:when test="$XMLDataType='ui2'">float</xsl:when>
  142. <xsl:when test="$XMLDataType='ui4'">float</xsl:when>
  143. <xsl:when test="$XMLDataType='ui8'">float</xsl:when>
  144. <xsl:when test="$XMLDataType='r4'">float</xsl:when>
  145. <xsl:when test="$XMLDataType='r8'">float</xsl:when>
  146. <xsl:when test="$XMLDataType='datetime'">date</xsl:when>
  147. <xsl:when test="starts-with($XMLDataType, 'dateTime')">date</xsl:when>
  148. <xsl:when test="starts-with($XMLDataType, 'date')">date</xsl:when>
  149. <xsl:when test="starts-with($XMLDataType, 'time')">time</xsl:when>
  150. <xsl:when test="$XMLDataType='boolean'">boolean</xsl:when>
  151. <xsl:otherwise>string</xsl:otherwise>
  152. </xsl:choose>
  153. </xsl:template>
  154. <!-- A utility to convert a column number (e.g. 27; 1-based) to column name (like AA) -->
  155. <xsl:template name="ColNum2Name">
  156. <xsl:param name="num"/>
  157. <xsl:if test="$num > 0">
  158. <xsl:call-template name="ColNum2Name">
  159. <xsl:with-param name="num" select="floor($num div 26)"/>
  160. </xsl:call-template>
  161. <xsl:choose>
  162. <xsl:when test="$num mod 26 = 1">A</xsl:when>
  163. <xsl:when test="$num mod 26 = 2">B</xsl:when>
  164. <xsl:when test="$num mod 26 = 3">C</xsl:when>
  165. <xsl:when test="$num mod 26 = 4">D</xsl:when>
  166. <xsl:when test="$num mod 26 = 5">E</xsl:when>
  167. <xsl:when test="$num mod 26 = 6">F</xsl:when>
  168. <xsl:when test="$num mod 26 = 7">G</xsl:when>
  169. <xsl:when test="$num mod 26 = 8">H</xsl:when>
  170. <xsl:when test="$num mod 26 = 9">I</xsl:when>
  171. <xsl:when test="$num mod 26 = 10">J</xsl:when>
  172. <xsl:when test="$num mod 26 = 11">K</xsl:when>
  173. <xsl:when test="$num mod 26 = 12">L</xsl:when>
  174. <xsl:when test="$num mod 26 = 13">M</xsl:when>
  175. <xsl:when test="$num mod 26 = 14">N</xsl:when>
  176. <xsl:when test="$num mod 26 = 15">O</xsl:when>
  177. <xsl:when test="$num mod 26 = 16">P</xsl:when>
  178. <xsl:when test="$num mod 26 = 17">Q</xsl:when>
  179. <xsl:when test="$num mod 26 = 18">R</xsl:when>
  180. <xsl:when test="$num mod 26 = 19">S</xsl:when>
  181. <xsl:when test="$num mod 26 = 20">T</xsl:when>
  182. <xsl:when test="$num mod 26 = 21">U</xsl:when>
  183. <xsl:when test="$num mod 26 = 22">V</xsl:when>
  184. <xsl:when test="$num mod 26 = 23">W</xsl:when>
  185. <xsl:when test="$num mod 26 = 24">X</xsl:when>
  186. <xsl:when test="$num mod 26 = 25">Y</xsl:when>
  187. <xsl:otherwise>Z</xsl:otherwise><!-- 0 -->
  188. </xsl:choose>
  189. </xsl:if>
  190. </xsl:template>
  191. <!-- A utility to convert a cell address (e.g. row 2, column 27) to cell name (like AA2) -->
  192. <xsl:template name="CellName">
  193. <xsl:param name="rowNum"/>
  194. <xsl:param name="colNum"/>
  195. <xsl:call-template name="ColNum2Name">
  196. <xsl:with-param name="num" select="$colNum"/>
  197. </xsl:call-template>
  198. <xsl:value-of select="$rowNum"/>
  199. </xsl:template>
  200. <!-- A utility to convert a range given in terms of numbers (e.g. row 1, column 1 to row 2, column 27) to range name (like A1:AA2) -->
  201. <xsl:template name="RangeName">
  202. <xsl:param name="rowStartNum"/>
  203. <xsl:param name="colStartNum"/>
  204. <xsl:param name="rowEndNum"/>
  205. <xsl:param name="colEndNum"/>
  206. <xsl:call-template name="CellName">
  207. <xsl:with-param name="rowNum" select="$rowStartNum"/>
  208. <xsl:with-param name="colNum" select="$colStartNum"/>
  209. </xsl:call-template>
  210. <xsl:text>:</xsl:text>
  211. <xsl:call-template name="CellName">
  212. <xsl:with-param name="rowNum" select="$rowEndNum"/>
  213. <xsl:with-param name="colNum" select="$colEndNum"/>
  214. </xsl:call-template>
  215. </xsl:template>
  216. </xsl:stylesheet>