Mercurial > hg > ooxml
comparison tokenise.xsl @ 39:4c6a341e75da
big rework works on sample2, w/o refs processing
author | Henry S. Thompson <ht@markup.co.uk> |
---|---|
date | Wed, 26 Apr 2017 18:51:34 +0100 |
parents | 468a6cf8bf0b |
children | ac6d1ca099f7 |
comparison
equal
deleted
inserted
replaced
38:468a6cf8bf0b | 39:4c6a341e75da |
---|---|
3 <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"> | 3 <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"> |
4 <xsl:param name="sheet-number"/> | 4 <xsl:param name="sheet-number"/> |
5 <xsl:param name="xlDir"/> | 5 <xsl:param name="xlDir"/> |
6 | 6 |
7 <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> | 7 <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> |
8 <xsl:param name="pat" select="$pat1"/><!-- xsl:param for refinement debugging by passing in the pattern --> | 8 <xsl:variable name="pat2">("[^"]*")|(\{[^}]+})|(,)|([^=\-+*/();:,.$<>^!]+(?:\.[^=\-+*/();:,.$<>^!]+)*\()|([)])|(^=|\()|((?:'[^']+'!)|(?:[\[0-9A-Za-z_][^=\-+*/();:,.$<>^!]*!))|(\$?[A-Z]+\$?[0-9]+)|([a-zA-Z_\\][a-zA-Z0-9._]*)|(.)</xsl:variable> |
9 <xsl:param name="pat" select="$pat2"/><!-- xsl:param for refinement debugging by passing in the pattern --> | |
9 | 10 |
10 <xsl:variable name="workbook" select="document(concat($xlDir,'/workbook.xml'))/*"/> | 11 <xsl:variable name="workbook" select="document(concat($xlDir,'/workbook.xml'))/*"/> |
11 <xsl:variable name="sheet-name" select="$workbook/s:sheets/s:sheet[@sheetId=$sheet-number]/@name"/> | 12 <xsl:variable name="sheet-name" select="$workbook/s:sheets/s:sheet[@sheetId=$sheet-number]/@name"/> |
12 | 13 |
13 <xsl:function name="e:lookup" as="xs:string*"> | 14 <xsl:function name="e:lookup" as="xs:string*"> |
16 </xsl:function> | 17 </xsl:function> |
17 | 18 |
18 <xsl:function name="e:tokenise" as="element(*)*"> | 19 <xsl:function name="e:tokenise" as="element(*)*"> |
19 <!-- Tokenise a formula, recursively wrt variables | 20 <!-- Tokenise a formula, recursively wrt variables |
20 Output is composed of e:* as follows: | 21 Output is composed of e:* as follows: |
22 b: Boolean constant | |
21 c: A list (function parameter) separator | 23 c: A list (function parameter) separator |
22 e: An external (variable, cell or range) reference | 24 e: An external (variable, cell or range) reference |
23 f: A function name followed by an opening parenthesis | 25 f: A function name followed by an opening parenthesis |
24 l: The beginning of the formula or an opening paren | 26 l: The beginning of the formula or an opening paren |
25 m: A constant matrix | 27 m: A constant matrix |
32 --> | 34 --> |
33 <xsl:param name="formula" as="xs:string" required="yes"/> | 35 <xsl:param name="formula" as="xs:string" required="yes"/> |
34 <!-- The row and column number of the cell whence the formula came --> | 36 <!-- The row and column number of the cell whence the formula came --> |
35 <xsl:param name="row" required="yes" as="xs:integer"/> | 37 <xsl:param name="row" required="yes" as="xs:integer"/> |
36 <xsl:param name="col" required="yes" as="xs:integer"/> | 38 <xsl:param name="col" required="yes" as="xs:integer"/> |
39 <xsl:message>tok: <xsl:value-of select="$formula"/></xsl:message> | |
37 <xsl:sequence select=" | 40 <xsl:sequence select=" |
38 let $tokens := analyze-string($formula,$pat)/xf:match/xf:group | 41 let $tokens := analyze-string($formula,$pat)/xf:match/xf:group |
39 return e:tok1($tokens,count($tokens),1,$row,$col,())"/> | 42 return e:tok1($tokens,count($tokens),1,$row,$col,())"/> |
40 </xsl:function> | 43 </xsl:function> |
41 | 44 |
43 <xsl:param name="tokens" as="element(xf:group)*" required="yes"/> | 46 <xsl:param name="tokens" as="element(xf:group)*" required="yes"/> |
44 <xsl:param name="n" required="yes" as="xs:integer"/> | 47 <xsl:param name="n" required="yes" as="xs:integer"/> |
45 <xsl:param name="i" required="yes" as="xs:integer"/> | 48 <xsl:param name="i" required="yes" as="xs:integer"/> |
46 <xsl:param name="row" required="yes" as="xs:integer"/> | 49 <xsl:param name="row" required="yes" as="xs:integer"/> |
47 <xsl:param name="col" required="yes" as="xs:integer"/> | 50 <xsl:param name="col" required="yes" as="xs:integer"/> |
48 <xsl:param name="soFar" required="yes" as="element(*)*"/> | 51 <xsl:param name="soFar" as="element(*)*"/> |
52 <xsl:variable name="last" select="$soFar[count($soFar)]"></xsl:variable> | |
53 <xsl:message>tok1: <xsl:value-of select="$n"/>|<xsl:value-of select="$i"/>|<xsl:value-of select="if ($last instance of element()) then name($last) else 'bogus'"/>|<xsl:value-of select="string($last)"/></xsl:message> | |
49 <xsl:sequence select=" | 54 <xsl:sequence select=" |
50 if ($i gt $n) | 55 if ($i gt $n) |
51 then $soFar | 56 then $soFar |
52 else | 57 else |
53 let $next := e:expand($tokens,$i,true(),$row,$col), | 58 let $next := e:expand($tokens,$i,true(),$row,$col), |
60 <xsl:param name="tokens" required="yes" as="element(xf:group)*"/> | 65 <xsl:param name="tokens" required="yes" as="element(xf:group)*"/> |
61 <xsl:param name="i" required="yes" as="xs:integer"/> | 66 <xsl:param name="i" required="yes" as="xs:integer"/> |
62 <xsl:param name="local" required="yes" as="xs:boolean"/> | 67 <xsl:param name="local" required="yes" as="xs:boolean"/> |
63 <xsl:param name="row" required="yes" as="xs:integer"/> | 68 <xsl:param name="row" required="yes" as="xs:integer"/> |
64 <xsl:param name="col" required="yes" as="xs:integer"/> | 69 <xsl:param name="col" required="yes" as="xs:integer"/> |
70 <xsl:message>exp: <xsl:value-of select="$tokens[$i]/@nr"/>:<xsl:value-of select="$tokens[$i]"/>,<xsl:value-of select="$tokens[$i+1]"/></xsl:message> | |
65 <xsl:sequence select=" | 71 <xsl:sequence select=" |
66 let $t := $tokens[$i], | 72 let $t := $tokens[$i], |
67 $r := $tokens[$i + 1] return | 73 $r := $tokens[$i + 1] return |
68 if ($t/@nr=1) then e:exp1($i,'q',string($t)) | 74 if ($t/@nr=1) then e:exp1($i,'q',string($t)) |
69 else if ($t/@nr=2) then e:exp1($i,'m',string($t)) | 75 else if ($t/@nr=2) then e:exp1($i,'m',string($t)) |
70 else if ($t/@nr=3) then e:exp1($i,'c',',') | 76 else if ($t/@nr=3) then e:exp1($i,'c',',') |
71 else if ($t/@nr=4) then e:exp1($i,'f',string($t)) | 77 else if ($t/@nr=4) then e:exp1($i,'f',string($t)) |
72 else if ($t/@nr=5) then e:exp1($i,'p',')') | 78 else if ($t/@nr=5) then e:exp1($i,'p',')') |
73 else if ($t/@nr=6) then e:exp1($i,'l',string($t)) | 79 else if ($t/@nr=6) then e:exp1($i,'l',string($t)) |
74 else if ($t/@nr=7) | 80 else if ($t/@nr=7) |
75 then if (substring-before($t,'!')=('[0]',$sheet-name)) | 81 then let $xref := substring-before($t,'!') return |
82 if ($xref=('[0]',$sheet-name)) | |
76 then (: it's a local reference after all :) | 83 then (: it's a local reference after all :) |
77 e:expand($tokens,$i+1,true(),$row,$col) | 84 e:expand($tokens,$i+1,true(),$row,$col) |
78 else let $ext := e:expand($tokens,$i+1,false(),$row,$col) return | 85 else let $ext := e:expand($tokens,$i+1,false(),$row,$col) return |
79 [$ext?1,e:external($ext?2)] | 86 [$ext?1,e:external($xref,$ext?2)] |
80 else if ($t/@nr=10) then e:amalgamate($tokens,$i+1,string($t)) | 87 else if ($t/@nr=10) then e:amalgamate($tokens,$i+1,string($t)) |
81 else if ($r[@nr=10 and .=':']) | 88 else if ($r[@nr=10 and .=':']) |
82 then (: a range, takes priority :) | 89 then (: a range, takes priority :) |
83 [$i+2,e:range($tokens,$i,$local,$row,$col)] | 90 [$i+3,e:range($tokens,$i,$local,$row,$col)] |
84 else if ($t/@nr=8) then [$i+1,e:single(string($t),$row,$col)] | 91 else if ($t/@nr=8) then [$i+1,e:single(string($t),$row,$col)] |
85 else if ($t/@nr=9) | 92 else if ($t/@nr=9) |
86 then if ($local) | 93 then if (matches($t,'^(true|false)$','i')) |
94 then e:exp1($i,upper-case($t),'b') | |
95 else (: a variable name, I think :) if ($local) | |
87 then let $sub := e:tokenise(e:lookup(string($t)),$row,$col) return | 96 then let $sub := e:tokenise(e:lookup(string($t)),$row,$col) return |
88 [$i+1,$sub] | 97 [$i+1,$sub] |
89 else (: can't expand :) e:exp1($i,'v',string($t)) | 98 else (: can't expand :) e:exp1($i,'v',string($t)) |
90 else (: shouldn't ever get here :) ()"/> | 99 else (: shouldn't ever get here :) ()"/> |
91 </xsl:function> | 100 </xsl:function> |
92 | 101 |
93 <xsl:function name="e:amalgamate" as="array(*)"> | 102 <xsl:function name="e:amalgamate" as="array(*)"> |
94 <xsl:param name="tokens" as="element(xf:group)*"/> | 103 <xsl:param name="tokens" as="element(xf:group)*"/> |
95 <xsl:param name="i" as="xs:integer"/> | 104 <xsl:param name="i" as="xs:integer"/> |
96 <xsl:param name="soFar" as="xs:string"/> | 105 <xsl:param name="soFar" as="xs:string"/> |
97 <xsl:sequence select="if ($tokens[i]/@nr=10) | 106 <xsl:choose> |
98 then e:amalgamate($tokens,$i+1,concat($soFar, | 107 <xsl:when test="$tokens[i]/@nr=10"> |
99 string($tokens[$i]))) | 108 <xsl:sequence select="e:amalgamate($tokens,$i+1,concat($soFar, |
100 else [$i,$soFar]"/> | 109 string($tokens[$i])))"/> |
110 </xsl:when> | |
111 <xsl:otherwise> | |
112 <xsl:variable name="res"> | |
113 <x><xsl:value-of select="$soFar"/></x> | |
114 </xsl:variable> | |
115 <xsl:message>amal: <xsl:value-of select="$res/."/></xsl:message> | |
116 <xsl:sequence select="[$i,$res/*]"/> | |
117 </xsl:otherwise> | |
118 </xsl:choose> | |
119 | |
101 </xsl:function> | 120 </xsl:function> |
102 | 121 |
103 <xsl:function name="e:exp1" as="array(*)"> | 122 <xsl:function name="e:exp1" as="array(*)"> |
104 <xsl:param name="i" as="xs:integer"/> | 123 <xsl:param name="i" as="xs:integer"/> |
105 <xsl:param name="name" as="xs:string"/> | 124 <xsl:param name="name" as="xs:string"/> |
107 <xsl:variable name="elt"> | 126 <xsl:variable name="elt"> |
108 <xsl:element name="{$name}" namespace="http://markup.co.uk/excel"> | 127 <xsl:element name="{$name}" namespace="http://markup.co.uk/excel"> |
109 <xsl:value-of select="$val"/> | 128 <xsl:value-of select="$val"/> |
110 </xsl:element> | 129 </xsl:element> |
111 </xsl:variable> | 130 </xsl:variable> |
112 <xsl:sequence select="[$i+1,$elt]"/> | 131 <xsl:message>exp1: <xsl:value-of select="$name"/>|<xsl:value-of select="$val"/>|<xsl:value-of select="name($elt/*)"/></xsl:message> |
132 <xsl:sequence select="[$i+1,$elt/*]"/> | |
113 </xsl:function> | 133 </xsl:function> |
114 | 134 |
115 <xsl:function name="e:single" as="element(e:s)"> | 135 <xsl:function name="e:single" as="element(e:s)"> |
116 <!-- I'm _guessing_ that external doesn't matter, i.e. that you | 136 <!-- I'm _guessing_ that external doesn't matter, i.e. that you |
117 can copy an external relative ref and have it change --> | 137 can copy an external relative ref and have it change --> |
165 <xsl:param name="t" as="xs:integer"/> | 185 <xsl:param name="t" as="xs:integer"/> |
166 <xsl:param name="local" as="xs:boolean"/> | 186 <xsl:param name="local" as="xs:boolean"/> |
167 <xsl:param name="row" as="xs:integer"/> | 187 <xsl:param name="row" as="xs:integer"/> |
168 <xsl:param name="col" as="xs:integer"/> | 188 <xsl:param name="col" as="xs:integer"/> |
169 <xsl:param name="toks" as="element(*)*"/> | 189 <xsl:param name="toks" as="element(*)*"/> |
170 <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> | 190 <xsl:message>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> |
171 <u r="{concat(e:n2a($col),$row)}" s="{$s}" t="{$t}" local="{$local}"> | 191 <u r="{concat(e:n2a($col),$row)}" s="{$s}" t="{$t}" local="{$local}"> |
172 <xsl:value-of select="string-join($toks,',')"/> | 192 <xsl:value-of select="string-join($toks,',')"/> |
173 </u> | 193 </u> |
174 </xsl:function> | 194 </xsl:function> |
175 | 195 |
176 <xsl:function name="e:external" as="element(e:e)"> | 196 <xsl:function name="e:external" as="element(e:e)"> |
197 <xsl:param name="xref" as="xs:string" required="yes"/> | |
177 <xsl:param name="ref" as="element(*)" required="yes"/> | 198 <xsl:param name="ref" as="element(*)" required="yes"/> |
178 <e><xsl:sequence select="$ref"/></e> | 199 <e x="{$xref}"><xsl:sequence select="$ref"/></e> |
179 </xsl:function> | 200 </xsl:function> |
180 </xsl:stylesheet> | 201 </xsl:stylesheet> |