Mercurial > hg > ooxml
changeset 38:468a6cf8bf0b
big change wrt formulae compiles, crashes
author | Henry S. Thompson <ht@markup.co.uk> |
---|---|
date | Tue, 25 Apr 2017 22:17:12 +0100 |
parents | ac3cd8de7a10 |
children | 4c6a341e75da |
files | rect.xsl refs.xsl tokenise.xsl |
diffstat | 3 files changed, 96 insertions(+), 58 deletions(-) [+] |
line wrap: on
line diff
--- a/rect.xsl Tue Apr 25 18:30:04 2017 +0100 +++ b/rect.xsl Tue Apr 25 22:17:12 2017 +0100 @@ -5,6 +5,7 @@ <xsl:include href="a2n.xsl"/> <xsl:include href="n2a.xsl"/> + <xsl:include href="tokenise.xsl"/> <xsl:variable name="refs" select="collection()[2]/*"/> @@ -40,6 +41,10 @@ <t> <xsl:if test="$c/@e:class"><xsl:attribute name="c"><xsl:value-of select="substring($c/@e:class,1,1)"/></xsl:attribute></xsl:if> <xsl:if test="$c/@e:code"><xsl:attribute name="l"><xsl:value-of select="$c/@e:code"/></xsl:attribute></xsl:if> + <xsl:if test="$c/s:f"> + <s:f> + <xsl:copy-of select="e:tokenise($c/s:f,$row,$col)"/> + </s:f></xsl:if> <xsl:value-of select="substring($c/@e:type,1,1)"/> </t> </xsl:if>
--- a/refs.xsl Tue Apr 25 18:30:04 2017 +0100 +++ b/refs.xsl Tue Apr 25 22:17:12 2017 +0100 @@ -1,28 +1,19 @@ <?xml version='1.0'?> <!DOCTYPE xsl:stylesheet 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:include href="a2n.xsl"/> + + <xsl:param name="sheet-name"/> <xsl:template match="/"> <refs sheetName="{$sheet-name}"><xsl:apply-templates select="//s:c"/></refs> </xsl:template> - <xsl:template match="s:c[s:f]"> + <xsl:template match="e:c[e:f]"> <xsl:variable name="cr" select="e:cr(@r,0,0)"/> - <xsl:variable name="tokens" select="e:tokenise(s:f/.,$cr/e:r[1],$cr/e:r[2])"/> - <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 test="@r='xxx'"><xsl:message><xsl:value-of select="count(e:f/*)"/>|</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"/>
--- a/tokenise.xsl Tue Apr 25 18:30:04 2017 +0100 +++ b/tokenise.xsl Tue Apr 25 22:17:12 2017 +0100 @@ -3,8 +3,6 @@ <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:include href="a2n.xsl"/> <xsl:variable name="pat1">("[^"]*")|(\{[^}]+})|(,)|([^=\-+*/();:,.$<>^!]+(?:\.[^=\-+*/();:,.$<>^!]+)*\()|([)])|(^=|\()|((?:(?:'[^']+')|(?:\[[0-9]+\][^!]*)|(?:[a-zA-Z_][a-zA-Z0-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 --> @@ -14,12 +12,7 @@ <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:value-of select="string($workbook/s:definedNames/s:definedName[@name=$name])"/> </xsl:function> <xsl:function name="e:tokenise" as="element(*)*"> @@ -32,15 +25,15 @@ m: A constant matrix p: A close-paren q: A text (delimited by double quotes) - r: A range reference + r: A range reference (two children, either e or s or u (unsupported)) s: A single-cell reference v: A variable name [should only occur inside e] x: Amalgamated single characters not matched by anything else --> <xsl:param name="formula" as="xs:string" required="yes"/> <!-- The row and column number of the cell whence the formula came --> - <xsl:param name="row" required="yes" as="xs:int"/> - <xsl:param name="col" required="yes" as="xs:int"/> + <xsl:param name="row" required="yes" as="xs:integer"/> + <xsl:param name="col" required="yes" as="xs:integer"/> <xsl:sequence select=" let $tokens := analyze-string($formula,$pat)/xf:match/xf:group return e:tok1($tokens,count($tokens),1,$row,$col,())"/> @@ -48,10 +41,10 @@ <xsl:function name="e:tok1" as="element(*)*"> <xsl:param name="tokens" as="element(xf:group)*" required="yes"/> - <xsl:param name="n" required="yes" as="xs:int"/> - <xsl:param name="i" required="yes" as="xs:int"/> - <xsl:param name="row" required="yes" as="xs:int"/> - <xsl:param name="col" required="yes" as="xs:int"/> + <xsl:param name="n" required="yes" as="xs:integer"/> + <xsl:param name="i" required="yes" as="xs:integer"/> + <xsl:param name="row" required="yes" as="xs:integer"/> + <xsl:param name="col" required="yes" as="xs:integer"/> <xsl:param name="soFar" required="yes" as="element(*)*"/> <xsl:sequence select=" if ($i gt $n) @@ -63,12 +56,12 @@ e:tok1($tokens,$n,$j,$row,$col,($soFar,$res))"/> </xsl:function> - <xsl:function name="e:expand" as="element(*)*"> + <xsl:function name="e:expand" as="array(*)"> <xsl:param name="tokens" required="yes" as="element(xf:group)*"/> - <xsl:param name="i" required="yes" as="xs:int"/> + <xsl:param name="i" required="yes" as="xs:integer"/> <xsl:param name="local" required="yes" as="xs:boolean"/> - <xsl:param name="row" required="yes" as="xs:int"/> - <xsl:param name="col" required="yes" as="xs:int"/> + <xsl:param name="row" required="yes" as="xs:integer"/> + <xsl:param name="col" required="yes" as="xs:integer"/> <xsl:sequence select=" let $t := $tokens[$i], $r := $tokens[$i + 1] return @@ -87,16 +80,28 @@ else if ($t/@nr=10) then e:amalgamate($tokens,$i+1,string($t)) else if ($r[@nr=10 and .=':']) then (: a range, takes priority :) - e:range($tokens,$i,$ext,$row,$col) - else if ($t/@nr=8) then e:single($i,$ext,string($t)) + [$i+2,e:range($tokens,$i,$local,$row,$col)] + else if ($t/@nr=8) then [$i+1,e:single(string($t),$row,$col)] else if ($t/@nr=9) - then if ($ext) then (: can't expand :) e:exp1($i,'v',string($t)) - else e:tokenise(e:lookup(string($t)),$row,$col) - else (-- shouldn't ever get here --) ()"/> + then if ($local) + then let $sub := e:tokenise(e:lookup(string($t)),$row,$col) return + [$i+1,$sub] + else (: can't expand :) e:exp1($i,'v',string($t)) + else (: shouldn't ever get here :) ()"/> + </xsl:function> + + <xsl:function name="e:amalgamate" as="array(*)"> + <xsl:param name="tokens" as="element(xf:group)*"/> + <xsl:param name="i" as="xs:integer"/> + <xsl:param name="soFar" as="xs:string"/> + <xsl:sequence select="if ($tokens[i]/@nr=10) + then e:amalgamate($tokens,$i+1,concat($soFar, + string($tokens[$i]))) + else [$i,$soFar]"/> </xsl:function> <xsl:function name="e:exp1" as="array(*)"> - <xsl:param name="i" as="xs:int"/> + <xsl:param name="i" as="xs:integer"/> <xsl:param name="name" as="xs:string"/> <xsl:param name="val" as="xs:string"/> <xsl:variable name="elt"> @@ -107,32 +112,69 @@ <xsl:sequence select="[$i+1,$elt]"/> </xsl:function> - <xsl:function name="e:single" as="element(*)"> - <xsl:param name="group" as="element(xf:group)"/> + <xsl:function name="e:single" as="element(e:s)"> + <!-- I'm _guessing_ that external doesn't matter, i.e. that you + can copy an external relative ref and have it change --> + <xsl:param name="val" as="xs:string"/> <xsl:param name="row" as="xs:integer"/> <xsl:param name="col" as="xs:integer"/> - <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)"> - <xsl:sequence select="e:cr($val,$row,$col)"/> - </xsl:when> - <xsl:otherwise> - <v><xsl:value-of select="$group"/></v> - </xsl:otherwise> - </xsl:choose> + <xsl:sequence select="e:cr($val,$row,$col)"/> </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:param name="tokens" as="element(xf:group)*"/> + <xsl:param name="i" as="xs:integer"/> + <xsl:param name="local" as="xs:boolean"/> + <xsl:param name="row" as="xs:integer"/> + <xsl:param name="col" as="xs:integer"/> + <xsl:variable name="l" select="$tokens[$i]"/> + <xsl:variable name="r" select="$tokens[$i+2]"/> + <xsl:variable name="lv" select="e:rPart($l,$local,$row,$col)"/> + <xsl:variable name="rv" select="e:rPart($r,$local,$row,$col)"/> + <r> + <xsl:copy-of select="($lv,$rv)"/> + </r> + </xsl:function> + + <xsl:function name="e:rPart" as="element(*)"> + <xsl:param name="g" as="element(xf:group)"/> + <xsl:param name="local" as="xs:boolean"/> + <xsl:param name="row" as="xs:integer"/> + <xsl:param name="col" as="xs:integer"/> + <xsl:sequence select=" + if ($g/@nr=8) then e:single(string($g),$row,$col) + else if ($g/@nr=9) + then if ($local) + then let $tokens := e:tokenise(e:lookup(string($g)), + $row,$col) return + if (count($tokens)=1 and + $tokens[local-name()='s' or + (local-name()='e' and $tokens/e:s)]) + then $tokens + else e:badRP(string($g),$g/@nr,$local,$row,$col,$tokens) + else e:var(string($g)) + else e:badRP(string($g),$g/@nr,$local,$row,$col,())"/> + </xsl:function> + + <xsl:function name="e:var" as="element(e:v)"> + <xsl:param name="name" as="xs:string"/> + <v><xsl:value-of select="$name"/></v> + </xsl:function> + <xsl:function name="e:badRP" as="element(e:u)"> + <xsl:param name="s" as="xs:string"/> + <xsl:param name="t" as="xs:integer"/> + <xsl:param name="local" as="xs:boolean"/> + <xsl:param name="row" as="xs:integer"/> + <xsl:param name="col" as="xs:integer"/> + <xsl:param name="toks" as="element(*)*"/> + <xsl:message terminate="yes">Bad range part in <xsl:value-of select="concat(e:n2a($col),$row)"/>: <xsl:value-of select="$s"/> of type <xsl:value-of select="$t"/> (<xsl:value-of select="if ($local) then 'local' else 'external'"/>: (<xsl:value-of select="string-join($toks,',')"/>)</xsl:message> + <u r="{concat(e:n2a($col),$row)}" s="{$s}" t="{$t}" local="{$local}"> + <xsl:value-of select="string-join($toks,',')"/> + </u> </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> + <e><xsl:sequence select="$ref"/></e> </xsl:function> </xsl:stylesheet>