-
Notifications
You must be signed in to change notification settings - Fork 10
Best practice for writing Excel XML
foglcz edited this page Apr 22, 2013
·
8 revisions
Always prepare and completely finalize the excel template, in excel and on production machines. Once you start implementing, there's no going back.
The generic structure which we usually use is as follows:
- static.xsl, containing two variables -
themes
andstyles
, with contents of respective .xml files - template.xsl, containing the actual transformation:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:include href="engine/2012.engine.xsl" />
<xsl:include href="static.xsl" />
<!-- put your data-preprocessing in here -->
<xsl:variable name="images">
<!-- generate <image> structure in here based on data -->
</xsl:variable>
<xsl:variable name="contents">
<!-- put your worksheet generation in here -->
</xsl:variable>
<xsl:template match="/">
<xsl:call-template name="generate_excel">
<xsl:with-param name="author">ACME Corp.</xsl:with-param>
<xsl:with-param name="themes"><xsl:copy-of select="$themes" /></xsl:with-param>
<xsl:with-param name="styles"><xsl:copy-of select="$styles" /></xsl:with-param>
<xsl:with-param name="images"><xsl:copy-of select="$images" /></xsl:with-param>
<xsl:with-param name="sheetContents"><xsl:copy-of select="$contents" /></xsl:with-param>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
When generating the worksheet, the structure of office XML is pretty simple:
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" mc:Ignorable="x14ac">
<sheetPr codeName="Sheet2"/>
<dimension>
<xsl:attribute name="ref">
<xsl:text>A1:</xsl:text>
<!-- calculate bottom right corner here. In our case it would be always AE<something> -->
<xsl:text>AE</xsl:text>
<xsl:value-of select="count(data/data) * 2 + 10" />
</xsl:attribute>
</dimension>
<!-- <sheetViews>, <sheetFormatPr>, <cols> parameters here.
copy/pasted from the template excel -->
<sheetData>
<xsl:for-each select="data/data">
<xsl:variable name="rowNr" select="(position()-1) * 2 + 10" /> <!-- one row of data is two rows within excel, starting from row 10 -->
<row r="{$rowNr}" spans="{$rowNr}:31" ht="27" customHeight="1"> <!-- the span :31 exuals to AE column -->
<c r="A{$rowNr}" s="12" t="inlineStr">
<is><t>Static text</t></is>
</c>
<c r="B{$rowNr}" s="12" t="inlineStr">
<is><t><xsl:value-of select="some_node" /></t></is>
</c>
<!-- column C contains the current date -->
<c r="C{$rowNr}" s="41">
<f ca="1">
<xsl:text>DATEVALUE("</xsl:text>
<xsl:value-of select="format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]')" />
<xsl:text>")</xsl:text>
</f>
</c>
<!-- And column D contains any other function -->
<c r="D{$rowNr}" s="42">
<f ca="1">
<xsl:text>RAND()</xsl:text>
</f>
</c>
</row>
<!-- The data row is always separated by blank row -->
<row r="{$rowNr + 1}" spans="1:31" ht="41.25" customHeight="1" thickBot="1" x14ac:dyDescent="0.3"/>
</xsl:for-each>
</sheetData>
<!-- If you're merging cells, you will want the following: -->
<mergeCells count="{count(data/data)}">
<xsl:for-each select="data/data">
<xsl:variable name="rowNr" select="(position()-1) * 2 + 10" />
<mergeCell ref="{E$rowNr}:G{$rowNr}"/>
</xsl:for-each>
</mergeCells>
<!-- Following is static. DON'T CHANGE THE ORDER OF ARGUMENTS!! -->
<phoneticPr fontId="9" type="noConversion"/>
<pageMargins left="0.19685039370078741" right="0" top="0.23622047244094491" bottom="0" header="0" footer="0"/>
<pageSetup paperSize="9" scale="70" fitToHeight="10000" orientation="landscape" r:id="rId2"/>
<drawing r:id="rId1"/>
</worksheet>
You don't want to change order of xml nodes! Yeah, it's xml, but it's microsoft's XML implementation. In example, following will result in invalid document:
<drawing r:id="rId1"/>
<pageSetup paperSize="9" scale="70" fitToHeight="10000" orientation="landscape" r:id="rId2"/>
While the following code is ok:
<pageSetup paperSize="9" scale="70" fitToHeight="10000" orientation="landscape" r:id="rId2"/>
<drawing r:id="rId1"/>
So much for microsoft.