Mercurial > hg > ooxml
view refs.xsl @ 34:93fd0d532754
fix bug in refs wrt e.g. [1]!.SGX,
adapt html and ascii to new-format refs,
move a2n and n2a into separate files for re-use
author | Henry S. Thompson <ht@markup.co.uk> |
---|---|
date | Wed, 12 Apr 2017 21:35:04 +0100 |
parents | 27bffc66ce10 |
children | ae605b77d1e4 |
line wrap: on
line source
<?xml version='1.0'?> <!DOCTYPE doc SYSTEM "../../../lib/xml/xsl.dtd" > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" xmlns:s="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:e="http://markup.co.uk/excel" exclude-result-prefixes="xs s e xf" xmlns="http://markup.co.uk/excel" xmlns:xf="http://www.w3.org/2005/xpath-functions"> <xsl:param name="sheet-number"/> <xsl:param name="xlDir"/> <xsl:variable name="pat1">("[^"]*")|(\{[^}]+})|(,)|([^=\-+*/();:,.$<>^!]+(?:\.[^=\-+*/();:,.$<>^!]+)*\()|([)])|(^=|\()|((?:'[^']+')|(?:\[[0-9]+\][^!]*))|(\$?[A-Z]+\$?[0-9]+)|([a-zA-Z_\\][a-zA-Z0-9._]*)|(.)</xsl:variable> <xsl:param name="pat" select="$pat1"/><!-- xsl:param for refinement debugging by passing in the pattern --> <xsl:variable name="workbook" select="document(concat($xlDir,'/workbook.xml'))/*"/> <xsl:variable name="sheet-name" select="$workbook/s:sheets/s:sheet[@sheetId=$sheet-number]/@name"/> <xsl:function name="e:lookup" as="xs:string*"> <xsl:param name="name" as="xs:string" required="yes"/> <xsl:variable name="defn" select="$workbook/s:definedNames/s:definedName[@name=$name]"/> <xsl:sequence select="let $prefix := concat($sheet-name,'!') return if ($defn and starts-with($defn,$prefix)) then substring-after($defn,$prefix) else ()"/> </xsl:function> <xsl:function name="e:tokenise" as="array(element(*)*)*"> <!-- Tokenise a formula, recursively wrt variables --> <xsl:param name="formula" as="xs:string" required="yes"/> <xsl:sequence select=" let $tokens := analyze-string($formula,$pat)/xf:match/xf:group return if ($tokens[@nr=(7,8,9)]) then let $n := count($tokens), $vars := for $i in (1 to $n) return let $t := $tokens[$i], $l := $tokens[$i - 1], $r := $tokens[$i + 1] return if ($t/@nr=9 and not($l[@nr=10 and .=(':','!')]) and not($r[@nr=10 and .=':'])) then string($t) else (), $defns := for $var in $vars return e:lookup($var), $recur := for $sub in $defns return if ($sub) then e:tokenise($sub) else (), $singles := for $i in (1 to $n) return let $t := $tokens[$i], $l := $tokens[$i - 1], $r := $tokens[$i + 1] return if ($t/@nr=8 and not($l[@nr=10 and .=(':','!')]) and not($r[@nr=10 and .=':'])) then e:single($t,false()) else (), $ranges := for $i in (1 to count($tokens)) return let $t := $tokens[$i] return if ($t[@nr=10 and .=':' and not($i gt 2 and $tokens[$i - 2][@nr=10 and .='!'])]) then let $l := $tokens[$i - 1], $r := $tokens[$i + 1] return e:range(e:single($l,false()), e:single($r,false())) else (), $externals := for $i in (1 to count($tokens)) return let $t := $tokens[$i] return if ($t/@nr=7 and $tokens[$i+1]='!') then let $ext := $t!='[0]', $ref := e:single($tokens[$i + 2], $ext), $res := if ((($i+3) le $n) and $tokens[$i + 3][@nr=10 and .=':']) then e:range($ref, e:single($tokens[$i+4], $ext)) else $ref return if ($ext) then e:external($t,$res) else $res else () return [($singles,for $a in $recur return $a?1), ($ranges,for $a in $recur return $a?2), ($externals,for $a in $recur return $a?3)] else ()"/> </xsl:function> <xsl:function name="e:single" as="element(*)"> <xsl:param name="group" as="element(xf:group)"/> <xsl:param name="external" as="xs:boolean"/> <xsl:variable name="val" select="if ($group/@nr=9) then e:lookup($group) else string($group)"/> <xsl:choose> <xsl:when test="count($val)>0 or not($external)"> <s><xsl:value-of select="$val"/></s> </xsl:when> <xsl:otherwise> <v><xsl:value-of select="$group"/></v> </xsl:otherwise> </xsl:choose> </xsl:function> <xsl:function name="e:range" as="element(e:r)"> <xsl:param name="l" as="element(e:s)" required="yes"/> <xsl:param name="r" as="element(e:s)" required="yes"/> <r><xsl:copy-of select="$l"/><xsl:copy-of select="$r"/></r> </xsl:function> <xsl:function name="e:external" as="element(e:e)"> <xsl:param name="source" as="element(xf:group)" required="yes"/> <xsl:param name="ref" as="element(*)" required="yes"/> <e s="{$source}"><xsl:sequence select="$ref"/></e> </xsl:function> <xsl:template match="/"> <refs sheetName="{$sheet-name}"><xsl:apply-templates select="//s:c"/></refs> </xsl:template> <xsl:template match="s:c[s:f]"> <xsl:variable name="tokens" select="e:tokenise(s:f/.)"/> <xsl:if test="@r='xxx'"><xsl:message><xsl:value-of select="s:f"/>|<xsl:value-of select="(analyze-string(s:f/.,$pat)/xf:match/xf:group)[3]/@nr"/></xsl:message> </xsl:if> <xsl:if test="count($tokens)>0"> <xsl:variable name="singles" select="$tokens?1"/> <!-- Note that we don't bother to treat external ranges as ranges, since we're not going to try to detect cross-document refs --> <xsl:variable name="ranges" select="$tokens?2"/> <xsl:variable name="externals" select="$tokens?3"/> <!-- Lost distinct-values filter, not sure it's really possible... --> <ref c="{@r}"> <xsl:copy-of select="$singles"/> <xsl:copy-of select="$ranges"/> <xsl:copy-of select="$externals"/> </ref></xsl:if> </xsl:template> <xsl:template match="s:c"/> </xsl:stylesheet>