diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /filter/source/xslt/export/spreadsheetml | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'filter/source/xslt/export/spreadsheetml')
-rw-r--r-- | filter/source/xslt/export/spreadsheetml/formular.xsl | 631 | ||||
-rw-r--r-- | filter/source/xslt/export/spreadsheetml/ooo2spreadsheetml.xsl | 408 | ||||
-rw-r--r-- | filter/source/xslt/export/spreadsheetml/style_mapping.xsl | 381 | ||||
-rw-r--r-- | filter/source/xslt/export/spreadsheetml/styles.xsl | 686 | ||||
-rw-r--r-- | filter/source/xslt/export/spreadsheetml/table.xsl | 928 |
5 files changed, 3034 insertions, 0 deletions
diff --git a/filter/source/xslt/export/spreadsheetml/formular.xsl b/filter/source/xslt/export/spreadsheetml/formular.xsl new file mode 100644 index 000000000..f284e342d --- /dev/null +++ b/filter/source/xslt/export/spreadsheetml/formular.xsl @@ -0,0 +1,631 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" + xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:dom="http://www.w3.org/2001/xml-events" + xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" + xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" + xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" + xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" + xmlns:math="http://www.w3.org/1998/Math/MathML" + xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" + xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" + xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" + xmlns:ooo="http://openoffice.org/2004/office" + xmlns:oooc="http://openoffice.org/2004/calc" + xmlns:ooow="http://openoffice.org/2004/writer" + xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" + xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" + xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible: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:xlink="http://www.w3.org/1999/xlink" + xmlns:xt="http://www.jclark.com/xt" + xmlns:common="http://exslt.org/common" + xmlns:xalan="http://xml.apache.org/xalan" + xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x2="http://schemas.microsoft.com/office/excel/2003/xml" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + exclude-result-prefixes="chart config dc dom dr3d draw fo form math meta number office ooo oooc ooow script style svg table text xlink xt common xalan"> + + + <!-- Mapping @table:formula to @ss:Formula translating the expression syntax --> + <xsl:template match="@table:formula"> + <xsl:param name="calculatedCellPosition" /> + <xsl:param name="calculatedRowPosition" /> + + <xsl:attribute name="ss:Formula"> + <xsl:call-template name="translate-formular-expression"> + <xsl:with-param name="rowPos" select="$calculatedRowPosition" /> + <xsl:with-param name="columnPos" select="$calculatedCellPosition" /> + <xsl:with-param name="expression" select="." /> + </xsl:call-template> + </xsl:attribute> + </xsl:template> + + + <!-- Translate OOOC formula expressions of table cells to spreadsheetml expression + + For example: + "oooc:=ROUNDDOWN(123.321;2)" + to "=ROUNDDOWN(123.321,2)" + "oooc:=([.B2]-[.C2])" + to "=(RC[-2]-RC[-1])" + "oooc:=DCOUNTA([.E14:.F21];[.F14];[.H14:.I15])" + to "=DCOUNTA(R[-17]C[3]:R[-10]C[4],R[-17]C[4],R[-17]C[6]:R[-16]C[7])" --> + <xsl:template name="translate-formular-expression"> + <!-- return position or range for formula or other --> + <xsl:param name="rowPos" /> <!-- the position in row (vertical) of cell --> + <xsl:param name="columnPos" /> <!-- the position in column (horizontal of cell) --> + <xsl:param name="expression" /> <!-- the expression string to be converted --> + + <xsl:choose> + <xsl:when test="$expression != ''"> + <xsl:choose> + <!-- OASIS Open Document XML formular expressions --> + <xsl:when test="starts-with($expression,'oooc:')"> + <!-- giving out the '=', which will be removed with 'oooc:=' to enable recursive string parsing --> + <xsl:text>=</xsl:text> + <xsl:call-template name="function-parameter-mapping"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <!-- 1) remove 'oooc:=' prefix and exchange ';' with ',' --> + <xsl:with-param name="expression" select="translate(substring($expression,7),';',',')"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$expression" /> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$expression" /> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- As the function API of our Office and MS Office show differences in the argumentlists, + - sometimes the last parameter have to be neglected + - sometimes a default have to be added + these exchanges have to be done as well --> + <xsl:template name="function-parameter-mapping"> + <xsl:param name="rowPos" /> <!-- the position in row (vertical of cell) --> + <xsl:param name="columnPos" /> <!-- the position in column (horizontal of cell) --> + <xsl:param name="expression" /> <!-- expression to be exchanged --> + + <!-- Choose if the expression contains one of the function, which might need changes --> + <xsl:choose> + <!-- if not contain one of the functions, which need parameter mapping --> + <xsl:when test="not(contains($expression, 'ADDRESS(') or + contains($expression, 'CEILING(') or + contains($expression, 'FLOOR(') or + contains($expression, 'IF(') or + contains($expression, 'ROUND('))"> + <!-- simply translate possibly existing column & row references --> + <xsl:call-template name="translate-oooc-expression"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="$expression"/> + </xsl:call-template> + </xsl:when> + <!-- functions to be mapped --> + <xsl:otherwise> + <xsl:variable name="functionPrefix" select="substring-before($expression, '(')" /> + <xsl:variable name="expressionSuffix" select="substring-after($expression, '(')" /> + + <!-- translate in case the expression contains row/cell references aside of the function name --> + <xsl:call-template name="translate-oooc-expression"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="$functionPrefix"/> + </xsl:call-template> + <!-- Prefix do not include the bracket --> + <xsl:text>(</xsl:text> + <xsl:choose> + <xsl:when test="not(contains($functionPrefix, 'ADDRESS') or + contains($functionPrefix, 'CEILING') or + contains($functionPrefix, 'FLOOR') or + (contains($functionPrefix, 'IF') and not( + contains($functionPrefix, 'COUNTIF') or + contains($functionPrefix, 'SUMIF'))) or + contains($functionPrefix, 'ROUND'))"> + <xsl:call-template name="function-parameter-mapping"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="$expressionSuffix"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="contains($functionPrefix, 'ADDRESS')"> + <xsl:call-template name="find-parameters"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + <xsl:with-param name="parameterRemoval" select="4" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="contains($functionPrefix, 'CEILING') or + contains($functionPrefix, 'FLOOR')"> + <xsl:call-template name="find-parameters"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + <xsl:with-param name="parameterRemoval" select="3" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="contains($functionPrefix, 'IF')"> + <xsl:if test="not(contains($functionPrefix, 'COUNTIF') or + contains($functionPrefix, 'SUMIF'))"> + <xsl:call-template name="find-parameters"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + <xsl:with-param name="parameterAddition" select="'true'" /> + <xsl:with-param name="additonAfterLastParameter" select="2" /> + </xsl:call-template> + </xsl:if> + </xsl:when> + <xsl:when test="contains($functionPrefix, 'ROUND')"> + <xsl:call-template name="find-parameters"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + <xsl:with-param name="parameterAddition" select="'null'" /> + <xsl:with-param name="additonAfterLastParameter" select="1" /> + </xsl:call-template> + </xsl:when> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Each parameter of the argumentlist have to be determined. + Due to the low level string functionality in XSLT it becomes a clumsy task --> + <xsl:template name="find-parameters"> + <!-- used for mapping of row/column reference --> + <xsl:param name="rowPos" /> <!-- the position in row (vertical of cell) --> + <xsl:param name="columnPos" /> <!-- the position in column (horizontal of cell) --> + <!-- used for mapping of parameter --> + <xsl:param name="parameterRemoval" /> + <xsl:param name="parameterAddition" /> + <xsl:param name="additonAfterLastParameter" /> + <!-- used as helper to find a parameter --> + <xsl:param name="expressionSuffix" /> + <xsl:param name="parameterNumber" select="1" /> + + <xsl:variable name="parameter"> + <xsl:call-template name="getParameter"> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + </xsl:call-template> + </xsl:variable> + + <xsl:choose> + <!-- if it is not the last parameter --> + <xsl:when test="starts-with(substring-after($expressionSuffix, $parameter), ',')"> + <!-- searches the argument for functions to be mapped --> + <xsl:if test="not($parameterRemoval = $parameterNumber)"> + <xsl:call-template name="function-parameter-mapping"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression"> + <xsl:choose> + <!-- in case a character will be removed the preceding won't make a comma --> + <xsl:when test="$parameterRemoval = ($parameterNumber + 1)"> + <xsl:value-of select="$parameter" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="concat($parameter, ',')" /> + </xsl:otherwise> + </xsl:choose> + </xsl:with-param> + </xsl:call-template> + </xsl:if> + <!-- searches for the next parameter --> + <xsl:call-template name="find-parameters"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expressionSuffix" select="substring-after(substring-after($expressionSuffix, $parameter),',')"/> + <xsl:with-param name="parameterAddition" select="$parameterAddition" /> + <xsl:with-param name="parameterRemoval" select="$parameterRemoval" /> + <xsl:with-param name="additonAfterLastParameter" select="$additonAfterLastParameter" /> + <xsl:with-param name="parameterNumber" select="$parameterNumber + 1" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <!-- the last parameter --> + <xsl:choose> + <xsl:when test="$parameterRemoval = $parameterNumber"> + <!-- searches the rest of the expression for functions to be mapped --> + <xsl:call-template name="function-parameter-mapping"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="substring-after($expressionSuffix, $parameter)"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$parameterAddition and ($parameterNumber = $additonAfterLastParameter)"> + <!-- searches the rest of the expression for functions to be mapped --> + <xsl:call-template name="function-parameter-mapping"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="$parameter" /> + </xsl:call-template> + <!-- searches last parameter and additional parameters for functions to be mapped --> + <xsl:call-template name="function-parameter-mapping"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <!-- for the final parameter the latter substring is the ')' --> + <xsl:with-param name="expression" select="concat(',', $parameterAddition, substring-after($expressionSuffix, $parameter))"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <!-- searches the argument for functions to be mapped --> + <xsl:call-template name="function-parameter-mapping"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="$parameter" /> + </xsl:call-template> + <!-- searches the rest of the expression for functions to be mapped --> + <xsl:call-template name="function-parameter-mapping"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="substring-after($expressionSuffix, $parameter)"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="getParameter"> + <xsl:param name="closingBracketCount" select="0" /> + <xsl:param name="openingBracketCount" select="0" /> + <xsl:param name="expressionSuffix" /> + <xsl:param name="parameterCandidate"> + <xsl:choose> + <!-- if there are multiple parameter --> + <xsl:when test="contains(substring-before($expressionSuffix, ')'), ',')"> + <xsl:value-of select="substring-before($expressionSuffix, ',')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="substring-before($expressionSuffix, ')')"/> + </xsl:otherwise> + </xsl:choose> + </xsl:param> + <xsl:param name="earlierCandidate" select="$parameterCandidate" /> + + <xsl:choose> + <xsl:when test="contains($parameterCandidate, '(') or contains($parameterCandidate, ')')"> + <xsl:choose> + <!-- contains only closing bracket(s) --> + <xsl:when test="contains($parameterCandidate, '(') and not(contains($parameterCandidate, ')'))"> + <xsl:call-template name="getParameter"> + <xsl:with-param name="openingBracketCount" select="$openingBracketCount + 1" /> + <xsl:with-param name="closingBracketCount" select="$closingBracketCount" /> + <xsl:with-param name="parameterCandidate" select="substring-after($parameterCandidate, '(')" /> + <xsl:with-param name="earlierCandidate" select="$earlierCandidate" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + </xsl:call-template> + </xsl:when> + <!-- contains only opening bracket(s) --> + <xsl:when test="not(contains($parameterCandidate, '(')) and contains($parameterCandidate, ')')"> + <xsl:call-template name="getParameter"> + <xsl:with-param name="openingBracketCount" select="$openingBracketCount" /> + <xsl:with-param name="closingBracketCount" select="$closingBracketCount + 1" /> + <xsl:with-param name="parameterCandidate" select="substring-after($parameterCandidate, ')')" /> + <xsl:with-param name="earlierCandidate" select="$earlierCandidate" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="string-length(substring-before($parameterCandidate, '(')) < + string-length(substring-before($parameterCandidate, ')'))"> + <xsl:call-template name="getParameter"> + <xsl:with-param name="openingBracketCount" select="$openingBracketCount + 1" /> + <xsl:with-param name="closingBracketCount" select="$closingBracketCount" /> + <xsl:with-param name="parameterCandidate" select="substring-after($parameterCandidate, '(')" /> + <xsl:with-param name="earlierCandidate" select="$earlierCandidate" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="getParameter"> + <xsl:with-param name="openingBracketCount" select="$openingBracketCount" /> + <xsl:with-param name="closingBracketCount" select="$closingBracketCount + 1" /> + <xsl:with-param name="parameterCandidate" select="substring-after($parameterCandidate, ')')" /> + <xsl:with-param name="earlierCandidate" select="$earlierCandidate" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="$openingBracketCount = $closingBracketCount"> + <xsl:value-of select="$earlierCandidate" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$earlierCandidate" /> + <xsl:variable name="parameterCandidate2"> + <xsl:variable name="formularAfterCandidate" select="substring-after($expressionSuffix, $earlierCandidate)" /> + <xsl:variable name="parameterTillBracket" select="concat(substring-before($formularAfterCandidate,')'),')')" /> + <xsl:variable name="parameterTillComma" select="substring-before(substring-after($expressionSuffix, $parameterTillBracket),',')" /> + <xsl:choose> + <xsl:when test="string-length($parameterTillComma) > 0 and + not(contains($parameterTillComma, '('))"> + <xsl:choose> + <xsl:when test="starts-with($formularAfterCandidate, ',')"> + <xsl:value-of select="concat(',',substring-before(substring-after($formularAfterCandidate,','),','))"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="substring-before($formularAfterCandidate,',')"/> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$parameterTillBracket"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:call-template name="getParameter"> + <xsl:with-param name="closingBracketCount" select="$closingBracketCount" /> + <xsl:with-param name="openingBracketCount" select="$openingBracketCount" /> + <xsl:with-param name="parameterCandidate" select="$parameterCandidate2" /> + <xsl:with-param name="earlierCandidate" select="$parameterCandidate2" /> + <xsl:with-param name="expressionSuffix" select="$expressionSuffix" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Mapping table-cell definitions by exchangomg all table cell definitions: + a) a pair of cells e.g. "[.E14:.F21]" to "R[-17]C[3]:R[-10]C[4]" + b) a single cell e.g. "[.F14]" to "R[-17]"--> + <xsl:template name="translate-oooc-expression"> + <xsl:param name="rowPos" /> <!-- the position in row (vertical of cell) --> + <xsl:param name="columnPos" /> <!-- the position in column (horizontal of cell) --> + <xsl:param name="expression" /> <!-- expression to be exchanged --> + + <xsl:choose> + <xsl:when test="contains($expression, '[')"> + + <!-- Giving out the part before '[.' --> + <xsl:value-of select="substring-before($expression, '[')" /> + + <!-- Mapping cell definitions + 1) a pair of cells e.g. "[.E14:.F21]" to "R[-17]C[3]:R[-10]C[4]" + 2) a single cell e.g. "[.F14]" to "R[-17]"--> + <xsl:variable name="remainingExpression" select="substring-after($expression, '[')"/> + <xsl:choose> + <xsl:when test="contains(substring-before($remainingExpression, ']'), ':')"> + <xsl:call-template name="translate-cell-expression"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="substring-before($remainingExpression, ':')" /> + </xsl:call-template> + <xsl:value-of select="':'" /> + <xsl:call-template name="translate-cell-expression"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="substring-after(substring-before($remainingExpression, ']'), ':')" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="translate-cell-expression"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="substring-before($remainingExpression, ']')" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + <xsl:call-template name="translate-oooc-expression"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="substring-after($remainingExpression,']')"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <!-- Giving out the remaining part --> + <xsl:value-of select="$expression" /> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- A cell expression has usually starts with a '.' otherwise it references to a sheet --> + <xsl:template name="translate-cell-expression"> + <xsl:param name="rowPos" /> <!-- the vertical position of the current cell --> + <xsl:param name="columnPos" /> <!-- the horizontal position of the current cell --> + <xsl:param name="targetRowPos" select="0"/> <!-- the vertical position of the target cell --> + <xsl:param name="targetColumnPos" select="0"/> <!-- the horizontal position of the target cell --> + <xsl:param name="charPos" select="0"/> <!-- current column position (needed for multiplying) --> + <xsl:param name="digitPos" select="0"/> <!-- current row position (needed for multiplying) --> + <xsl:param name="expression" /> <!-- expression to be parsed by character --> + <xsl:param name="isRow" select="true()"/> <!-- the string (e.g. $D39 is parsed character per character from the back, + first the row, later the column is parsed --> + + <xsl:choose> + <xsl:when test="starts-with($expression, '.')"> + <xsl:variable name="expLength" select="string-length($expression)" /> + <xsl:choose> + <!-- parsing from the end, till only the '.' remains --> + <xsl:when test="$expLength != 1"> + <xsl:variable name="token" select="substring($expression, $expLength)" /> + <xsl:choose> + <xsl:when test="$token='0' or $token='1' or $token='2' or $token='3' or $token='4' or $token='5' or $token='6' or $token='7' or $token='8' or $token='9'"> + <xsl:variable name="multiplier"> + <xsl:call-template name="calculate-square-numbers"> + <xsl:with-param name="base" select="10" /> + <xsl:with-param name="exponent" select="$digitPos"/> + </xsl:call-template> + </xsl:variable> + <xsl:call-template name="translate-cell-expression"> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="targetColumnPos" select="$targetColumnPos" /> + <xsl:with-param name="targetRowPos" select="$targetRowPos + $multiplier * $token" /> + <xsl:with-param name="digitPos" select="$digitPos + 1" /> + <xsl:with-param name="charPos" select="$charPos" /> + <!-- removing the last character--> + <xsl:with-param name="expression" select="substring($expression, 1, $expLength - 1)" /> + <xsl:with-param name="isRow" select="true()" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="$token = '$'"> + <xsl:choose> + <!-- if this is the first '$' after '.' (column--> + <xsl:when test="$expLength = 2"> + <xsl:text>C</xsl:text><xsl:value-of select="$targetColumnPos"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>R</xsl:text><xsl:value-of select="$targetRowPos"/> + <xsl:call-template name="translate-cell-expression"> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="targetColumnPos" select="$targetColumnPos" /> + <xsl:with-param name="targetRowPos" select="$targetRowPos" /> + <xsl:with-param name="charPos" select="$charPos" /> + <!-- removing the last character--> + <xsl:with-param name="expression" select="substring($expression, 1, $expLength - 1)" /> + <xsl:with-param name="isRow" select="false()" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <!-- in case of a letter --> + <xsl:otherwise> + <xsl:if test="$isRow"> + <xsl:text>R</xsl:text> + <xsl:if test="$targetRowPos != $rowPos"> + <xsl:text>[</xsl:text><xsl:value-of select="$targetRowPos - $rowPos"/><xsl:text>]</xsl:text> + </xsl:if> + </xsl:if> + <xsl:variable name="multiplier"> + <xsl:call-template name="calculate-square-numbers"> + <xsl:with-param name="base" select="26" /> + <xsl:with-param name="exponent" select="$charPos"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="tokenNumber"> + <xsl:call-template name="character-to-number"> + <xsl:with-param name="character" select="$token" /> + </xsl:call-template> + </xsl:variable> + + <xsl:call-template name="translate-cell-expression"> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="targetColumnPos" select="$targetColumnPos + $multiplier * $tokenNumber" /> + <xsl:with-param name="targetRowPos" select="$targetRowPos" /> + <xsl:with-param name="digitPos" select="$digitPos" /> + <xsl:with-param name="charPos" select="$charPos + 1" /> + <!-- removing the last character--> + <xsl:with-param name="expression" select="substring($expression, 1, $expLength - 1)" /> + <xsl:with-param name="isRow" select="false()" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:text>C</xsl:text> + <xsl:if test="$targetColumnPos != $columnPos"> + <xsl:text>[</xsl:text><xsl:value-of select="$targetColumnPos - $columnPos"/><xsl:text>]</xsl:text> + </xsl:if> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="sheetName" select="substring-before($expression, '.')" /> + <xsl:value-of select="$sheetName"/><xsl:text>!</xsl:text> + <xsl:call-template name="translate-cell-expression"> + <xsl:with-param name="rowPos" select="$rowPos" /> + <xsl:with-param name="columnPos" select="$columnPos" /> + <xsl:with-param name="expression" select="substring-after($expression, $sheetName)" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <xsl:template name="calculate-square-numbers"> + <xsl:param name="base" /> + <xsl:param name="exponent" /> + <xsl:param name="return" select="1" /> + + <xsl:choose> + <xsl:when test="$exponent > '1'"> + <xsl:call-template name="calculate-square-numbers"> + <xsl:with-param name="base" select="$base" /> + <xsl:with-param name="exponent" select="$exponent - 1"/> + <xsl:with-param name="return" select="$return * $base" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="$exponent = '1'"> + <xsl:value-of select="$return * $base"/> + </xsl:when> + <!-- if exponent is equal '0' --> + <xsl:otherwise> + <xsl:value-of select="1"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <xsl:template name="character-to-number"> + <xsl:param name="character" /> + <xsl:choose> + <xsl:when test="$character = 'A'">1</xsl:when> + <xsl:when test="$character = 'B'">2</xsl:when> + <xsl:when test="$character = 'C'">3</xsl:when> + <xsl:when test="$character = 'D'">4</xsl:when> + <xsl:when test="$character = 'E'">5</xsl:when> + <xsl:when test="$character = 'F'">6</xsl:when> + <xsl:when test="$character = 'G'">7</xsl:when> + <xsl:when test="$character = 'H'">8</xsl:when> + <xsl:when test="$character = 'I'">9</xsl:when> + <xsl:when test="$character = 'J'">10</xsl:when> + <xsl:when test="$character = 'K'">11</xsl:when> + <xsl:when test="$character = 'L'">12</xsl:when> + <xsl:when test="$character = 'M'">13</xsl:when> + <xsl:when test="$character = 'N'">14</xsl:when> + <xsl:when test="$character = 'O'">15</xsl:when> + <xsl:when test="$character = 'P'">16</xsl:when> + <xsl:when test="$character = 'Q'">17</xsl:when> + <xsl:when test="$character = 'R'">18</xsl:when> + <xsl:when test="$character = 'S'">19</xsl:when> + <xsl:when test="$character = 'T'">20</xsl:when> + <xsl:when test="$character = 'U'">21</xsl:when> + <xsl:when test="$character = 'V'">22</xsl:when> + <xsl:when test="$character = 'W'">23</xsl:when> + <xsl:when test="$character = 'X'">24</xsl:when> + <xsl:when test="$character = 'Y'">25</xsl:when> + <xsl:when test="$character = 'Z'">26</xsl:when> + <xsl:otherwise/> + </xsl:choose> + </xsl:template> + +</xsl:stylesheet> diff --git a/filter/source/xslt/export/spreadsheetml/ooo2spreadsheetml.xsl b/filter/source/xslt/export/spreadsheetml/ooo2spreadsheetml.xsl new file mode 100644 index 000000000..321369efc --- /dev/null +++ b/filter/source/xslt/export/spreadsheetml/ooo2spreadsheetml.xsl @@ -0,0 +1,408 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" + xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:dom="http://www.w3.org/2001/xml-events" + xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" + xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" + xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" + xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" + xmlns:math="http://www.w3.org/1998/Math/MathML" + xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" + xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" + xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" + xmlns:ooo="http://openoffice.org/2004/office" + xmlns:oooc="http://openoffice.org/2004/calc" + xmlns:ooow="http://openoffice.org/2004/writer" + xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" + xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" + xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible: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:xlink="http://www.w3.org/1999/xlink" + xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x2="http://schemas.microsoft.com/office/excel/2003/xml" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + exclude-result-prefixes="chart config dc dom dr3d draw fo form math meta number office ooo oooc ooow script style svg table text xlink"> + + + <!--+++++ INCLUDED XSL MODULES +++++--> + + <!-- helper collection, to convert measures (e.g. inch to pixel using DPI (dots per inch) parameter)--> + <xsl:import href="../../common/measure_conversion.xsl" /> + + <!-- excel table handling --> + <xsl:include href="table.xsl" /> + + <!-- mapping rules of office style properties to Excel style properties --> + <xsl:include href="style_mapping.xsl" /> + + <!-- creating the Excel styles element --> + <xsl:include href="styles.xsl" /> + + <!-- mapping formular Expressions --> + <xsl:include href="formular.xsl" /> + + <xsl:output method = "xml" + indent = "no" + encoding = "UTF-8" + omit-xml-declaration = "no" /> + + <xsl:strip-space elements="ss:Data html:Data" /> + + + <!-- common table handling --> + <xsl:variable name="namespace" select="'urn:schemas-microsoft-com:office:spreadsheet'" /> + + <!--+++++ PARAMETER SECTION +++++--> + + <!-- OPTIONAL: (MANDATORY: for all input document with relative external links): parameter is a (relative) URL to the target directory. + Relative links from the office document (e.g. to external graphics) will get this parameter as a prefix --> + <xsl:param name="targetBaseURL" select="'./'" /> + + <!-- OPTIONAL: (MANDATORY: for input document with relative internal links) + To access contents of an office file (content like the meta.xml, styles.xml file or graphics) a URL could be chosen. + This could be even a JAR URL. The sourceBase of the content URL "jar:file:/C:/temp/Test.sxw!/content.xml" would be + "jar:file:/C:/temp/Test.sxw!/" for example. + When working with OpenOffice API a Package-URL encoded over HTTP can be used to access the jared contents of the jared document. --> + <xsl:param name="sourceBaseURL" select="'./'" /> + + <!-- OPTIONAL: (MANDATORY: for session management by URL rewriting) + Useful for WebApplications: if a HTTP session is not cookie based, URL rewriting is being used (the session is appended to the URL). + This URL session is used for example when links to graphics are created by XSLT. Otherwise the user has to log again in for every graphic he likes to see. --> + <xsl:param name="optionalURLSuffix" /> + + <!-- OPTIONAL: URL to office meta file (flat xml use the URL to the input file) --> + <xsl:param name="metaFileURL" /> + + <!-- OPTIONAL: URL to office meta file (flat xml use the URL to the input file) --> + <xsl:param name="stylesFileURL" /> + + <!-- OPTIONAL: in case of using a different processor than a JAVA XSLT, you can unable the Java functionality + (e.g. encoding chapter names for the content-table as href and anchors ) --> + <xsl:param name="java" select="true()" /> + <xsl:param name="javaEnabled" select="boolean($java)" /> + + <!-- OPTIONAL: for activating the debug mode set the variable here to 'true()' or give any value from outside --> + <xsl:param name="debug" select="false()" /> + <xsl:param name="debugEnabled" select="boolean($debug)" /> + + <!-- matching configuration entries --> + <xsl:key name="config" use="@config:name" + match="/*/office:settings/config:config-item-set/config:config-item-map-indexed/config:config-item-map-entry/config:config-item | + /*/office:settings/config:config-item-set/config:config-item-map-indexed/config:config-item-map-entry/config:config-item-map-named/config:config-item-map-entry/config:config-item" /> + + <xsl:key name="colors" match="/*/office:styles//@*[name() = 'fo:background-color' or name() = 'fo:color'] | + /*/office:automatic-styles//@*[name() = 'fo:background-color' or name() = 'fo:color']" use="/" /> + <xsl:key name="colorRGB" match="@fo:background-color | @fo:color" use="." /> + <!-- *************************** --> + <!-- *** Built up Excel file *** --> + <!-- *************************** --> + <xsl:template match="/"> + <xsl:processing-instruction name="mso-application">progid="Excel.Sheet"</xsl:processing-instruction> + <!-- Note: for debugging purpose include schema location + <Workbook xsi:schemaLocation="urn:schemas-microsoft-com:office:spreadsheet <YOUR_SCHEMA_URL>/excelss.xsd"> --> + <Workbook> + <!-- adding some default settings --> + <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office"> + <Colors> + <xsl:for-each select="key('colors', /) + [generate-id(.) = + generate-id(key('colorRGB', .)[1]) and starts-with(., '#')] "> + <xsl:sort select="." /> + <Color> + <Index><xsl:value-of select="position() + 2" /></Index> + <RGB><xsl:value-of select="." /></RGB> + </Color> + </xsl:for-each> + <xsl:for-each select="key('config', 'TabColor')[not(.=preceding::config:config-item)]"> + <xsl:sort select="." /> + <Color> + <Index><xsl:value-of select="56 - position()" /></Index> + <RGB> + <xsl:call-template name="colordecimal2rgb"> + <xsl:with-param name="colordecimal" select="."/> + </xsl:call-template> + </RGB> + </Color> + </xsl:for-each> + </Colors> + </OfficeDocumentSettings> + <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel"> + <xsl:if test="key('config', 'HasSheetTabs') = 'false'"> + <xsl:element name="HideWorkbookTabs" /> + </xsl:if> + <WindowHeight>9000</WindowHeight> + <WindowWidth>13860</WindowWidth> + <WindowTopX>240</WindowTopX> + <WindowTopY>75</WindowTopY> + <ProtectStructure>False</ProtectStructure> + <ProtectWindows>False</ProtectWindows> + </ExcelWorkbook> + <!-- Note: the following handling will exchange the default, later + <x:ExcelWorkbook> + <xsl:apply-templates select="table:calculation-settings" /> + </x:ExcelWorkbook> + --> + <xsl:element name="Styles"> + <!-- our application default will not be used for export to Excel + <xsl:apply-templates select="/*/office:styles/style:default-style" mode="styles" />--> + <xsl:apply-templates select="/*/office:styles/style:style" mode="styles" /> + <xsl:apply-templates select="/*/office:automatic-styles/style:style" mode="styles" > + <xsl:with-param name="isAutomatic" select="true()" /> + </xsl:apply-templates> + </xsl:element> + <xsl:apply-templates select="/*/office:body" /> + </Workbook> + </xsl:template> + + <xsl:template name="colordecimal2rgb"> + <xsl:param name="colordecimal"/> + <xsl:choose> + <xsl:when test="$colordecimal <= 16777215 and $colordecimal >= 65536"> + <xsl:variable name="redValue" select="floor(($colordecimal) div 65536)"/> + <xsl:variable name="greenValue" select="floor(($colordecimal - ($redValue*65536)) div 256)"/> + <xsl:variable name="blueValue" select="$colordecimal - ($redValue*65536) - ($greenValue*256)"/> + <xsl:call-template name="dec_rgb2Hex"> + <xsl:with-param name="decRedValue" select="$redValue"/> + <xsl:with-param name="decGreenValue" select="$greenValue"/> + <xsl:with-param name="decBlueValue" select="$blueValue"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$colordecimal <= 65535 and $colordecimal >= 256"> + <xsl:variable name="redValue" select="0"/> + <xsl:variable name="greenValue" select="$colordecimal div 256"/> + <xsl:variable name="blueValue" select="$colordecimal - ($greenValue*256)"/> + <xsl:call-template name="dec_rgb2Hex"> + <xsl:with-param name="decRedValue" select="$redValue"/> + <xsl:with-param name="decGreenValue" select="$greenValue"/> + <xsl:with-param name="decBlueValue" select="$blueValue"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$colordecimal <= 255 and $colordecimal >= 0"> + <xsl:variable name="redValue" select="0"/> + <xsl:variable name="greenValue" select="0"/> + <xsl:variable name="blueValue" select="$colordecimal"/> + <xsl:call-template name="dec_rgb2Hex"> + <xsl:with-param name="decRedValue" select="$redValue"/> + <xsl:with-param name="decGreenValue" select="$greenValue"/> + <xsl:with-param name="decBlueValue" select="$blueValue"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise/> + </xsl:choose> + </xsl:template> + <xsl:template name="dec_rgb2Hex"> + <xsl:param name="decRedValue"/> + <xsl:param name="decGreenValue"/> + <xsl:param name="decBlueValue"/> + <xsl:variable name="hexRedValue"> + <xsl:variable name="tmpHexRedValue"> + <xsl:call-template name="decimal2hex"> + <xsl:with-param name="dec-number" select="$decRedValue"/> + <xsl:with-param name="last-value" select="'H'"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="string-length($tmpHexRedValue) = 1"> + <xsl:value-of select="concat('0',$tmpHexRedValue)"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$tmpHexRedValue"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="hexGreenValue"> + <xsl:variable name="tmpHexGreenValue"> + <xsl:call-template name="decimal2hex"> + <xsl:with-param name="dec-number" select="$decGreenValue"/> + <xsl:with-param name="last-value" select="'H'"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="string-length($tmpHexGreenValue) = 1"> + <xsl:value-of select="concat('0',$tmpHexGreenValue)"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$tmpHexGreenValue"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:variable name="hexBlueValue"> + <xsl:variable name="tmpHexBlueValue"> + <xsl:call-template name="decimal2hex"> + <xsl:with-param name="dec-number" select="$decBlueValue"/> + <xsl:with-param name="last-value" select="'H'"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="string-length($tmpHexBlueValue) = 1"> + <xsl:value-of select="concat('0',$tmpHexBlueValue)"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$tmpHexBlueValue"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:value-of select="concat('#',$hexRedValue,$hexGreenValue,$hexBlueValue)"/> + </xsl:template> + <xsl:template name="decimal2hex"> + <!-- transforms a decimal number to a hex number,only for two-bit hex(less than 256 in decimal) currently --> + <xsl:param name="dec-number"/> + <xsl:param name="last-value"/> + <xsl:variable name="current-value"> + <xsl:call-template name="decNumber2hex"> + <xsl:with-param name="dec-value"> + <xsl:if test="$dec-number > 15"> + <xsl:value-of select="floor($dec-number div 16)"/> + </xsl:if> + <xsl:if test="$dec-number < 16"> + <xsl:value-of select="$dec-number"/> + </xsl:if> + </xsl:with-param> + </xsl:call-template> + </xsl:variable> + <xsl:if test="$dec-number > 15"> + <xsl:call-template name="decimal2hex"> + <xsl:with-param name="dec-number" select="$dec-number mod 16"/> + <xsl:with-param name="last-value" select="concat($last-value,$current-value)"/> + </xsl:call-template> + </xsl:if> + <xsl:if test="$dec-number < 16"> + <xsl:value-of select="substring-after(concat($last-value,$current-value),'H')"/> + </xsl:if> + </xsl:template> + + <xsl:template name="decNumber2hex"> + <!-- return a hex number for a decimal character --> + <xsl:param name="dec-value"/> + <xsl:choose> + <xsl:when test="$dec-value = 10"> + <xsl:value-of select="'A'"/> + </xsl:when> + <xsl:when test="$dec-value = 11"> + <xsl:value-of select="'B'"/> + </xsl:when> + <xsl:when test="$dec-value = 12"> + <xsl:value-of select="'C'"/> + </xsl:when> + <xsl:when test="$dec-value = 13"> + <xsl:value-of select="'D'"/> + </xsl:when> + <xsl:when test="$dec-value = 14"> + <xsl:value-of select="'E'"/> + </xsl:when> + <xsl:when test="$dec-value = 15"> + <xsl:value-of select="'F'"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$dec-value"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + <xsl:template name="GetTabColorIndex"> + <xsl:param name="SheetColor"/> + <xsl:for-each select="key('config', 'TabColor')[not(.=preceding::config:config-item)]"> + <xsl:sort select="." /> + <xsl:variable name="tmpColor" select="."/> + <xsl:if test=". = $SheetColor" > + <xsl:value-of select="56 - position()"/> + </xsl:if> + </xsl:for-each> + </xsl:template> + <xsl:template match="office:body"> + <!-- office:body table:table children are spreadsheets --> + <xsl:apply-templates /> + </xsl:template> + + <xsl:template match="office:spreadsheet"> + <xsl:apply-templates /> + </xsl:template> + + <!-- office:body table:table children are spreadsheets --> + <xsl:template match="office:spreadsheet/table:table"> + <xsl:element name="ss:Worksheet"> + <xsl:variable name="TableName"> + <xsl:value-of select="@table:name" /> + </xsl:variable> + <xsl:attribute name="ss:Name"> + <xsl:value-of select="$TableName" /> + </xsl:attribute> + <xsl:call-template name="table:table" /> + <xsl:element name="x:WorksheetOptions"> + <xsl:if test="key('config', 'ShowGrid') = 'false'"> + <xsl:element name="x:DoNotDisplayGridlines" /> + </xsl:if> + <xsl:if test="key('config', 'HasColumnRowHeaders') = 'false'"> + <xsl:element name="x:DoNotDisplayHeadings" /> + </xsl:if> + <xsl:if test="key('config', 'IsOutlineSymbolsSet') = 'false'"> + <xsl:element name="x:DoNotDisplayOutline" /> + </xsl:if> + <xsl:if test="key('config', 'ShowZeroValues') = 'false'"> + <xsl:element name="x:DoNotDisplayZeros" /> + </xsl:if> + <xsl:if test="/*/office:settings/config:config-item-set/config:config-item-map-indexed/config:config-item-map-entry/config:config-item-map-named/config:config-item-map-entry[@config:name=$TableName]/config:config-item[@config:name='TabColor']"> + <xsl:element name="x:TabColorIndex"> + <xsl:variable name="TabColorIndex"> + <xsl:call-template name="GetTabColorIndex"> + <xsl:with-param name="SheetColor" select="/*/office:settings/config:config-item-set/config:config-item-map-indexed/config:config-item-map-entry/config:config-item-map-named/config:config-item-map-entry[@config:name=$TableName]/config:config-item[@config:name='TabColor']"/> + </xsl:call-template> + </xsl:variable> + <xsl:value-of select="$TabColorIndex"/> + </xsl:element> + </xsl:if> + </xsl:element> + </xsl:element> + </xsl:template> + + <xsl:template match="table:decls" mode="ExcelWorkbook"> + <xsl:apply-templates mode="ExcelWorkbook" /> + </xsl:template> + + <xsl:template match="table:calculation-settings" mode="ExcelWorkbook"> + <xsl:if test="table:precision-as-shown"> + <x:PrecisionAsDisplayed/> + </xsl:if> + <xsl:if test="table:null-date/@office:date-value='1904-01-01'"> + <x:Date1904/> + </xsl:if> + <xsl:apply-templates select="table:iteration" /> + </xsl:template> + + <xsl:template match="table:iteration" mode="ExcelWorkbook"> + <xsl:element name="x:ExcelWorkbook"> + <xsl:if test="@table:status = 'enable'"> + <x:Iteration/> + </xsl:if> + <xsl:if test="@table:steps"> + <xsl:element name="x:MaxIterations"> + <xsl:value-of select="@table:steps" /> + </xsl:element> + </xsl:if> + <xsl:if test="@table:maximum-difference"> + <xsl:element name="x:MaxChange"> + <xsl:value-of select="@table:maximum-difference" /> + </xsl:element> + </xsl:if> + </xsl:element> + </xsl:template> + +</xsl:stylesheet> diff --git a/filter/source/xslt/export/spreadsheetml/style_mapping.xsl b/filter/source/xslt/export/spreadsheetml/style_mapping.xsl new file mode 100644 index 000000000..b338afcc2 --- /dev/null +++ b/filter/source/xslt/export/spreadsheetml/style_mapping.xsl @@ -0,0 +1,381 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" + xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:dom="http://www.w3.org/2001/xml-events" + xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" + xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" + xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" + xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" + xmlns:math="http://www.w3.org/1998/Math/MathML" + xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" + xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" + xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" + xmlns:ooo="http://openoffice.org/2004/office" + xmlns:oooc="http://openoffice.org/2004/calc" + xmlns:ooow="http://openoffice.org/2004/writer" + xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" + xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" + xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible: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:xlink="http://www.w3.org/1999/xlink" + xmlns:xt="http://www.jclark.com/xt" + xmlns:common="http://exslt.org/common" + xmlns:xalan="http://xml.apache.org/xalan" + xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x2="http://schemas.microsoft.com/office/excel/2003/xml" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + exclude-result-prefixes="chart config dc dom dr3d draw fo form math meta number office ooo oooc ooow script style svg table text xlink xt common xalan"> + + <xsl:variable name="namespace-html" select="'http://www.w3.org/TR/REC-html40'" /> + + <xsl:template match="@table:style-name | @table:default-cell-style-name"> + <xsl:if test="not(name() = 'Default')"> + <xsl:attribute name="ss:StyleID"> + <xsl:value-of select="." /> + </xsl:attribute> + </xsl:if> + </xsl:template> + + <xsl:key match="table:table-cell" name="getCellByStyle" use="@table:style-name"/> + <xsl:template match="@table:style-name" mode="table-row"> + <!-- only row styles used by cells are exported, + as usual row style properties are already written as row attributes --> + <xsl:if test="key('getCellByStyle', '.')"> + <xsl:attribute name="ss:StyleID"> + <xsl:value-of select="." /> + </xsl:attribute> + </xsl:if> + </xsl:template> + + <xsl:template name="style-and-contents"> + <xsl:param name="cellStyleName" /> + + <!-- WorkAround of Excel2003 issue: + Styles from the CellStyle will not be inherited to HTML content (e.g. Colour style). + --> + <xsl:choose> + <xsl:when test="@text:style-name"> + <xsl:variable name="styles"> + <xsl:copy-of select="key('styles', @text:style-name)/*" /> + <xsl:copy-of select="key('styles', $cellStyleName)/*" /> + </xsl:variable> + <xsl:choose> + <xsl:when test="function-available('xalan:nodeset')"> + <xsl:call-template name="create-nested-format-tags"> + <xsl:with-param name="styles" select="xalan:nodeset($styles)" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('xt:node-set')"> + <xsl:call-template name="create-nested-format-tags"> + <xsl:with-param name="styles" select="xt:node-set($styles)" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('common:node-set')"> + <xsl:call-template name="create-nested-format-tags"> + <xsl:with-param name="styles" select="common:node-set($styles)" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes">The required node-set function was not found!</xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="@table:style-name"> + <xsl:variable name="styles"> + <xsl:copy-of select="key('styles', @text:style-name)/*" /> + <xsl:copy-of select="key('styles', $cellStyleName)/*" /> + </xsl:variable> + + <xsl:choose> + <xsl:when test="function-available('xalan:nodeset')"> + <xsl:call-template name="create-nested-format-tags"> + <xsl:with-param name="styles" select="xalan:nodeset($styles)" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('xt:node-set')"> + <xsl:call-template name="create-nested-format-tags"> + <xsl:with-param name="styles" select="xt:node-set($styles)" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('common:node-set')"> + <xsl:call-template name="create-nested-format-tags"> + <xsl:with-param name="styles" select="common:node-set($styles)" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes">The required node-set function was not found!</xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- *********************************** --> + <!-- *** creating nested format tags *** --> + <!-- *********************************** --> + + <!-- Bold --> + <xsl:template name="create-nested-format-tags"> + <xsl:param name="styles" /> + <xsl:param name="cellStyleName" /> + + <xsl:choose> + <xsl:when test="$styles/*/@fo:font-weight = 'bold' or $styles/*/@fo:font-weight = 'bolder'"> + <xsl:element namespace="{$namespace-html}" name="B"> + <xsl:call-template name="italic"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="italic"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- Italic --> + <xsl:template name="italic"> + <xsl:param name="styles" /> + <xsl:param name="cellStyleName" /> + + <xsl:choose> + <xsl:when test="$styles/*/@fo:font-style = 'italic' or $styles/*/@fo:font-style = 'oblique'"> + <xsl:element namespace="{$namespace-html}" name="I"> + <xsl:call-template name="underline"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="underline"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- Underline --> + <xsl:template name="underline"> + <xsl:param name="styles" /> + <xsl:param name="cellStyleName" /> + + <xsl:choose> + <xsl:when test="$styles/*/@style:text-underline-type and not($styles/*/@style:text-underline-type = 'none')"> + <xsl:element namespace="{$namespace-html}" name="U"> + <xsl:call-template name="strikethrough"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="strikethrough"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + + </xsl:template> + + + <!-- strikethrough --> + <xsl:template name="strikethrough"> + <xsl:param name="styles" /> + <xsl:param name="cellStyleName" /> + + <xsl:choose> + <xsl:when test="$styles/*/@style:text-line-through-style and not($styles/*/@style:text-line-through-style = 'none')"> + <xsl:element namespace="{$namespace-html}" name="S"> + <xsl:call-template name="super-subscript"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="super-subscript"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + + <!-- superscript & subscript --> + <xsl:template name="super-subscript"> + <xsl:param name="styles" /> + <xsl:param name="cellStyleName" /> + + <xsl:choose> + <xsl:when test="$styles/*/@style:text-position"> + <xsl:variable name="textPosition" select="number(substring-before($styles/*/@style:text-position, '% '))" /> + <xsl:choose> + <xsl:when test="$textPosition > 0"> + <xsl:element namespace="{$namespace-html}" name="Sup"> + <xsl:call-template name="align"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:element> + </xsl:when> + <xsl:when test="$textPosition < 0"> + <xsl:element namespace="{$namespace-html}" name="Sub"> + <xsl:call-template name="align"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="align"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="align"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- Alignment - normally called by strikethrough, but no DIV elements in HTML --> + <xsl:template name="align"> + <xsl:param name="styles" /> + <xsl:param name="cellStyleName" /> + + <xsl:choose> + <xsl:when test="$styles/*/@fo:font-align"> + <xsl:element namespace="{$namespace-html}" name="DIV"> + <xsl:attribute name="html:style"> + <xsl:choose> + <xsl:when test="$styles/*/@fo:font-align = 'start'"> + <xsl:text>text-align:left;</xsl:text> + </xsl:when> + <xsl:when test="$styles/*/@fo:font-align = 'end'"> + <xsl:text>text-align:right;</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>text-align:center;</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:call-template name="font"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="font"> + <xsl:with-param name="styles" select="$styles" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- Font (size and color) --> + <xsl:template name="font"> + <xsl:param name="styles" /> + <xsl:param name="cellStyleName" /> + + <xsl:choose> + <xsl:when test="$styles/*/@style:font-name or + $styles/*/@fo:font-size or + $styles/*/@fo:color"> + <xsl:element namespace="{$namespace-html}" name="Font"> + <xsl:if test="$styles/*/@style:font-name"> + <xsl:attribute name="html:Face"> + <xsl:value-of select="$styles/*/@style:font-name" /> + </xsl:attribute> + </xsl:if> + <xsl:if test="$styles/*/@fo:color"> + <xsl:attribute name="html:Color"> + <xsl:value-of select="$styles/*/@fo:color" /> + </xsl:attribute> + </xsl:if> + <xsl:if test="$styles/*/@fo:font-size"> + <!-- WORKAROUND TO EXCEL2003 issue where nested FONT elements with size attributes result in unloadable documents --> + <!-- Only create size attribute if parent do not have already one --> + + <!--<xsl:choose> + <xsl:when test="not(key('styles', parent::*/@text:style-name)/*/@fo:font-size)"> --> + <xsl:if test="not(key('styles', parent::*/@text:style-name)/*/@fo:font-size)"> + <xsl:attribute name="html:Size"> + <xsl:call-template name="convert2pt"> + <xsl:with-param name="value" select="$styles/*/@fo:font-size" /> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:attribute> + </xsl:if> + <!--</xsl:when> + <xsl:otherwise> + <xsl:message>Due Excel issue we have to neglect size from @text:style-name '<xsl:value-of select="@text:style-name"/>'!</xsl:message> + </xsl:otherwise> + </xsl:choose>--> + </xsl:if> + <!-- get the embedded content --> + <xsl:apply-templates> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:apply-templates> + </xsl:element> + </xsl:when> + <xsl:otherwise> + <!-- get the embedded content --> + <xsl:apply-templates> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + +</xsl:stylesheet> diff --git a/filter/source/xslt/export/spreadsheetml/styles.xsl b/filter/source/xslt/export/spreadsheetml/styles.xsl new file mode 100644 index 000000000..a3c4b8bae --- /dev/null +++ b/filter/source/xslt/export/spreadsheetml/styles.xsl @@ -0,0 +1,686 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" + xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:dom="http://www.w3.org/2001/xml-events" + xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" + xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" + xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" + xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" + xmlns:math="http://www.w3.org/1998/Math/MathML" + xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" + xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" + xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" + xmlns:ooo="http://openoffice.org/2004/office" + xmlns:oooc="http://openoffice.org/2004/calc" + xmlns:ooow="http://openoffice.org/2004/writer" + xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" + xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" + xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible: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:xlink="http://www.w3.org/1999/xlink" + xmlns:xt="http://www.jclark.com/xt" + xmlns:common="http://exslt.org/common" + xmlns:xalan="http://xml.apache.org/xalan" + xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x2="http://schemas.microsoft.com/office/excel/2003/xml" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + exclude-result-prefixes="chart config dc dom dr3d draw fo form math meta number office ooo oooc ooow script style svg table text xlink xt common xalan"> + + <!-- Used in case of 'style:map', conditional formatting, where a style references to another --> + <xsl:key name="styles" match="/*/office:styles/style:style | /*/office:automatic-styles/style:style" use="@style:name" /> + <!-- + Mapping of OOo style:name and style:family to excel ss:ID + Styles form style:style map from style:name to ss:Name + style:parent-style map to ss:Parent + --> + <!-- default styles of the application + <xsl:template match="style:default-style" mode="styles" > + <xsl:call-template name="style:style"> + <xsl:with-param name="styleName" select="'Default'" /> + </xsl:call-template> + </xsl:template> + --> + + <xsl:template match="style:style" mode="styles"> + <xsl:param name="isAutomatic" /> + <xsl:param name="styleName" select="@style:name" /> + <xsl:param name="styleParentName" select="@style:parent-style-name" /> + + <!-- only row styles used by cells are exported, + as usual row style properties are already exported as row attributes --> + <xsl:if test="not(@style:family='table-row') or @style:family='table-row' and key('getCellByStyle', '.')"> + <xsl:element name="Style"> + <xsl:attribute name="ss:ID"> + <!-- neglecting that a style is only unique in conjunction with its family name --> + <xsl:value-of select="@style:name" /> + </xsl:attribute> + <xsl:choose> + <xsl:when test="not($isAutomatic)"> + <xsl:choose> + <xsl:when test="@style:display-name"> + <xsl:attribute name="ss:Name"><xsl:value-of select="@style:display-name"/></xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:attribute name="ss:Name"><xsl:value-of select="@style:name" /></xsl:attribute> + </xsl:otherwise> + </xsl:choose> + <xsl:choose> + <!-- when a non-allowed parent style is found + (in spreadsheetml no style with ss:Name is able to have a ss:Parent) --> + <xsl:when test="@style:parent-style-name"> + <!-- styles have to be merged (flatting heritance tree) --> + <xsl:variable name="stylePropertiesContainer"> + <xsl:call-template name="merge-all-parent-styles"> + <xsl:with-param name="currentStyle" select="." /> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="function-available('xalan:nodeset')"> + <xsl:call-template name="write-style-properties"> + <xsl:with-param name="styleProperties" select="xalan:nodeset($stylePropertiesContainer)/*" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('common:node-set')"> + <xsl:call-template name="write-style-properties"> + <xsl:with-param name="styleProperties" select="common:node-set($stylePropertiesContainer)/*" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('xt:node-set')"> + <xsl:call-template name="write-style-properties"> + <xsl:with-param name="styleProperties" select="xt:node-set($stylePropertiesContainer)/*" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes">WARNING: The required node set function was not found!</xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="write-style-properties" /> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <!-- automatic styles are implicit inheriting from a style called 'Default', + furthermore nor in spreadsheetml nor in OpenDocument automatic styles are able to inherit from each other --> + <xsl:choose> + <xsl:when test="@style:parent-style-name and not(@style:parent-style-name = 'Default')"> + <xsl:attribute name="ss:Parent"><xsl:value-of select="@style:parent-style-name" /></xsl:attribute> + </xsl:when> + </xsl:choose> + <xsl:call-template name="write-style-properties" /> + </xsl:otherwise> + </xsl:choose> + </xsl:element> + </xsl:if> + </xsl:template> + + <!-- resolving the style inheritance by starting from uppermost parent and + overriding existing style properties by new found child properties --> + <xsl:template name="merge-all-parent-styles"> + <xsl:param name="currentStyle" /> + + <xsl:choose> + <!-- in case of a parent, styles have to be merged (flatting heritance tree) --> + <xsl:when test="$currentStyle/@style:parent-style-name"> + <!-- collect parent style properties --> + <xsl:variable name="parentStyleContainer"> + <!-- take a look if the parent style has a parent himself --> + <xsl:call-template name="merge-all-parent-styles" > + <xsl:with-param name="currentStyle" select="key('styles', $currentStyle/@style:parent-style-name)" /> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="function-available('xalan:nodeset')"> + <xsl:call-template name="merge-style-properties"> + <xsl:with-param name="childStyleContainer" select="$currentStyle" /> + <xsl:with-param name="parentStyleContainer" select="xalan:nodeset($parentStyleContainer)" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('common:node-set')"> + <xsl:call-template name="merge-style-properties"> + <xsl:with-param name="childStyleContainer" select="$currentStyle" /> + <xsl:with-param name="parentStyleContainer" select="common:node-set($parentStyleContainer)" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('xt:node-set')"> + <xsl:call-template name="merge-style-properties"> + <xsl:with-param name="childStyleContainer" select="$currentStyle" /> + <xsl:with-param name="parentStyleContainer" select="xt:node-set($parentStyleContainer)" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes">WARNING: The required node-set function was not found!</xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <!-- called for top parents (or styles without parents) --> + <xsl:otherwise> + <xsl:copy-of select="$currentStyle/*"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="merge-style-properties"> + <xsl:param name="childStyleContainer" /> + <xsl:param name="parentStyleContainer" /> + + <xsl:choose> + <xsl:when test="$parentStyleContainer/*"> + <xsl:apply-templates select="$parentStyleContainer/*" mode="inheritance"> + <xsl:with-param name="childStyleContainer" select="$childStyleContainer" /> + </xsl:apply-templates> + </xsl:when> + <xsl:otherwise> + <xsl:copy-of select="$childStyleContainer/*"/> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="*" mode="inheritance"> + <xsl:param name="childStyleContainer" /> + + <!-- create an element named equal to the current properties parent element (e.g. style:table-cell-properties) --> + <xsl:element name="{name()}" namespace="urn:oasis:names:tc:opendocument:xmlns:style:1.0"> + <!-- attributes will be automatically replaced --> + <xsl:copy-of select="@*" /> + <xsl:copy-of select="$childStyleContainer/*[name() = name(current() )]/@*"/> + + <!-- elements are not needed yet, will be neglected for simplicity reasons --> + </xsl:element> + </xsl:template> + + <xsl:key match="/*/office:styles/number:date-style | + /*/office:styles/number:time-style | + /*/office:styles/number:number-style | + /*/office:styles/number:percentage-style | + /*/office:styles/number:currency-style | + /*/office:automatic-styles/number:date-style | + /*/office:automatic-styles/number:time-style | + /*/office:automatic-styles/number:number-style | + /*/office:automatic-styles/number:percentage-style | + /*/office:automatic-styles/number:currency-style" name="number-style" use="@style:name" /> + + + <xsl:template name="write-style-properties"> + <xsl:param name="styleProperties" select="key('styles', @style:name)/*" /> + + <xsl:call-template name="Alignment"> + <xsl:with-param name="styleProperties" select="$styleProperties" /> + </xsl:call-template> + <xsl:call-template name="Border"> + <xsl:with-param name="styleProperties" select="$styleProperties" /> + </xsl:call-template> + <xsl:call-template name="Font"> + <xsl:with-param name="styleProperties" select="$styleProperties" /> + <xsl:with-param name="styleParentName" select="@style:parent-style-name" /> + </xsl:call-template> + <xsl:call-template name="Interior"> + <xsl:with-param name="styleProperties" select="$styleProperties" /> + </xsl:call-template> + <xsl:call-template name="NumberFormat"> + <xsl:with-param name="styleProperties" select="$styleProperties" /> + </xsl:call-template> + </xsl:template> + + <!-- context is element 'style:style' --> + <xsl:template name="NumberFormat"> + <xsl:if test="@style:data-style-name"> + <xsl:variable name="numberStyleName" select="@style:data-style-name" /> + <xsl:variable name="numberStyle" select="key('number-style', $numberStyleName)" /> + + <xsl:element name="NumberFormat"> + <xsl:attribute name="ss:Format"> + <xsl:choose> + <xsl:when test="not($numberStyle/node())"> + <!-- Excel2003sp1 issue: 'General' and 'General Number' is not supported --> + <xsl:text>General</xsl:text> + </xsl:when> + <xsl:when test="name($numberStyle) = 'number:number-style'"> + <xsl:choose> + <xsl:when test="$numberStyle/number:scientific-number"> + <xsl:text>Scientific</xsl:text> + </xsl:when> + <!-- Excel2003sp1 issue: 'General Number' not supported --> + <xsl:when test="$numberStyle/number:number/@number:decimal-places and + $numberStyle/number:number/@number:decimal-places='0'"> + <xsl:text>General</xsl:text> + </xsl:when> + <xsl:when test="$numberStyle/number:text"> + <xsl:choose> + <xsl:when test="$numberStyle/number:text = 'No' or $numberStyle/number:text = 'Nein'"> + <xsl:text>Yes/No</xsl:text> + </xsl:when> + <xsl:when test="$numberStyle/number:text = 'False' or $numberStyle/number:text = 'Falsch'"> + <xsl:text>True/False</xsl:text> + </xsl:when> + <xsl:when test="$numberStyle/number:text = 'Off' or $numberStyle/number:text = 'Aus'"> + <xsl:text>On/Off</xsl:text> + </xsl:when> + <!-- Excel2003sp1 issue: currency is saved as 'float' --> + <xsl:when test="$numberStyle/number:currency-symbol"> + <xsl:choose> + <xsl:when test="contains($numberStyle/number:currency-symbol, '€')"> + <xsl:text>Euro Currency</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>Currency</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <!-- Excel2003sp1 issue: 'Currency' is saved as 'float' --> + <xsl:when test="contains($numberStyle/number:text, '$')"> + <xsl:text>Currency</xsl:text> + </xsl:when> + <!-- OASIS XML adaptation --> + <xsl:otherwise> + <xsl:text>General</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="$numberStyle/number:grouping"> + <xsl:text>Standard</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>Fixed</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="name($numberStyle) = 'number:time-style'"> + <xsl:choose> + <xsl:when test="$numberStyle/number:am-pm"> + <xsl:choose> + <xsl:when test="$numberStyle/number:seconds"> + <xsl:text>Long Time</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>Medium Time</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:text>Short Time</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="name($numberStyle) = 'number:percentage-style'"> + <xsl:text>Percent</xsl:text> + </xsl:when> + <xsl:when test="name($numberStyle) = 'number:currency-style'"> + <xsl:choose> + <xsl:when test="contains($numberStyle/number:currency-symbol, '€')"> + <xsl:text>Euro Currency</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>Currency</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="$numberStyle/number:month"> + <xsl:choose> + <xsl:when test="$numberStyle/number:month/@number:textual and + $numberStyle/number:month/@number:textual=true()"> + <xsl:text>Medium Date</xsl:text> + <!-- Excel2003 sp1 issue: No difference between 'Long Date' and 'Medium Date' --> + </xsl:when> + <xsl:when test="$numberStyle/number:hours"> + <xsl:text>General Date</xsl:text> + </xsl:when> + <xsl:when test="$numberStyle/number:year/@number:style and + $numberStyle/number:year/@number:style='long'"> + <xsl:text>Short Date</xsl:text> + </xsl:when> + <!-- OASIS XML adaptation --> + <xsl:otherwise> + <xsl:text>Short Date</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <!-- OASIS XML adaptation --> + <xsl:otherwise> + <xsl:text>General</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:element> + </xsl:if> + </xsl:template> + + <xsl:template name="Alignment"> + <xsl:param name="styleProperties" /> + + <!-- An empty Alignment element, might overwrite parents setting by + the default attributes --> + <xsl:if test="$styleProperties/@fo:text-align or + $styleProperties/@style:vertical-align or + $styleProperties/@fo:wrap-option or + $styleProperties/@fo:margin-left or + $styleProperties/@style:rotation-angle or + $styleProperties/@style:direction"> + <xsl:element name="Alignment"> + <xsl:if test="$styleProperties/@fo:text-align"> + <xsl:attribute name="ss:Horizontal"> + <xsl:choose> + <xsl:when test="$styleProperties/@fo:text-align = 'center'">Center</xsl:when> + <xsl:when test="$styleProperties/@fo:text-align = 'end'">Right</xsl:when> + <xsl:when test="$styleProperties/@fo:text-align = 'justify'">Justify</xsl:when> + <xsl:otherwise>Left</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@style:vertical-align"> + <xsl:attribute name="ss:Vertical"> + <xsl:choose> + <xsl:when test="$styleProperties/@style:vertical-align = 'top'">Top</xsl:when> + <xsl:when test="$styleProperties/@style:vertical-align = 'bottom'">Bottom</xsl:when> + <xsl:when test="$styleProperties/@style:vertical-align = 'middle'">Center</xsl:when> + <xsl:otherwise>Automatic</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@fo:wrap-option = 'wrap'"> + <xsl:attribute name="ss:WrapText">1</xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@fo:margin-left"> + <xsl:attribute name="ss:Indent"> + <xsl:variable name="margin"> + <xsl:call-template name="convert2pt"> + <xsl:with-param name="value" select="$styleProperties/@fo:margin-left" /> + <xsl:with-param name="rounding-factor" select="1" /> + </xsl:call-template> + </xsl:variable> + <!-- one ss:Indent is equal to 10 points --> + <xsl:value-of select="number($margin) div 10"/> + </xsl:attribute> + </xsl:if> + <!-- Excel is only able to rotate between 90 and -90 degree (inclusive). + Other degrees will be mapped by 180 degrees --> + <xsl:if test="$styleProperties/@style:rotation-angle"> + <xsl:attribute name="ss:Rotate"> + <xsl:choose> + <xsl:when test="$styleProperties/@style:rotation-angle > 90"> + <xsl:choose> + <xsl:when test="$styleProperties/@style:rotation-angle >= 270"> + <xsl:value-of select="$styleProperties/@style:rotation-angle - 360" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$styleProperties/@style:rotation-angle - 180" /> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="$styleProperties/@style:rotation-angle < -90"> + <xsl:choose> + <xsl:when test="$styleProperties/@style:rotation-angle <= -270"> + <xsl:value-of select="$styleProperties/@style:rotation-angle + 360" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$styleProperties/@style:rotation-angle + 180" /> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$styleProperties/@style:rotation-angle" /> + </xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@style:direction = 'ttb'"> + <xsl:attribute name="ss:VerticalText">1</xsl:attribute> + </xsl:if> + </xsl:element> + </xsl:if> + </xsl:template> + + + <xsl:template name="Border"> + <xsl:param name="styleProperties" /> + + <!-- An empty border element, might overwrite parents setting by + the default attributes --> + <xsl:if test="$styleProperties/@fo:border or + $styleProperties/@fo:border-bottom or + $styleProperties/@fo:border-left or + $styleProperties/@fo:border-right or + $styleProperties/@fo:border-top"> + <xsl:element name="Borders"> + <xsl:if test="$styleProperties/@fo:border-bottom and not($styleProperties/@fo:border-bottom = 'none')"> + <xsl:element name="Border"> + <xsl:attribute name="ss:Position">Bottom</xsl:attribute> + <xsl:call-template name="border-attributes"> + <xsl:with-param name="border_properties" select="$styleProperties/@fo:border-bottom" /> + </xsl:call-template> + </xsl:element> + </xsl:if> + <xsl:if test="$styleProperties/@fo:border-left and not($styleProperties/@fo:border-left = 'none')"> + <xsl:element name="Border"> + <xsl:attribute name="ss:Position">Left</xsl:attribute> + <xsl:call-template name="border-attributes"> + <xsl:with-param name="border_properties" select="$styleProperties/@fo:border-left" /> + </xsl:call-template> + </xsl:element> + </xsl:if> + <xsl:if test="$styleProperties/@fo:border-right and not($styleProperties/@fo:border-right = 'none')"> + <xsl:element name="Border"> + <xsl:attribute name="ss:Position">Right</xsl:attribute> + <xsl:call-template name="border-attributes"> + <xsl:with-param name="border_properties" select="$styleProperties/@fo:border-right" /> + </xsl:call-template> + </xsl:element> + </xsl:if> + <xsl:if test="$styleProperties/@fo:border-top and not($styleProperties/@fo:border-top = 'none')"> + <xsl:element name="Border"> + <xsl:attribute name="ss:Position">Top</xsl:attribute> + <xsl:call-template name="border-attributes"> + <xsl:with-param name="border_properties" select="$styleProperties/@fo:border-top" /> + </xsl:call-template> + </xsl:element> + </xsl:if> + <!-- write out all table border --> + <xsl:if test="$styleProperties/@fo:border and not($styleProperties/@fo:border = 'none')"> + <xsl:element name="Border"> + <xsl:attribute name="ss:Position">Bottom</xsl:attribute> + <xsl:call-template name="border-attributes"> + <xsl:with-param name="border_properties" select="$styleProperties/@fo:border" /> + </xsl:call-template> + </xsl:element> + <xsl:element name="Border"> + <xsl:attribute name="ss:Position">Left</xsl:attribute> + <xsl:call-template name="border-attributes"> + <xsl:with-param name="border_properties" select="$styleProperties/@fo:border" /> + </xsl:call-template> + </xsl:element> + <xsl:element name="Border"> + <xsl:attribute name="ss:Position">Right</xsl:attribute> + <xsl:call-template name="border-attributes"> + <xsl:with-param name="border_properties" select="$styleProperties/@fo:border" /> + </xsl:call-template> + </xsl:element> + <xsl:element name="Border"> + <xsl:attribute name="ss:Position">Top</xsl:attribute> + <xsl:call-template name="border-attributes"> + <xsl:with-param name="border_properties" select="$styleProperties/@fo:border" /> + </xsl:call-template> + </xsl:element> + </xsl:if> + </xsl:element> + </xsl:if> + </xsl:template> + + + <xsl:template name="border-attributes"> + <xsl:param name="border_properties" /> + + <xsl:variable name="border-width"> + <xsl:call-template name="convert2cm"> + <xsl:with-param name="value" select="substring-before($border_properties, ' ')" /> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="border-style" select="substring-before(substring-after($border_properties, ' '), ' ')" /> + <xsl:variable name="border-color" select="substring-after(substring-after($border_properties, ' '), ' ')" /> +<!-- + <xsl:message>border-width:<xsl:value-of select="$border-width" /></xsl:message> + <xsl:message>border-style:<xsl:value-of select="$border-style" /></xsl:message> + <xsl:message>border-color:<xsl:value-of select="$border-color" /></xsl:message> + --> + + <!-- Dash, Dot, DashDot, DashDotDot, SlantDashDot are not supported yet --> + <xsl:attribute name="ss:LineStyle"> + <xsl:choose> + <xsl:when test="$border-style = 'none'">None</xsl:when> + <xsl:when test="$border-style = 'double'">Double</xsl:when> + <xsl:otherwise>Continuous</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + + <xsl:attribute name="ss:Weight"> + <xsl:choose> + <!-- 0: Hairline --> + <xsl:when test="$border-width <= 0.002">0</xsl:when> + <!-- 1: Thin --> + <xsl:when test="$border-width <= 0.035">1</xsl:when> + <!-- 2: Medium --> + <xsl:when test="$border-width <= 0.088">2</xsl:when> + <!-- 3: Thick --> + <xsl:otherwise>3</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + + <xsl:attribute name="ss:Color"> + <xsl:choose> + <xsl:when test="$border-color"><xsl:value-of select="$border-color" /></xsl:when> + <xsl:otherwise>Automatic</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:template> + + + <xsl:template name="Font"> + <xsl:param name="styleProperties" /> + <xsl:param name="styleParentName" /> + + <!-- An empty font element, might overwrite parents setting by + the default attributes --> + <xsl:if test="$styleProperties/@style:font-weight or + $styleProperties/@fo:color or + $styleProperties/@style:font-name or + $styleProperties/@fo:font-style or + $styleProperties/@style:text-outline or + $styleProperties/@style:text-shadow or + $styleProperties/@style:font-size or + $styleProperties/@style:text-line-through-style or + $styleProperties/@style:text-underline-type or + $styleProperties/@style:text-underline-style or + $styleProperties/@style:text-position"> + + + <xsl:element name="Font"> + <xsl:call-template name="getParentBold"> + <xsl:with-param name="styleProperties" select="$styleProperties" /> + <xsl:with-param name="styleParentName" select="$styleParentName" /> + </xsl:call-template> + <xsl:if test="$styleProperties/@fo:color"> + <xsl:attribute name="ss:Color"><xsl:value-of select="$styleProperties/@fo:color" /></xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@style:font-name"> + <xsl:attribute name="ss:FontName"><xsl:value-of select="$styleProperties/@style:font-name" /></xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@fo:font-style = 'italic'"> + <xsl:attribute name="ss:Italic">1</xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@style:text-outline = 'true'"> + <xsl:attribute name="ss:Outline">1</xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@style:text-shadow = 'shadow'"> + <xsl:attribute name="ss:Shadow">1</xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@fo:font-size"> + <xsl:attribute name="ss:Size"> + <xsl:call-template name="convert2pt"> + <xsl:with-param name="value" select="$styleProperties/@fo:font-size" /> + </xsl:call-template> + </xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@style:text-line-through-style and $styleProperties/@style:text-line-through-style != 'none'"> + <xsl:attribute name="ss:StrikeThrough">1</xsl:attribute> + </xsl:if> + <xsl:if test="($styleProperties/@style:text-underline-type and $styleProperties/@style:text-underline-type != 'none') or + ($styleProperties/@style:text-underline-style and $styleProperties/@style:text-underline-style != 'none')"> + <xsl:attribute name="ss:Underline"> + <xsl:choose> + <xsl:when test="$styleProperties/@style:text-underline-type = 'double'">Double</xsl:when> + <xsl:otherwise>Single</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + <xsl:if test="$styleProperties/@style:text-position"> + <xsl:attribute name="ss:VerticalAlign"> + <xsl:choose> + <xsl:when test="substring-before($styleProperties/@style:text-position, '% ') > 0">Superscript</xsl:when> + <xsl:otherwise>Subscript</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + </xsl:if> + </xsl:element> + </xsl:if> + </xsl:template> + + <xsl:template name="Interior"> + <xsl:param name="styleProperties" /> + <xsl:if test="$styleProperties/@fo:background-color and not($styleProperties/@fo:background-color = 'transparent')"> + <xsl:element name="Interior"> + <xsl:attribute name="ss:Color"> + <xsl:value-of select="$styleProperties/@fo:background-color" /> + </xsl:attribute> + <!-- Background color (i.e. Interior/ss:Color) not shown without ss:Pattern (or with 'none') + Therefore a default is set --> + <xsl:attribute name="ss:Pattern">Solid</xsl:attribute> + </xsl:element> + </xsl:if> + </xsl:template> + + <!-- Excel issue workaround: <Font ss:Bold="1"> is not inherited --> + <xsl:template name="getParentBold"> + <xsl:param name="styleProperties" /> + <xsl:param name="styleParentName" /> + <xsl:param name="styleName" /> + + <xsl:if test="$styleParentName and $styleParentName != $styleName"> + <xsl:choose> + <xsl:when test="$styleProperties/@fo:font-weight = 'bold'"> + <xsl:attribute name="ss:Bold">1</xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="getParentBold"> + <xsl:with-param name="styleProperties" select="key('styles', $styleParentName)/*" /> + <xsl:with-param name="styleParentName" select="key('styles', $styleParentName)/@style:parent-style-name" /> + <xsl:with-param name="styleName" select="$styleParentName" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + </xsl:template> + +</xsl:stylesheet> diff --git a/filter/source/xslt/export/spreadsheetml/table.xsl b/filter/source/xslt/export/spreadsheetml/table.xsl new file mode 100644 index 000000000..73d16b3eb --- /dev/null +++ b/filter/source/xslt/export/spreadsheetml/table.xsl @@ -0,0 +1,928 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" + xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:dom="http://www.w3.org/2001/xml-events" + xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" + xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" + xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" + xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" + xmlns:math="http://www.w3.org/1998/Math/MathML" + xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" + xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" + xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" + xmlns:ooo="http://openoffice.org/2004/office" + xmlns:oooc="http://openoffice.org/2004/calc" + xmlns:ooow="http://openoffice.org/2004/writer" + xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" + xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" + xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible: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:xlink="http://www.w3.org/1999/xlink" + xmlns:xt="http://www.jclark.com/xt" + xmlns:common="http://exslt.org/common" + xmlns:xalan="http://xml.apache.org/xalan" + xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:c="urn:schemas-microsoft-com:office:component:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x2="http://schemas.microsoft.com/office/excel/2003/xml" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + exclude-result-prefixes="chart config dc dom dr3d draw fo form math meta number office ooo oooc ooow script style svg table text xlink xt common xalan"> + + + <!-- ************** --> + <!-- *** Table *** --> + <!-- ************** --> + + <!-- check existence of default cell style --> + <xsl:variable name="firstDefaultCellStyle" select="descendant::table:table-column/@table:default-cell-style-name" /> + + + <xsl:template match="table:table" name="table:table"> + <xsl:element name="Table"> + <xsl:apply-templates select="@table:style-name" /> + + <!-- find all columns in the table --> + <xsl:variable name="columnNodes" select="descendant::table:table-column" /> + <!-- calculate the overall column amount --> + <xsl:variable name="maxColumnNo"> + <xsl:choose> + <xsl:when test="$columnNodes/@table:number-columns-repeated"> + <xsl:value-of select="count($columnNodes) + + number(sum($columnNodes/@table:number-columns-repeated)) + - count($columnNodes/@table:number-columns-repeated)" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="count($columnNodes)"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <!-- create columns --> + <xsl:apply-templates select="$columnNodes[1]"> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + <xsl:with-param name="maxColumnNo" select="$maxColumnNo" /> + </xsl:apply-templates> + + <!-- create rows --> + <xsl:choose> + <xsl:when test="not($columnNodes/@table:number-columns-repeated)"> + <xsl:call-template name="optimized-row-handling"> + <xsl:with-param name="rowNodes" select="descendant::table:table-row" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <!-- To be able to match from a cell to the corresponding column to match @table:default-cell-style-name, + the repeated columns are being resolved by copying them in a helper variable --> + <xsl:variable name="columnNodes-RTF"> + <xsl:for-each select="$columnNodes"> + <xsl:call-template name="adding-column-styles-entries" /> + </xsl:for-each> + </xsl:variable> + <xsl:choose> + <xsl:when test="function-available('xalan:nodeset')"> + <xsl:call-template name="optimized-row-handling"> + <xsl:with-param name="rowNodes" select="descendant::table:table-row" /> + <xsl:with-param name="columnNodes" select="xalan:nodeset($columnNodes-RTF)" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('common:node-set')"> + <xsl:call-template name="optimized-row-handling"> + <xsl:with-param name="rowNodes" select="descendant::table:table-row" /> + <xsl:with-param name="columnNodes" select="common:node-set($columnNodes-RTF)" /> + </xsl:call-template> + </xsl:when> + <xsl:when test="function-available('xt:node-set')"> + <xsl:call-template name="optimized-row-handling"> + <xsl:with-param name="rowNodes" select="descendant::table:table-row" /> + <xsl:with-param name="columnNodes" select="xt:node-set($columnNodes-RTF)" /> + </xsl:call-template> + </xsl:when> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:element> + </xsl:template> + + + <!-- **************** --> + <!-- *** Columns *** --> + <!-- **************** --> + + <xsl:template match="table:table-column"> + <xsl:param name="columnNodes" /> + <xsl:param name="currentColumnNumber" select="1" /> + <xsl:param name="setIndex" select="false()" /> + <xsl:param name="maxColumnNo" /> + + <xsl:element name="Column"> + <xsl:if test="@table:visibility = 'collapse' or @table:visibility = 'filter'"> + <xsl:attribute name="ss:Hidden">1</xsl:attribute> + </xsl:if> + + <xsl:if test="@table:number-columns-repeated"> + <xsl:attribute name="ss:Span"> + <xsl:value-of select="@table:number-columns-repeated - 1" /> + </xsl:attribute> + </xsl:if> + + <xsl:if test="$setIndex"> + <xsl:attribute name="ss:Index"> + <xsl:value-of select="$currentColumnNumber" /> + </xsl:attribute> + </xsl:if> + + <xsl:choose> + <xsl:when test="@style:use-optimal-column-width = 'true'"> + <xsl:attribute name="ss:AutoFitWidth">1</xsl:attribute> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="width" select="key('styles', @table:style-name)/style:table-column-properties/@style:column-width" /> + <xsl:if test="$width"> + <xsl:attribute name="ss:Width"> + <!-- using the absolute width in point --> + <xsl:call-template name="convert2pt"> + <xsl:with-param name="value" select="$width" /> + </xsl:call-template> + </xsl:attribute> + </xsl:if> + </xsl:otherwise> + </xsl:choose> + + <xsl:if test="@table:number-columns-repeated"> + <xsl:attribute name="ss:Span"> + <xsl:value-of select="@table:number-columns-repeated - 1" /> + </xsl:attribute> + </xsl:if> + </xsl:element> + + <xsl:variable name="columnNumber"> + <xsl:choose> + <xsl:when test="@table:number-columns-repeated"> + <xsl:value-of select="$currentColumnNumber + @table:number-columns-repeated"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$currentColumnNumber"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:if test="$columnNumber < $maxColumnNo"> + <xsl:variable name="nextColumnNodes" select="$columnNodes[position() != 1]" /> + <xsl:choose> + <xsl:when test="@table:number-columns-repeated"> + <xsl:apply-templates select="$nextColumnNodes[1]"> + <xsl:with-param name="columnNodes" select="$nextColumnNodes" /> + <xsl:with-param name="currentColumnNumber" select="$columnNumber" /> + <xsl:with-param name="maxColumnNo" select="$maxColumnNo" /> + <xsl:with-param name="setIndex" select="true()" /> + </xsl:apply-templates> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="$nextColumnNodes[1]"> + <xsl:with-param name="columnNodes" select="$nextColumnNodes" /> + <xsl:with-param name="currentColumnNumber" select="$columnNumber + 1" /> + <xsl:with-param name="maxColumnNo" select="$maxColumnNo" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + </xsl:template> + + <!-- current node is a table:table-column --> + <xsl:template name="adding-column-styles-entries"> + <xsl:choose> + <xsl:when test="not(@table:number-columns-repeated and @table:number-columns-repeated > 1)"> + <!-- writes an entry of a column in the columns-variable --> + <xsl:copy-of select="." /> + </xsl:when> + <xsl:otherwise> + <!-- repeated columns will be written explicit several times in the variable--> + <xsl:call-template name="repeat-adding-table-column"> + <xsl:with-param name="numberColumnsRepeated" select="@table:number-columns-repeated" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- current node is a table:table-column --> + <!-- duplicates column elements in case of column-repeated attribute --> + <xsl:template name="repeat-adding-table-column"> + <xsl:param name="table:table-column" /> + <xsl:param name="numberColumnsRepeated" /> + + <xsl:choose> + <xsl:when test="$numberColumnsRepeated > 1"> + <!-- writes an entry of a column in the columns-variable --> + <xsl:copy-of select="." /> + <!-- repeat calling this method until all elements written out --> + <xsl:call-template name="repeat-adding-table-column"> + <xsl:with-param name="numberColumnsRepeated" select="$numberColumnsRepeated - 1" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <!-- writes an entry of a column in the columns-variable --> + <xsl:copy-of select="." /> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- ************* --> + <!-- *** Rows *** --> + <!-- ************* --> + + + <!-- Recursions are much faster when the stack size is small --> + <xsl:template name="optimized-row-handling"> + <xsl:param name="rowNodes" /> + <xsl:param name="columnNodes" /> + <xsl:param name="offset" select="0"/> + <xsl:param name="threshold" select="10"/> + + <xsl:variable name="rowCount" select="count($rowNodes)"/> + <xsl:choose> + <xsl:when test="$rowCount <= $threshold"> + <xsl:apply-templates select="$rowNodes[1]"> + <xsl:with-param name="rowNodes" select="$rowNodes" /> + <xsl:with-param name="offset" select="$offset" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:when> + <xsl:otherwise> + <xsl:variable name="rowCountHalf" select="floor($rowCount div 2)"/> + <xsl:variable name="rowNodesSetA" select="$rowNodes[position() <= $rowCountHalf]"/> + <xsl:variable name="rowNodesSetB" select="$rowNodes[position() > $rowCountHalf]"/> + <!-- to keep track of the rownumber, the repeated rows have to kept into accounts --> + <xsl:variable name="rowsCreatedByRepetition"> + <xsl:choose> + <xsl:when test="$rowNodesSetA/@table:number-rows-repeated"> + <xsl:value-of select="number(sum($rowNodesSetA/@table:number-rows-repeated)) + - count($rowNodesSetA/@table:number-rows-repeated)" /> + </xsl:when> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:choose> + <xsl:when test="$rowCountHalf > $threshold"> + <xsl:call-template name="optimized-row-handling"> + <xsl:with-param name="rowNodes" select="$rowNodesSetA"/> + <xsl:with-param name="offset" select="$offset" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + <xsl:call-template name="optimized-row-handling"> + <xsl:with-param name="rowNodes" select="$rowNodesSetB"/> + <xsl:with-param name="offset" select="$offset + $rowCountHalf + $rowsCreatedByRepetition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="$rowNodesSetA[1]"> + <xsl:with-param name="rowNodes" select="$rowNodesSetA"/> + <xsl:with-param name="offset" select="$offset" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + <xsl:apply-templates select="$rowNodesSetB[1]"> + <xsl:with-param name="rowNodes" select="$rowNodesSetB" /> + <xsl:with-param name="offset" select="$offset + $rowCountHalf + $rowsCreatedByRepetition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- + Rows as "table:table-row" might be grouped in + "table:table-header-rows" or "table:table-row-group" + This row-tree will be traversed providing each Row with its + calculatedRowPosition and earlierRowNumber. + By this repeated empty rows might be neglected in the spreadsheetml output, + as the following row will notice the 'gap' and provide @ss:Index, + which results in filling up the gap by a row without style and content. + + In Excel created rows by ss:Index are 'default' rows. + --> + <xsl:template match="table:table-row"> + <xsl:param name="earlierRowNumber" select="0" /> + <xsl:param name="offset" /> + <xsl:param name="calculatedRowPosition" select="$offset + 1" /> + <xsl:param name="rowNodes" /> + <xsl:param name="columnNodes" /> + + <xsl:choose> + <xsl:when test="@table:number-rows-repeated > 1"> + <xsl:call-template name="write-table-row"> + <xsl:with-param name="earlierRowNumber" select="$earlierRowNumber" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + <xsl:if test="@table:number-rows-repeated > 2 and (table:table-cell/@office:value-type or $firstDefaultCellStyle != '')"> + <!-- In case a cell is being repeated, the cell will be created + in a variable, which is as many times given out, as being repeated --> + <xsl:variable name="tableRow"> + <xsl:call-template name="write-table-row"> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:variable> + <xsl:call-template name="optimized-row-repeating"> + <xsl:with-param name="tableRow" select="$tableRow" /> + <xsl:with-param name="repetition" select="@table:number-rows-repeated - 1" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:if> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="write-table-row"> + <xsl:with-param name="earlierRowNumber" select="$earlierRowNumber" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + + <xsl:variable name="nextRowNodes" select="$rowNodes[position()!=1]" /> + <xsl:choose> + <xsl:when test="@table:number-rows-repeated > 1"> + <xsl:apply-templates select="$nextRowNodes[1]"> + <xsl:with-param name="earlierRowNumber" select="$calculatedRowPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition + @table:number-rows-repeated" /> + <xsl:with-param name="rowNodes" select="$nextRowNodes" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="$nextRowNodes[1]"> + <xsl:with-param name="earlierRowNumber" select="$calculatedRowPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition + 1" /> + <xsl:with-param name="rowNodes" select="$nextRowNodes" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template name="write-table-row"> + <xsl:param name="earlierRowNumber" select="0" /> + <xsl:param name="calculatedRowPosition" select="1" /> + <xsl:param name="columnNodes" /> + + <xsl:element name="Row"> + <xsl:if test="@table:visibility = 'collapse' or @table:visibility = 'filter'"> + <xsl:attribute name="ss:Hidden">1</xsl:attribute> + </xsl:if> + <xsl:if test="not($earlierRowNumber + 1 = $calculatedRowPosition)"> + <xsl:attribute name="ss:Index"><xsl:value-of select="$calculatedRowPosition" /></xsl:attribute> + </xsl:if> + + <!-- writing the style of the row --> + <xsl:apply-templates select="@table:style-name" mode="table-row" /> + + <xsl:variable name="rowProperties" select="key('styles', @table:style-name)/*" /> + <xsl:if test="$rowProperties/@style:use-optimal-row-height = 'false'"> + <!-- default is '1', therefore write only '0' --> + <xsl:attribute name="ss:AutoFitHeight">0</xsl:attribute> + </xsl:if> + + <xsl:variable name="height" select="$rowProperties/@style:row-height" /> + <xsl:if test="$height"> + <xsl:attribute name="ss:Height"> + <!-- using the absolute height in point --> + <xsl:call-template name="convert2pt"> + <xsl:with-param name="value" select="$height" /> + </xsl:call-template> + </xsl:attribute> + </xsl:if> + <xsl:apply-templates select="table:table-cell[1]"> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="cellNodes" select="table:table-cell" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:element> + </xsl:template> + + + <!-- Recursions are much faster when the stack size is small --> + <xsl:template name="optimized-row-repeating"> + <xsl:param name="tableRow" /> + <xsl:param name="repetition" /> + <!-- resource optimization: instead of '1' it will be '1000' and the column is not full --> + <xsl:param name="thresholdmax" select="512"/> + <xsl:param name="thresholdmin" select="256"/> + + <xsl:choose> + <xsl:when test="$repetition <= $thresholdmax"> + <xsl:copy-of select="$tableRow" /> + <xsl:if test="$repetition >= $thresholdmin"> + <xsl:call-template name="optimized-row-repeating"> + <xsl:with-param name="repetition" select="$repetition - 1"/> + <xsl:with-param name="tableRow" select="$tableRow" /> + </xsl:call-template> + </xsl:if> + </xsl:when> + <xsl:otherwise> + <xsl:if test="$repetition mod 2 = 1"> + <xsl:copy-of select="$tableRow" /> + </xsl:if> + <xsl:variable name="repetitionHalf" select="floor($repetition div 2)"/> + <xsl:call-template name="optimized-row-repeating"> + <xsl:with-param name="repetition" select="$repetitionHalf"/> + <xsl:with-param name="tableRow" select="$tableRow" /> + </xsl:call-template> + <xsl:call-template name="optimized-row-repeating"> + <xsl:with-param name="repetition" select="$repetitionHalf"/> + <xsl:with-param name="tableRow" select="$tableRow" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + + <!-- ************** --> + <!-- *** Cells *** --> + <!-- ************** --> + + <!-- Table cells are able to be repeated by attribute in StarOffice, + but not in Excel. If more cells are repeated --> + <xsl:template name="table:table-cell" match="table:table-cell"> + <xsl:param name="calculatedCellPosition" select="1" /><!-- the later table position of the current cell --> + <xsl:param name="calculatedRowPosition" /><!-- the later table position of the current row --> + <xsl:param name="setIndex" select="false()" /> <!-- if not '0' @ss:Index used for neglecting repeated empty cells --> + <xsl:param name="repetition" select="@table:number-columns-repeated" /> <!-- used for explicit written out cells --> + <xsl:param name="repetitionCellPosition" select="$calculatedCellPosition" /><!-- during repetition formula needs exact cell positioning --> + <xsl:param name="nextMatchedCellPosition"><!-- the later table position of the next cell --> + <xsl:choose> + <xsl:when test="not(@table:number-columns-repeated) and not(@table:number-columns-spanned)"> + <xsl:value-of select="$calculatedCellPosition + 1" /> + </xsl:when> + <xsl:when test="not(@table:number-columns-spanned)"> + <xsl:value-of select="$calculatedCellPosition + @table:number-columns-repeated" /> + </xsl:when> + <xsl:when test="not(@table:number-columns-repeated)"> + <xsl:value-of select="$calculatedCellPosition + @table:number-columns-spanned" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$calculatedCellPosition + @table:number-columns-spanned * @table:number-columns-repeated" /> + </xsl:otherwise> + </xsl:choose> + </xsl:param> + <xsl:param name="cellNodes" /><!-- cells to be handled --> + <xsl:param name="columnNodes" /> + + <xsl:choose> + <!-- in case a repetition took place --> + <xsl:when test="$repetition > 0"> + <xsl:choose> + <!-- In case of no cell content (text, subelements, attribute, except repeated style) the ss:Index could be used --> + <xsl:when test="not(text()) and not(*) and not(@*[name() != 'table:number-columns-repeated'])"> + <xsl:choose> + <xsl:when test="count($cellNodes) = 1"> + <xsl:call-template name="create-table-cell"> + <xsl:with-param name="setIndex" select="true()" /> + <xsl:with-param name="calculatedCellPosition" select="$nextMatchedCellPosition - 1" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="$cellNodes[2]"> + <xsl:with-param name="calculatedCellPosition" select="$nextMatchedCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="setIndex" select="true()" /> + <xsl:with-param name="cellNodes" select="$cellNodes[position() != 1]" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <!-- Fastest cell repetition by creating cell once and copying, works not for + a) cells with formula (need of actual cell position) + b) cells, which start with ss:Index (as ss:Index is not allowed to be repeated) --> + <xsl:when test="not(@table:formula) and not($setIndex)"> + <!-- In case a non-empty cell is being repeated, the cell will be created + in a variable, which is as many times given out, as being repeated --> + <xsl:variable name="tableCell"> + <xsl:call-template name="create-table-cell"> + <xsl:with-param name="setIndex" select="false()" /><!-- copied cells may not have indices --> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:variable> + <xsl:call-template name="repeat-copy-table-cell"> + <xsl:with-param name="tableCell" select="$tableCell" /> + <xsl:with-param name="repetition" select="$repetition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + <xsl:apply-templates select="$cellNodes[2]"> + <xsl:with-param name="calculatedCellPosition" select="$nextMatchedCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="cellNodes" select="$cellNodes[position() != 1]" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:when> + <!-- explicit writing (instead of copying) of cell for the cases mentioned above --> + <xsl:otherwise> + <xsl:call-template name="create-table-cell"> + <xsl:with-param name="setIndex" select="$setIndex" /><!-- a possible Index will be created --> + <xsl:with-param name="calculatedCellPosition" select="$repetitionCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + <xsl:choose> + <!-- as long there is a repetition (higher '1') stay on the same cell node --> + <xsl:when test="$repetition > 1"> + <xsl:call-template name="table:table-cell"> + <xsl:with-param name="calculatedCellPosition" select="$nextMatchedCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="repetitionCellPosition"> + <xsl:choose> + <xsl:when test="@table:number-columns-spanned"> + <xsl:value-of select="$repetitionCellPosition + @table:number-columns-spanned" /> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$repetitionCellPosition + 1"/> + </xsl:otherwise> + </xsl:choose> + </xsl:with-param> + <xsl:with-param name="nextMatchedCellPosition" select="$nextMatchedCellPosition" /> + <xsl:with-param name="repetition" select="$repetition - 1" /> + <xsl:with-param name="cellNodes" select="$cellNodes" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="$cellNodes[2]"> + <xsl:with-param name="calculatedCellPosition" select="$nextMatchedCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="cellNodes" select="$cellNodes[position() != 1]" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <!-- in case no repetition took place --> + <xsl:choose> + <!-- neglect an empty cell by using ss:Index Attribute --> + <xsl:when test="not(text()) and not(*) and not(@*)"> + <xsl:choose> + <!-- if it is the last cell, write this cell --> + <xsl:when test="count($cellNodes) = 1"> + <xsl:call-template name="create-table-cell"> + <xsl:with-param name="setIndex" select="true()" /> + <xsl:with-param name="calculatedCellPosition" select="$nextMatchedCellPosition - 1" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:apply-templates select="$cellNodes[2]"> + <xsl:with-param name="setIndex" select="true()" /> + <xsl:with-param name="calculatedCellPosition" select="$nextMatchedCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="cellNodes" select="$cellNodes[position() != 1]" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <!-- create cell and use/unset the ss:Index --> + <xsl:call-template name="create-table-cell"> + <xsl:with-param name="setIndex" select="$setIndex" /> + <xsl:with-param name="calculatedCellPosition" select="$calculatedCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:call-template> + <xsl:apply-templates select="$cellNodes[2]"> + <xsl:with-param name="calculatedCellPosition" select="$nextMatchedCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + <xsl:with-param name="cellNodes" select="$cellNodes[position() != 1]" /> + <xsl:with-param name="columnNodes" select="$columnNodes" /> + </xsl:apply-templates> + </xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Copies the variable 'tableCell' to the output as often as 'repetition' --> + <xsl:template name="repeat-copy-table-cell"> + <xsl:param name="tableCell" /> + <xsl:param name="repetition" /> + + <xsl:if test="$repetition > 0"> + <xsl:copy-of select="$tableCell"/> + <xsl:call-template name="repeat-copy-table-cell"> + <xsl:with-param name="tableCell" select="$tableCell" /> + <xsl:with-param name="repetition" select="$repetition - 1" /> + </xsl:call-template> + </xsl:if> + </xsl:template> + + <xsl:template name="create-table-cell"> + <xsl:param name="setIndex" select="false()" /> + <xsl:param name="calculatedCellPosition" /> + <xsl:param name="calculatedRowPosition" /> + <xsl:param name="columnNodes" /> + + <xsl:element name="Cell" namespace="urn:schemas-microsoft-com:office:spreadsheet"> + <xsl:if test="$setIndex"> + <xsl:attribute name="ss:Index"> + <xsl:value-of select="$calculatedCellPosition"/> + </xsl:attribute> + </xsl:if> + <xsl:if test="@table:number-columns-spanned > 1"> + <xsl:attribute name="ss:MergeAcross"> + <xsl:value-of select="@table:number-columns-spanned - 1" /> + </xsl:attribute> + </xsl:if> + <xsl:if test="@table:number-rows-spanned > 1"> + <xsl:attribute name="ss:MergeDown"> + <xsl:value-of select="@table:number-rows-spanned - 1" /> + </xsl:attribute> + </xsl:if> + <xsl:variable name="link" select="descendant::text:a/@xlink:href" /> + <xsl:if test="$link"> + <xsl:attribute name="ss:HRef"> + <xsl:value-of select="$link" /> + </xsl:attribute> + </xsl:if> + <xsl:choose> + <xsl:when test="@table:style-name"> + <xsl:apply-templates select="@table:style-name" /> + </xsl:when> + <xsl:otherwise> + <xsl:if test="$firstDefaultCellStyle != ''"> + <xsl:variable name="defaultCellStyle" select="$columnNodes/table:table-column[position() = $calculatedCellPosition]/@table:default-cell-style-name" /> + <xsl:if test="$defaultCellStyle"> + <xsl:if test="not($defaultCellStyle = 'Default')"> + <xsl:attribute name="ss:StyleID"><xsl:value-of select="$defaultCellStyle"/></xsl:attribute> + </xsl:if> + </xsl:if> + </xsl:if> + </xsl:otherwise> + </xsl:choose> + <xsl:apply-templates select="@table:formula"> + <xsl:with-param name="calculatedCellPosition" select="$calculatedCellPosition" /> + <xsl:with-param name="calculatedRowPosition" select="$calculatedRowPosition" /> + </xsl:apply-templates> + <xsl:choose> + <xsl:when test="*"> + <!-- in case it is not an empty cell + + As the sequence of comment and data is opposite in Excel and Calc no match work here, in both comments exist only once + Possible Table Content of interest: text:h|text:p|text:list --> + <xsl:if test="text:h | text:p | text:list"> + <xsl:variable name="valueType"> + <xsl:choose> + <xsl:when test="@office:value-type"> + <xsl:value-of select="@office:value-type" /> + </xsl:when> + <xsl:otherwise>string</xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:call-template name="ss:Data"> + <xsl:with-param name="valueType" select="$valueType" /> + <xsl:with-param name="cellStyleName" select="@table:style-name" /> + </xsl:call-template> + </xsl:if> + + <xsl:if test="office:annotation"> + <xsl:element name="Comment"> + <xsl:if test="office:annotation/@office:author"> + <xsl:attribute name="ss:Author"><xsl:value-of select="office:annotation/@office:author" /></xsl:attribute> + </xsl:if> + <xsl:if test="office:annotation/@office:display = 'true'"> + <xsl:attribute name="ss:ShowAlways">1</xsl:attribute> + </xsl:if> + <!-- ss:Data is obligatory, but not the same as the ss:Cell ss:Data child, as it has no attributes --> + <ss:Data xmlns="http://www.w3.org/TR/REC-html40"> + <xsl:for-each select="office:annotation/text:p"> + <xsl:choose> + <xsl:when test="*"> + <!-- paragraph style have to be neglected due to Excel error, + which does not allow shadowing their HTML attributes --> + <xsl:for-each select="*"> + <xsl:call-template name="style-and-contents" /> + </xsl:for-each> + </xsl:when> + <xsl:when test="@text:style-name"> + <xsl:call-template name="style-and-contents" /> + </xsl:when> + <xsl:otherwise> + <!-- if no style is set, BOLD is set as default --> + <B> + <xsl:call-template name="style-and-contents" /> + </B> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + </ss:Data> + </xsl:element> + </xsl:if> + </xsl:when> + </xsl:choose> + </xsl:element> + </xsl:template> + + <!-- comments are handled separately in the cell --> + <xsl:template match="office:annotation" /> + <xsl:template match="dc:date" /> + + <xsl:template name="ss:Data"> + <!-- the default value is 'String' in the office --> + <xsl:param name="valueType" select="'string'" /> + <xsl:param name="cellStyleName" /> + + <xsl:choose> + <xsl:when test="descendant::*/@text:style-name"> + <xsl:choose> + <xsl:when test="$valueType = 'string'"> + <ss:Data ss:Type="String" xmlns="http://www.w3.org/TR/REC-html40"> + <xsl:apply-templates> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:apply-templates> + </ss:Data> + </xsl:when> + <xsl:when test="$valueType = 'boolean'"> + <ss:Data ss:Type="Boolean" xmlns="http://www.w3.org/TR/REC-html40"> + <xsl:apply-templates> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:apply-templates> + </ss:Data> + </xsl:when> + <xsl:when test="$valueType = 'date'"> + <ss:Data ss:Type="DateTime" xmlns="http://www.w3.org/TR/REC-html40"> + <xsl:apply-templates> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:apply-templates> + </ss:Data> + </xsl:when> + <!-- float, time, percentage, currency (no 'Error' setting) --> + <xsl:otherwise> + <ss:Data ss:Type="Number" xmlns="http://www.w3.org/TR/REC-html40"> + <xsl:apply-templates> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:apply-templates> + </ss:Data> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:element name="Data"> + <xsl:call-template name="ss:Type"> + <xsl:with-param name="valueType" select="$valueType" /> + </xsl:call-template> + </xsl:element> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <xsl:template name="ss:Type"> + <xsl:param name="valueType" select="'string'" /> + + <xsl:choose> + <xsl:when test="$valueType = 'string'"> + <xsl:attribute name="ss:Type">String</xsl:attribute> + <xsl:apply-templates select="*"/> + </xsl:when> + <xsl:when test="$valueType = 'boolean'"> + <xsl:attribute name="ss:Type">Boolean</xsl:attribute> + <xsl:choose> + <xsl:when test="@office:boolean-value = 'true'">1</xsl:when> + <xsl:otherwise>0</xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="$valueType = 'date' or $valueType = 'time'"> + <!-- issue in Excel: can not have an empty 'DateTime' cell --> + <xsl:attribute name="ss:Type">DateTime</xsl:attribute> + <!-- Gathering information of two StarOffice date/time attributes + Excel always needs both pieces of information in one attribute --> + <xsl:choose> + <xsl:when test="@office:date-value"> + <!-- office:date-value may contain time (after 'T')--> + <xsl:choose> + <xsl:when test="contains(@office:date-value, 'T')"> + <!-- in case time is also part of the date --> + <xsl:value-of select="substring-before(@office:date-value, 'T')" /> + <xsl:text>T</xsl:text> + <xsl:value-of select="substring-after(@office:date-value,'T')" /> + <xsl:if test="not(contains(@office:date-value,'.'))"> + <xsl:text>.</xsl:text> + </xsl:if> + <xsl:text>000</xsl:text> + </xsl:when> + <xsl:when test="@office:time-value"> + <!-- contains date and time (time will be evaluated later --> + <xsl:value-of select="@office:date-value" /> + <xsl:text>T</xsl:text> + <xsl:choose> + <xsl:when test="@table:formula or contains(@office:time-value,',')"> + <!-- customized number types not implemented yet --> + <xsl:text>00:00:00.000</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="translate(substring-after(@office:time-value,'PT'),'HMS','::.')" /> + <xsl:if test="not(contains(@office:time-value,'S'))"> + <xsl:text>.</xsl:text> + </xsl:if> + <xsl:text>000</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@office:date-value" /> + <xsl:text>T00:00:00.000</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise> + <xsl:if test="@office:time-value"> + <xsl:text>1899-12-31T</xsl:text> + <xsl:choose> + <xsl:when test="@table:formula or contains(@office:time-value,',')"> + <!-- customized number types not implemented yet --> + <xsl:text>00:00:00.000</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="translate(substring-after(@office:time-value,'PT'),'HMS','::.')" /> + <xsl:if test="not(contains(@office:time-value,'S'))"> + <xsl:text>.</xsl:text> + </xsl:if> + <xsl:text>000</xsl:text> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <!-- float, percentage, currency (no 'Error' setting) --> + <xsl:otherwise> + <xsl:attribute name="ss:Type">Number</xsl:attribute> + <xsl:value-of select="@office:value" /> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + + <!-- ******************** --> + <!-- *** Common Rules *** --> + <!-- ******************** --> + + <xsl:template match="*"> + <xsl:param name="cellStyleName" /> + +<!-- LineBreak in Cell --> + <xsl:if test="preceding-sibling::text:p[1]"><xsl:text> </xsl:text></xsl:if> + <xsl:call-template name="style-and-contents"> + <xsl:with-param name="cellStyleName" select="$cellStyleName" /> + </xsl:call-template> + </xsl:template> + + <!-- disabling draw:frames --> + <xsl:template match="draw:frame" /> + + <xsl:template match="text:s"> + <xsl:call-template name="write-breakable-whitespace"> + <xsl:with-param name="whitespaces" select="@text:c" /> + </xsl:call-template> + </xsl:template> + + <!--write the number of 'whitespaces' --> + <xsl:template name="write-breakable-whitespace"> + <xsl:param name="whitespaces" /> + + <xsl:text> </xsl:text> + <xsl:if test="$whitespaces >= 1"> + <xsl:call-template name="write-breakable-whitespace"> + <xsl:with-param name="whitespaces" select="$whitespaces - 1" /> + </xsl:call-template> + </xsl:if> + </xsl:template> + + <!-- allowing all matched text nodes --> + <xsl:template match="text()"><xsl:value-of select="." /></xsl:template> + +</xsl:stylesheet> + |