Created
December 21, 2016 14:43
-
-
Save xokomola/59a590a423b86bb3ea809c1b03706c4b to your computer and use it in GitHub Desktop.
Create ODS Spreadsheet with XQuery and BaseX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<tables> | |
<table name="Sheet 1"> | |
<thead> | |
<tr> | |
<td>A</td> | |
<td>B</td> | |
<td>C</td> | |
</tr> | |
</thead> | |
<tbody> | |
<tr> | |
<td>10</td> | |
<td>20</td> | |
<td>30</td> | |
</tr> | |
</tbody> | |
</table> | |
</tables> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<xsl:stylesheet | |
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" | |
xmlns:xs="http://www.w3.org/2001/XMLSchema" | |
xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" | |
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" | |
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" | |
xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" | |
exclude-result-prefixes="xs" | |
version="2.0"> | |
<xsl:output method="xml" indent="yes"/> | |
<xsl:strip-space elements="*"/> | |
<xsl:param name="template" as="xs:string"/> | |
<xsl:variable name="content" select="doc($template)" as="document-node()"/> | |
<xsl:template match="/"> | |
<xsl:apply-templates select="$content/office:document-content"> | |
<xsl:with-param name="tables" select="tables/table" tunnel="yes"/> | |
</xsl:apply-templates> | |
</xsl:template> | |
<xsl:template match="office:spreadsheet"> | |
<xsl:param name="tables" tunnel="yes" as="element(table)*"/> | |
<xsl:variable name="template" select="table:table[1]"/> | |
<xsl:copy> | |
<xsl:copy-of select="@*"/> | |
<xsl:for-each select="$tables"> | |
<xsl:apply-templates select="$template"> | |
<xsl:with-param name="table" select="." tunnel="yes"/> | |
</xsl:apply-templates> | |
</xsl:for-each> | |
</xsl:copy> | |
</xsl:template> | |
<xsl:template match="table:table"> | |
<xsl:param name="table" tunnel="yes" as="element(table)"/> | |
<xsl:copy> | |
<xsl:copy-of select="@*"/> | |
<xsl:attribute name="table:name" select="$table/@name"/> | |
<xsl:apply-templates/> | |
</xsl:copy> | |
</xsl:template> | |
<xsl:template match="table:table-row"/> | |
<xsl:template match="table:table-row[2]"> | |
<xsl:param name="table" tunnel="yes"/> | |
<xsl:call-template name="create-data-rows"> | |
<xsl:with-param name="table" select="$table"/> | |
<xsl:with-param name="model" select="."/> | |
</xsl:call-template> | |
</xsl:template> | |
<xsl:template match="table:table-row[1]"> | |
<xsl:param name="table" tunnel="yes"/> | |
<xsl:if test="exists($table/thead/tr)"> | |
<xsl:call-template name="create-header-rows"> | |
<xsl:with-param name="table" select="$table"/> | |
<xsl:with-param name="model" select="."/> | |
</xsl:call-template> | |
</xsl:if> | |
</xsl:template> | |
<xsl:template name="create-header-rows"> | |
<xsl:param name="table" as="element(table)"/> | |
<xsl:param name="model" as="element(table:table-row)"/> | |
<xsl:variable name="template-row" select="$model"/> | |
<xsl:variable name="template-cell" select="$model/table:table-cell[1]"/> | |
<xsl:for-each select="$table/thead/tr"> | |
<xsl:variable name="row" select="."/> | |
<xsl:for-each select="$template-row"> | |
<xsl:copy> | |
<xsl:copy-of select="@*"/> | |
<xsl:for-each select="$row/td"> | |
<xsl:apply-templates select="$template-cell"> | |
<xsl:with-param name="cell" select="."/> | |
</xsl:apply-templates> | |
</xsl:for-each> | |
</xsl:copy> | |
</xsl:for-each> | |
</xsl:for-each> | |
</xsl:template> | |
<xsl:template name="create-data-rows"> | |
<xsl:param name="table" as="element(table)"/> | |
<xsl:param name="model" as="element(table:table-row)"/> | |
<xsl:variable name="template-row" select="$model"/> | |
<xsl:variable name="template-cell" select="$model/table:table-cell[1]"/> | |
<xsl:for-each select="$table/tbody/tr"> | |
<xsl:variable name="row" select="."/> | |
<xsl:for-each select="$template-row"> | |
<xsl:copy> | |
<xsl:copy-of select="@*"/> | |
<xsl:for-each select="$row/td"> | |
<xsl:apply-templates select="$template-cell"> | |
<xsl:with-param name="cell" select="."/> | |
</xsl:apply-templates> | |
</xsl:for-each> | |
</xsl:copy> | |
</xsl:for-each> | |
</xsl:for-each> | |
</xsl:template> | |
<xsl:template match="table:table-cell"> | |
<xsl:param name="cell"/> | |
<xsl:copy> | |
<!-- TODO: may need to 'cook up' a set of default attributes --> | |
<!-- such as: office:value-type="string" calcext:value-type="string" --> | |
<xsl:apply-templates select="@* except (@table:number-columns-repeated, @table:number-columns-spanned)"/> | |
<text:p><xsl:value-of select="$cell"/></text:p> | |
</xsl:copy> | |
</xsl:template> | |
<xsl:template match="@office:value-type"> | |
<xsl:attribute name="office:value-type" select="'string'"/> | |
</xsl:template> | |
<xsl:template match="@calcext:value-type"> | |
<xsl:attribute name="calcext:value-type" select="'string'"/> | |
</xsl:template> | |
<xsl:template match="node()|@*"> | |
<xsl:copy> | |
<xsl:apply-templates select="@*"/> | |
<xsl:apply-templates/> | |
</xsl:copy> | |
</xsl:template> | |
</xsl:stylesheet> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare function ods:write( | |
$tables as element(tables), | |
$path as xs:string, | |
$options as map(*)) | |
as empty-sequence() | |
{ | |
let $template := file:path-to-uri(file:resolve-path(concat(file:base-dir(), 'templates/default.ods'))) | |
let $xsl := file:resolve-path(concat(file:base-dir(), 'ods-tables.xsl')) | |
let $template-dir := file:create-temp-dir('ods-', '.ods', file:temp-dir()) | |
let $extract archive:extract-to($template-dir, file:read-binary($template)) | |
for $entry in file:list($template-dir, true()) | |
where ends-with(file:path-to-uri($entry),'/content.xml') | |
let $uri := file:path-to-uri(file:resolve-path(concat($template-dir, '/', $entry))) | |
let $result := file:write($uri, xslt:transform($tables, $xsl, map { 'template': $uri })) | |
return | |
file:write-binary($path, archive:create-from($template-dir)) | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Not tested.
Copied from an internal module I use at work to quickly generate an ODS spreadsheet from a generic table structure. XLSX goes along the same lines though the XML is not as nice as for ODS (libreOffice, OpenOffice).