#
# ooxml ECMA-376 Office Open XML File Formats
# https://www.ecma-international.org/publications/standards/Ecma-376.htm
#
# $Id: ooxml.tcl,v 1.28 2018/06/20 15:01:38 alex Exp $
#
# Copyright (C) 2018 Alexander Schoepe, Bochum, DE, <schoepe@users.sourceforge.net>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. Neither the name of the project nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# INDEX and ID are zero based
#
#
# BORDERLINESTYLE
# dashDot | dashDotDot | dashed | dotted | double | hair | medium |
# mediumDashDot | mediumDashDotDot | mediumDashDotDot | none | slantDashDot | thick | thin
#
# COLOR
# 0-65
# Aqua | Black | Blue | BlueRomance | Canary | CarnationPink | Citrus | Cream | DarkSlateBlue | DeepSkyBlue |
# Eucalyptus | Fuchsia | Gray | Green | Karaka | LavenderBlue | LightCoral | LightCyan | LightSkyBlue | Lime |
# Lipstick | Maroon | Mauve | MediumTurquoise | Myrtle | Navy | NavyBlue | NightRider | Nobel | Olive |
# OrangePeel | PeachOrange | Portage | PrussianBlue | Purple | Red | RoyalBlue | SaddleBrown | SafetyOrange |
# Scampi | Silver | TangerineYellow | Teal | White | Yellow |
# SystemBackground | SystemForeground
# RGB
# ARGB
#
# DEGREE
# 0-360
#
# DIAGONALDIRECTION
# up | down
#
# HORIZONTAL
# left | center | right
#
# PATTERNTYPE
# darkDown | darkGray | darkGrid | darkHorizontal | darkTrellis | darkUp | darkVertical |
# gray0625 | gray125 | lightDown | lightGray |
# lightGrid | lightHorizontal | lightTrellis | lightUp | lightVertical | mediumGray | none | solid
#
# VERTICAL
# top | center | bottom
#
#
# ::ooxml::Default name value
# name = path
#
#
# ::ooxml::RowColumnToString rowcol
# return name
#
#
# ::ooxml::StringToRowColumn name
# return rowcol
#
#
# ::ooxml::CalcColumnWidth numberOfCharacters {maximumDigitWidth 7} {pixelPadding 5}
# return width
#
#
# ::ooxml::xl_sheets file
# return sheetInformation
#
#
# ::ooxml::xl_read file
# -valuesonly -keylist -sheets PATTERN -sheetnames PATTERN -datefmt FORMAT
# return workbookData
#
#
# ::ooxml::xl_write
#
# constructor args
# -creator CREATOR
# return class
#
# method numberformat args
# -format FORMAT -general -date -time -datetime -iso8601 -number -decimal -red -separator -fraction -scientific -percent -text -string
# return NUMFMTID
#
# method defaultdatestyle STYLEID
#
# method font args
# -list -name NAME -family FAMILY -size SIZE -color COLOR -scheme SCHEME -bold -italic -underline -color COLOR
# return FONTID
#
# method fill args
# -list -patterntype PATTERNTYPE -fgcolor COLOR -bgcolor COLOR
# return FILLID
#
# method border args
# -list -leftstyle BORDERLINESTYLE -leftcolor COLOR -rightstyle BORDERLINESTYLE -rightcolor COLOR -topstyle BORDERLINESTYLE -topcolor COLOR
# -bottomstyle BORDERLINESTYLE -bottomcolor COLOR -diagonalstyle BORDERLINESTYLE -diagonalcolor COLOR -diagonaldirection DIAGONALDIRECTION
# return BORDERID
#
# method style args
# -list -numfmt NUMFMTID -font FONTID -fill FILLID -border BORDERID -xf XFID -horizontal HORIZONTAL -vertical VERTICAL -rotate DEGREE
# return STYLEID
#
# method worksheet name
# return SHEETID
#
# method column sheet args
# -index INDEX -to INDEX -width WIDTH -style STYLEID -bestfit -customwidth -string -nozero -calcfit
# autoincrement of column if INDEX not applied
# return column
#
# method row sheet args
# -index INDEX -height HEIGHT
# autoincrement of row if INDEX not applied
# return row
#
# method cell sheet {data {}} args
# -index INDEX -style STYLEID -formula FORMULA -string -nozero -globalstyle -height HEIGHT
# autoincrement of column if INDEX not applied
# return row,column
#
# method autofilter sheet indexFrom indexTo
#
# method freeze sheet index
#
# method presetstyles
#
# method presetsheets
#
# method write filename
#
#
# ::ooxml::tablelist_to_xl lb args
# -callback CALLBACK -path PATH -file FILENAME -creator CREATOR -name NAME -rootonly -addtimestamp
# Callback arguments
# spreadsheet sheet maxcol column title width align sortmode hide
#
package require Tcl 8.6
package require vfs::zip
package require tdom 0.9.0-
package require msgcat
namespace eval ::ooxml {
namespace export xl_sheets xl_read xl_write
variable defaults
variable predefNumFmts
variable predefColors
variable predefColorsName
variable predefColorsARBG
variable predefBorderLineStyles
variable predefPatternType
set defaults(path) {.}
set defaults(numFmts,start) 166
set defaults(cols,width) 10.83203125
# predefined formats
array set predefNumFmts {
0 {dt 0 fmt {General}}
1 {dt 0 fmt {0}}
2 {dt 0 fmt {0.00}}
3 {dt 0 fmt {#,##0}}
4 {dt 0 fmt {#,##0.00}}
9 {dt 0 fmt {0%}}
10 {dt 0 fmt {0.00%}}
11 {dt 0 fmt {0.00E+00}}
12 {dt 0 fmt {#\ ?/?}}
13 {dt 0 fmt {#\ ??/??}}
14 {dt 1 fmt {mm-dd-yy}}
15 {dt 1 fmt {d-mmm-yy}}
16 {dt 1 fmt {d-mmm}}
17 {dt 1 fmt {mmm-yy}}
18 {dt 1 fmt {h:mm\ AM/PM}}
19 {dt 1 fmt {h:mm:ss\ AM/PM}}
20 {dt 1 fmt {h:mm}}
21 {dt 1 fmt {h:mm:ss}}
22 {dt 1 fmt {m/d/yy h:mm}}
37 {dt 0 fmt {#,##0\ ;(#,##0)}}
38 {dt 0 fmt {#,##0\ ;[Red](#,##0)}}
39 {dt 0 fmt {#,##0.00;(#,##0.00)}}
40 {dt 0 fmt {#,##0.00;[Red](#,##0.00)}}
45 {dt 1 fmt {mm:ss}}
46 {dt 1 fmt {[h]:mm:ss}}
47 {dt 1 fmt {mmss.0}}
48 {dt 0 fmt {##0.0E+0}}
49 {dt 0 fmt {@}}
}
array set predefColors {
0 {argb 00000000 name Black}
1 {argb 00FFFFFF name White}
2 {argb 00FF0000 name Red}
3 {argb 0000FF00 name Lime}
4 {argb 000000FF name Blue}
5 {argb 00FFFF00 name Yellow}
6 {argb 00FF00FF name Fuchsia}
7 {argb 0000FFFF name Aqua}
8 {argb 00000000 name Black}
9 {argb 00FFFFFF name White}
10 {argb 00FF0000 name Red}
11 {argb 0000FF00 name Lime}
12 {argb 000000FF name Blue}
13 {argb 00FFFF00 name Yellow}
14 {argb 00FF00FF name Fuchsia}
15 {argb 0000FFFF name Aqua}
16 {argb 00800000 name Maroon}
17 {argb 00008000 name Green}
18 {argb 00000080 name Navy}
19 {argb 00808000 name Olive}
20 {argb 00800080 name Purple}
21 {argb 00008080 name Teal}
22 {argb 00C0C0C0 name Silver}
23 {argb 00808080 name Gray}
24 {argb 009999FF name Portage}
25 {argb 00993366 name Lipstick}
26 {argb 00FFFFCC name Cream}
27 {argb 00CCFFFF name LightCyan}
28 {argb 00660066 name Purple}
29 {argb 00FF8080 name LightCoral}
30 {argb 000066CC name NavyBlue}
31 {argb 00CCCCFF name LavenderBlue}
32 {argb 00000080 name Navy}
33 {argb 00FF00FF name Fuchsia}
34 {argb 00FFFF00 name Yellow}
35 {argb 0000FFFF name Aqua}
36 {argb 00800080 name Purple}
37 {argb 00800000 name Maroon}
38 {argb 00008080 name Teal}
39 {argb 000000FF name Blue}
40 {argb 0000CCFF name DeepSkyBlue}
41 {argb 00CCFFFF name LightCyan}
42 {argb 00CCFFCC name BlueRomance}
43 {argb 00FFFF99 name Canary}
44 {argb 0099CCFF name LightSkyBlue}
45 {argb 00FF99CC name CarnationPink}
46 {argb 00CC99FF name Mauve}
47 {argb 00FFCC99 name PeachOrange}
48 {argb 003366FF name RoyalBlue}
49 {argb 0033CCCC name MediumTurquoise}
50 {argb 0099CC00 name Citrus}
51 {argb 00FFCC00 name TangerineYellow}
52 {argb 00FF9900 name OrangePeel}
53 {argb 00FF6600 name SafetyOrange}
54 {argb 00666699 name Scampi}
55 {argb 00969696 name Nobel}
56 {argb 00003366 name PrussianBlue}
57 {argb 00339966 name Eucalyptus}
58 {argb 00003300 name Myrtle}
59 {argb 00333300 name Karaka}
60 {argb 00993300 name SaddleBrown}
61 {argb 00993366 name Lipstick}
62 {argb 00333399 name DarkSlateBlue}
63 {argb 00333333 name NightRider}
64 {argb {} name SystemForeground}
65 {argb {} name SystemBackground}
}
set predefColorsName {}
set predefColorsARBG {}
foreach idx [lsort -integer [array names predefColors]] {
lappend predefColorsName [dict get $predefColors($idx) name]
lappend predefColorsARBG [dict get $predefColors($idx) argb]
}
set predefPatternType {
darkDown
darkGray
darkGrid
darkHorizontal
darkTrellis
darkUp
darkVertical
gray0625
gray125
lightDown
lightGray
lightGrid
lightHorizontal
lightTrellis
lightUp
lightVertical
mediumGray
none
solid
}
set predefBorderLineStyles {
dashDot
dashDotDot
dashed
dotted
double
hair
medium
mediumDashDot
mediumDashDotDot
mediumDashDotDot
none
slantDashDot
thick
thin
}
# ar - Arabic - العربية
msgcat::mcset ar LANGUAGE \u0627\u0644\u0639\u0631\u0628\u064a\u0629
msgcat::mcset ar Book \u0627\u0644\u0643\u062a\u0627\u0628
msgcat::mcset ar Worksheets "\u0623\u0648\u0631\u0627\u0642 \u0627\u0644\u0639\u0645\u0644"
msgcat::mcset ar Sheet \u0627\u0644\u0648\u0631\u0642\u0629
# cs - Czech - čeština, český jazyk
msgcat::mcset cs LANGUAGE \u010de\u0161tina
msgcat::mcset cs Book Ses\u030cit
msgcat::mcset cs Worksheets Listy
msgcat::mcset cs Sheet List
# da - Danish - dansk
msgcat::mcset da LANGUAGE dansk
msgcat::mcset da Book Mappe
msgcat::mcset da Worksheets Regneark
msgcat::mcset da Sheet Ark
# de - German - Deutsch
msgcat::mcset de LANGUAGE Deutsch
msgcat::mcset de Book Mappe
msgcat::mcset de Worksheets Arbeitsbl\u00e4tter
msgcat::mcset de Sheet Blatt
msgcat::mcset de {Tablelist does not exists!} {Die Tablelist existiert nicht!}
msgcat::mcset de {No file selected!} "Keine Datei ausgew\u00e4hlt!"
# el - Greek - ελληνικά
msgcat::mcset el LANGUAGE \u03b5\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac
msgcat::mcset el Book \u0392\u03b9\u03b2\u03bb\u03b9\u0301\u03bf
msgcat::mcset el Worksheets "\u03a6\u03cd\u03bb\u03bb\u03b1 \u03b5\u03c1\u03b3\u03b1\u03c3\u03af\u03b1\u03c2"
msgcat::mcset el Sheet \u03a6\u03cd\u03bb\u03bb\u03bf
# en - English - English
msgcat::mcset en LANGUAGE English
msgcat::mcset en Book Book
msgcat::mcset en Worksheets Worksheets
msgcat::mcset en Sheet Sheet
msgcat::mcset en {Tablelist does not exists!} {Tablelist does not exists!}
msgcat::mcset en {No file selected!} {No file selected!}
# es - Spanish - Español
msgcat::mcset es LANGUAGE Espa\u00f1ol
msgcat::mcset es Book Libro
msgcat::mcset es Worksheets "Hojas de c\u00e1lculo"
msgcat::mcset es Sheet Hoja
msgcat::mcset es {Tablelist does not exists!} "\u00a1Tablelist no existe!"
msgcat::mcset es {No file selected!} "\u00a1Ning\u00fan archivo seleccionado!"
# fi - Finnish - suomi, suomen kieli
msgcat::mcset fi LANGUAGE suomi
msgcat::mcset fi Book Tyo\u0308kirja
msgcat::mcset fi Worksheets Laskentataulukot
msgcat::mcset fi Sheet Taulukko
# fr - French - français, langue française
msgcat::mcset fr LANGUAGE fran\u00e7ais
msgcat::mcset fr Book Classeur
msgcat::mcset fr Worksheets "Feuilles de calcul"
msgcat::mcset fr Sheet Feuil
msgcat::mcset fr {Tablelist does not exists!} {Tablelist n'existe pas!}
msgcat::mcset fr {No file selected!} "Aucun fichier s\u00e9lectionn\u00e9!"
# he - Hebrew - עברית
msgcat::mcset he LANGUAGE \u05e2\u05d1\u05e8\u05d9\u05ea
msgcat::mcset he Book \u05d7\u05d5\u05d1\u05e8\u05ea
msgcat::mcset he Worksheets "\u05d2\u05dc\u05d9\u05d5\u05e0\u05d5\u05ea \u05e2\u05d1\u05d5\u05d3\u05d4"
msgcat::mcset he Sheet \u05d2\u05d9\u05dc\u05d9\u05d5\u05df
# hu - Hungarian - magyar
msgcat::mcset hu LANGUAGE magyar
msgcat::mcset hu Book Munkafu\u0308zet
msgcat::mcset hu Worksheets Munkalapok
msgcat::mcset hu Sheet Munkalap
# it - italian - Italiano
msgcat::mcset it LANGUAGE Italiano
msgcat::mcset it Book Cartel
msgcat::mcset it Worksheets "Fogli di lavoro"
msgcat::mcset it Sheet Foglio
msgcat::mcset it {Tablelist does not exists!} {Tablelist non esiste!}
msgcat::mcset it {No file selected!} {Nessun file selezionato!}
# ja - Japanese - 日本語 (にほんご)
msgcat::mcset ja LANGUAGE "\u65e5\u672c\u8a9e (\u306b\u307b\u3093\u3054)"
msgcat::mcset ja Book Book
msgcat::mcset ja Worksheets \u30ef\u30fc\u30af\u30b7\u30fc\u30c8
msgcat::mcset ja Sheet Sheet
# ko - Korean - 한국어
msgcat::mcset ko LANGUAGE "\ud55c\uad6d\uc5b4"
msgcat::mcset ko Book "\u1110\u1169\u11bc\u1112\u1161\u11b8 \u1106\u116e\u11ab\u1109\u1165"
msgcat::mcset ko Worksheets \uc6cc\ud06c\uc2dc\ud2b8
msgcat::mcset ko Sheet \uc2dc\ud2b8
# nl - Dutch, Flemish - Nederlands, Vlaams
msgcat::mcset nl LANGUAGE Nederlands
msgcat::mcset nl Book Map
msgcat::mcset nl Worksheets Werkbladen
msgcat::mcset nl Sheet Blad
msgcat::mcset nl {Tablelist does not exists!} {Tablelist bestaat niet!}
msgcat::mcset nl {No file selected!} {Geen bestand geselecteerd!}
# no - Norwegian - Norsk
msgcat::mcset no LANGUAGE Norsk
msgcat::mcset no Book Bok
msgcat::mcset no Worksheets Regneark
msgcat::mcset no Sheet Ark
# pl - Polish - język polski, polszczyzna
msgcat::mcset pl LANGUAGE polszczyzna
msgcat::mcset pl Book Skoroszyt
msgcat::mcset pl Worksheets Arkusze
msgcat::mcset pl Sheet Arkusz
# pt - Portuguese - Português
msgcat::mcset pt LANGUAGE Portugu\u00eas
msgcat::mcset pt Book Livro
msgcat::mcset pt Worksheets "Folhas de C\u00e1lculo"
msgcat::mcset pt Sheet Folha
# ru - Russian - русский
msgcat::mcset ru LANGUAGE \u0440\u0443\u0441\u0441\u043a\u0438\u0439
msgcat::mcset ru Book \u041a\u043d\u0438\u0433\u0430
msgcat::mcset ru Worksheets \u041b\u0438\u0441\u0442\u044b
msgcat::mcset ru Sheet \u041b\u0438\u0441\u0442
# sl - Slovenian - Slovenski Jezik, Slovenščina
msgcat::mcset sl LANGUAGE Sloven\u0161\u010dina
msgcat::mcset sl Book Zos\u030cit
msgcat::mcset sl Worksheets H\u00e1rky
msgcat::mcset sl Sheet H\u00e1rok
# sv - Swedish - Svenska
msgcat::mcset sv LANGUAGE Svenska
msgcat::mcset sv Book Bok
msgcat::mcset sv Worksheets Kalkylblad
msgcat::mcset sv Sheet Blad
# th - Thai - ไทย
msgcat::mcset th LANGUAGE \u0e44\u0e17\u0e22
msgcat::mcset th Book \u0e2a\u0e21\u0e38\u0e14\u0e07\u0e32\u0e19
msgcat::mcset th Worksheets \u0e40\u0e27\u0e34\u0e23\u0e4c\u0e01\u0e0a\u0e35\u0e15
msgcat::mcset th Sheet \u0e41\u0e1c\u0e48\u0e19\u0e07\u0e32\u0e19
# tr - Turkish - Türkçe
msgcat::mcset tr LANGUAGE T\u00fcrk\u00e7e
msgcat::mcset tr Book Kitap
msgcat::mcset tr Worksheets "\u00c7al\u0131\u015fma Sayfalar\u0131"
msgcat::mcset tr Sheet Sayfa
# zh - Chinese - 中文 (Zhōngwén), 汉语, 漢語
msgcat::mcset zh LANGUAGE \u4e2d\u6587
msgcat::mcset zh Book \u5de5\u4f5c\u7c3f
msgcat::mcset zh Worksheets \u5de5\u4f5c\u8868
msgcat::mcset zh Sheet \u5de5\u4f5c\u8868
}
proc ::ooxml::Default { name value } {
variable defaults
switch -- $name {
path {
set defaults($name) [string trim $value]
if {$value eq {}} {
set defaults($name) .
}
}
default {
}
}
}
proc ::ooxml::Getopt { *result declaration to_parse } {
if {${*result} ne {}} {
upvar 1 ${*result} result
}
set error 0
set errmsg {}
array set result {}
set optopts {}
set argcnt [llength $declaration]
for {set argc 0} {$argc < $argcnt} {incr argc} {
set opt [lindex $declaration $argc]
if {[lsearch -exact {. -} [string index $opt 0]] > -1} {
set error 1
lappend errmsg "option name can not start with '.' or '-'"
set result(-error) $error
set result(-errmsg) $errmsg
return $error
}
if {[regsub -- {\..*$} $opt {} name]} {
regsub -- (${name}) $opt {} opt
}
if {![regsub -- {\.arg\M} $opt {} opt]} {
dict set optopts $name arg 0
set result($name) 0
} else {
dict set optopts $name arg 1
incr argc
if {$argc < $argcnt} {
set result($name) [lindex $declaration $argc]
} else {
set result($name) {}
set error 1
lappend errmsg "declaration of '$name' missing default value"
set result(-error) $error
set result(-errmsg) $errmsg
return $error
}
}
}
set argcnt [llength $to_parse]
for {set argc 0} {$argc < $argcnt} {incr argc} {
set opt [lindex $to_parse $argc]
if {$opt eq {--}} {
set result(--) [lrange $to_parse ${argc}+1 end]
break
} elseif {[string index $opt 0] eq {-}} {
set opt [string range $opt 1 end]
if {[dict keys $optopts $opt] eq $opt || [llength [set opt [dict keys $optopts ${opt}*]]] == 1} {
if {[dict get $optopts $opt arg]} {
incr argc
if {$argc < $argcnt} {
set result($opt) [lindex $to_parse $argc]
} else {
set error 1
lappend errmsg "${opt}: missing argument"
}
} else {
set result($opt) 1
}
} else {
set error 1
lappend errmsg "[lindex $to_parse $argc]: unknown or ambiguous option"
}
} else {
set error 1
lappend errmsg "${opt}: syntax error"
}
}
if {![info exists result(--)]} {
set result(--) {}
}
set result(-error) $error
set result(-errmsg) $errmsg
return $error
}
proc ::ooxml::ScanDateTime { scan {iso8601 0} } {
set d 1
set m 1
set ml {}
set y 1970
set H 0
set M 0
set S 0
set F 0
if {[regexp {^(\d+)\.(\d+)\.(\d+)T?\s*(\d+)?:?(\d+)?:?(\d+)?\.?(\d+)?\s*([+-])?(\d+)?:?(\d+)?$} $scan all d m y H M S F x a b] ||
[regexp {^(\d+)-(\d+)-(\d+)T?\s*(\d+)?:?(\d+)?:?(\d+)?\.?(\d+)?\s*([+-])?(\d+)?:?(\d+)?$} $scan all y m d H M S F x a b] ||
[regexp {^(\d+)-(\w+)-(\d+)T?\s*(\d+)?:?(\d+)?:?(\d+)?\.?(\d+)?\s*([+-])?(\d+)?:?(\d+)?$} $scan all d ml y H M S F x a b] ||
[regexp {^(\d+)/(\d+)/(\d+)T?\s*(\d+)?:?(\d+)?:?(\d+)?\.?(\d+)?\s*([+-])?(\d+)?:?(\d+)?$} $scan all m d y H M S F x a b]} {
scan $y %u y
if {[string is integer -strict $y] && $y >= 0 && $y <= 2038} {
switch -- [string tolower $ml] {
jan -
ene -
gen -
tam {set m 1}
feb -
fev -
fév -
hel {set m 2}
mrz -
mar -
mär -
maa {set m 3}
apr -
avr -
abr -
huh {set m 4}
mai -
may -
mei -
mag -
maj -
tou {set m 5}
jun -
jui -
giu -
kes {set m 6}
jul -
jui -
lug -
hei {set m 7}
aug -
aou -
aoû -
ago -
elo {set m 8}
sep -
set -
syy {set m 9}
okt -
oct -
out -
ott -
lok {set m 10}
nov -
mar {set m 11}
dez -
dec -
déc -
dic -
des -
jou {set m 12}
default { set m [string trimleft $m 0] }
}
foreach name {y m d H M S F a b} {
upvar 0 $name var
set var [string trimleft $var 0]
if {![string is integer -strict $var]} {
set var 0
}
}
if {$y < 100} {
if {$y < 50} {
incr y 2000
} else {
incr y 1900
}
}
if {$y < 1900} {
return {}
}
set Y [format %04u $y]
set y [format %02u [expr {$y - int($y / 100) * 100}]]
set m [format %02u $m]
set d [format %02u $d]
set H [format %02u $H]
set M [format %02u $M]
set S [format %02u $S]
if {$iso8601} {
return [list ${Y}-${m}-${d}T${H}:${M}:${S}]
}
return [set ole [expr {[clock scan ${Y}${m}${d}T${H}${M}${S} -gmt 1] / 86400.0 + 25569}]]
}
}
return {}
}
proc ::ooxml::Zip { zipfile directory files } {
array set v { fd {} base {} toc {} }
# this code is a rewrite and extension of the zipper code found
# at http://equi4.com/critlib/ and http://wiki.tcl.tk/36689
# by Tom Krehbiel 2012 krehbiel.tom at gmail dot com
proc Initialize { *v file } {
upvar ${*v} v
set fd [open $file w]
set v(fd) $fd
set v(base) [tell $fd]
set v(toc) {}
fconfigure $fd -translation binary -encoding binary
}
proc Emit { *v s } {
upvar ${*v} v
puts -nonewline $v(fd) $s
}
proc DosTime { sec } {
set f [clock format $sec -format {%Y %m %d %H %M %S} -gmt 1]
regsub -all { 0(\d)} $f { \1} f
foreach {Y M D h m s} $f break
set date [expr {(($Y-1980)<<9) | ($M<<5) | $D}]
set time [expr {($h<<11) | ($m<<5) | ($s>>1)}]
return [list $date $time]
}
proc AddEntry { *v name contents {date {}} {force 0} } {
upvar ${*v} v
if {$date eq {}} {
set date [clock seconds]
}
lassign [DosTime $date] date time
set flag 0
set type 0 ;# stored
set fsize [string length $contents]
set csize $fsize
set fnlen [string length $name]
if {$force > 0 && $force != [string length $contents]} {
set csize $fsize
set fsize $force
set type 8 ;# if we're passing in compressed data, it's deflated
}
if {[catch {zlib crc32 $contents} crc]} {
set crc 0
} elseif {$type == 0} {
set cdata [zlib deflate $contents 9]
if {[string length $cdata] < [string length $contents]} {
set contents $cdata
set csize [string length $cdata]
set type 8 ;# deflate
}
}
lappend v(toc) "[binary format a2c6ssssiiiss4ii PK {1 2 20 0 20 0} $flag $type $time $date $crc $csize $fsize $fnlen {0 0 0 0} 128 [tell $v(fd)]]$name"
Emit v [binary format a2c4ssssiiiss PK {3 4 20 0} $flag $type $time $date $crc $csize $fsize $fnlen 0]
Emit v $name
Emit v $contents
}
proc AddDirectory { *v name {date {}} {force 0} } {
upvar ${*v} v
set name "${name}/"
if {$date eq {}} {
set date [clock seconds]
}
lassign [DosTime $date] date time
set flag 0
set type 0 ;# stored
set fsize 0
set csize 0
set fnlen [string length $name]
set crc 0
lappend v(toc) "[binary format a2c6ssssiiiss4ii PK {1 2 20 0 20 0} $flag $type $time $date $crc $csize $fsize $fnlen {0 0 0 0} 128 [tell $v(fd)]]$name"
Emit v [binary format a2c4ssssiiiss PK {3 4 20 0} $flag $type $time $date $crc $csize $fsize $fnlen 0]
Emit v $name
}
proc Finalize { *v } {
upvar ${*v} v
set pos [tell $v(fd)]
set ntoc [llength $v(toc)]
foreach x $v(toc) {
Emit v $x
}
set v(toc) {}
set len [expr {[tell $v(fd)] - $pos}]
incr pos -$v(base)
Emit v [binary format a2c2ssssiis PK {5 6} 0 0 $ntoc $ntoc $len $pos 0]
close $v(fd)
}
Initialize v $zipfile
foreach file $files {
regsub {^\./} $file {} to
set from [file join [file normalize $directory] $to]
if {[file isfile $from]} {
set fd [open $from r]
fconfigure $fd -translation binary -encoding binary
AddEntry v $to [read $fd] [file mtime $from]
close $fd
} elseif {[file isdir $from]} {
AddDirectory v $to [file mtime $from]
lappend dirs $file
}
}
Finalize v
}
proc ::ooxml::RowColumnToString { rowcol } {
proc Column { col } {
set name {}
while {$col >= 0} {
set char [binary format c [expr {($col % 26) + 65}]]
set name $char$name
set col [expr {$col / 26 -1}]
}
return $name
}
lassign [split $rowcol ,] row col
return [Column $col][incr row 1]
}
proc ::ooxml::StringToRowColumn { name } {
set row 0
set col 0
binary scan [string toupper $name] c* vals
foreach val $vals {
if {$val < 58} {
# 0-9, "0" = 48
set row [expr {$row * 10 + ($val-48)}]
} else {
# A-Z, "A" = 65 (-1 zero based shift)
set col [expr {$col * 26 + ($val-64)}]
}
}
return [incr row -1],[incr col -1]
}
proc ::ooxml::IndexToString { index } {
lassign [split $index ,] row col
if {[string is integer -strict $row] && [string is integer -strict $col] && $row > -1 && $col > -1} {
return [RowColumnToString $index]
} else {
lassign [split [StringToRowColumn $index] ,] row col
if {[string is integer -strict $row] && [string is integer -strict $col] && $row > -1 && $col > -1} {
return $index
}
}
return {}
}
proc ::ooxml::CalcColumnWidth { numberOfCharacters {maximumDigitWidth 7} {pixelPadding 5} } {
return [expr {int(($numberOfCharacters * $maximumDigitWidth + $pixelPadding + 0.0) / $maximumDigitWidth * 256.0) / 256.0}]
}
# Seite 3947
# <xsd:complexType name="CT_Color">
# <xsd:attribute name="auto" type="xsd:boolean" use="optional"/>
# <xsd:attribute name="indexed" type="xsd:unsignedInt" use="optional"/>
# <xsd:attribute name="rgb" type="ST_UnsignedIntHex" use="optional"/>
# <xsd:attribute name="theme" type="xsd:unsignedInt" use="optional"/>
# <xsd:attribute name="tint" type="xsd:double" use="optional" default="0.0"/>
# </xsd:complexType>
proc ::ooxml::Color { color } {
variable predefColors
variable predefColorsName
variable predefColorsARBG
if {[string trim $color] eq {}} {
return {}
} elseif {$color in {auto none}} {
return [list $color 1]
} elseif {[string is integer -strict $color] && $color >= 0 && $color <= 65} {
return [list indexed $color]
} elseif {[set idx [lsearch -exact -nocase [array names predefColors] $color]] && $idx > -1} {
return [list indexed $idx]
} elseif {[set idx [lsearch -exact -nocase $predefColorsName $color]] && $idx > -1} {
return [list indexed $idx]
}
if {[string is xdigit -strict $color]} {
if {[string length $color] == 6} {
set color 00$color
}
if {[set idx [lsearch -exact -nocase $predefColorsARBG $color]] && $idx > -1} {
return [list indexed $idx]
} else {
return [list rgb $color]
}
}
return {}
}
#
# ooxml::xl_sheets
#
proc ::ooxml::xl_sheets { file } {
set sheets {}
set mnt [vfs::zip::Mount $file xlsx]
set rels 0
if {![catch {open xlsx/xl/_rels/workbook.xml.rels r} fd]} {
fconfigure $fd -encoding utf-8
if {![catch {dom parse [read $fd]} rdoc]} {
set rels 1
set relsroot [$rdoc documentElement]
}
close $fd
}
if {![catch {open xlsx/xl/workbook.xml r} fd]} {
fconfigure $fd -encoding utf-8
if {![catch {dom parse [read $fd]} doc]} {
set root [$doc documentElement]
set idx -1
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:workbook/X:sheets/X:sheet}] {
if {[$node hasAttribute sheetId] && [$node hasAttribute name]} {
set sheetId [$node getAttribute sheetId]
set name [$node getAttribute name]
set rid [$node getAttribute r:id]
foreach node [$relsroot selectNodes -namespaces [list X [$relsroot namespaceURI]] [subst -nobackslashes -nocommands {/X:Relationships/X:Relationship[@Id="$rid"]}]] {
if {[$node hasAttribute Target]} {
lappend sheets [incr idx] [list sheetId $sheetId name $name rId $rid]
}
}
}
}
$doc delete
}
close $fd
}
if {$rels} {
$rdoc delete
}
vfs::zip::Unmount $mnt xlsx
return $sheets
}
#
# ooxml::xl_read
#
proc ::ooxml::xl_read { file args } {
variable predefNumFmts
array set cellXfs {}
array set numFmts [array get predefNumFmts]
array set sharedStrings {}
set sheets {}
if {[::ooxml::Getopt opts {valuesonly keylist sheets.arg {} sheetnames.arg {} datefmt.arg {%Y-%m-%d %H:%M:%S} as.arg array} $args]} {
error $opts(-errmsg)
}
if {[string trim $opts(sheets)] eq {} && [string trim $opts(sheetnames)] eq {}} {
set opts(sheetnames) *
}
set mnt [vfs::zip::Mount $file xlsx]
set rels 0
if {![catch {open xlsx/xl/_rels/workbook.xml.rels r} fd]} {
fconfigure $fd -encoding utf-8
if {![catch {dom parse [read $fd]} rdoc]} {
set rels 1
set relsroot [$rdoc documentElement]
}
close $fd
}
if {![catch {open xlsx/xl/workbook.xml r} fd]} {
fconfigure $fd -encoding utf-8
if {![catch {dom parse [read $fd]} doc]} {
set root [$doc documentElement]
set idx -1
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:workbook/X:sheets/X:sheet}] {
if {[$node hasAttribute sheetId] && [$node hasAttribute name]} {
set sheetId [$node getAttribute sheetId]
set name [$node getAttribute name]
set rid [$node getAttribute r:id]
foreach node [$relsroot selectNodes -namespaces [list X [$relsroot namespaceURI]] [subst -nobackslashes -nocommands {/X:Relationships/X:Relationship[@Id="$rid"]}]] {
if {[$node hasAttribute Target]} {
lappend sheets [incr idx] $sheetId $name $rid [$node getAttribute Target]
}
}
}
}
$doc delete
}
close $fd
}
if {$rels} {
$rdoc delete
}
if {![catch {open xlsx/xl/sharedStrings.xml r} fd]} {
fconfigure $fd -encoding utf-8
if {![catch {dom parse [read $fd]} doc]} {
set root [$doc documentElement]
set idx -1
foreach shared [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:sst/X:si}] {
incr idx
foreach node [$shared selectNodes -namespaces [list X [$shared namespaceURI]] {X:t/text()}] {
append sharedStrings($idx) [$node nodeValue]
}
foreach node [$shared selectNodes -namespaces [list X [$shared namespaceURI]] {*/X:t/text()}] {
append sharedStrings($idx) [$node nodeValue]
}
}
$doc delete
}
close $fd
}
if {![catch {open xlsx/xl/styles.xml r} fd]} {
fconfigure $fd -encoding utf-8
if {![catch {dom parse [read $fd]} doc]} {
set root [$doc documentElement]
set idx -1
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:styleSheet/X:numFmts/X:numFmt}] {
incr idx
if {[$node hasAttribute numFmtId] && [$node hasAttribute formatCode]} {
set numFmtId [$node getAttribute numFmtId]
set formatCode [$node getAttribute formatCode]
set datetime 0
foreach tag {*y* *m* *d* *h* *s*} {
if {[string match -nocase $tag [string map {Black {} Blue {} Cyan {} Green {} Magenta {} Red {} White {} Yellow {}} $formatCode]]} {
set datetime 1
break
}
}
set numFmts($numFmtId) [list dt $datetime fmt $formatCode]
}
}
set idx -1
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:styleSheet/X:cellXfs/X:xf}] {
incr idx
if {[$node hasAttribute numFmtId]} {
set numFmtId [$node getAttribute numFmtId]
if {[$node hasAttribute applyNumberFormat]} {
set applyNumberFormat [$node getAttribute applyNumberFormat]
} else {
set applyNumberFormat 0
}
set cellXfs($idx) [list nfi $numFmtId anf $applyNumberFormat]
}
}
### READING KNOWN FORMATS AND STYLES ###
set wb(s,@) {}
array unset a *
set a(max) 0
set wb(s,numFmtsIds) {}
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:styleSheet/X:numFmts/X:numFmt}] {
if {[$node hasAttribute numFmtId] && [$node hasAttribute formatCode]} {
set wb(s,numFmts,[set idx [$node getAttribute numFmtId]]) [$node getAttribute formatCode]
lappend wb(s,numFmtsIds) $idx
if {$idx > $a(max)} {
set a(max) $idx
}
}
}
if {$a(max) < $::ooxml::defaults(numFmts,start)} {
set a(max) $::ooxml::defaults(numFmts,start)
}
lappend wb(s,@) numFmtId [incr a(max)]
set idx -1
array unset a *
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:styleSheet/X:fonts/X:font}] {
incr idx
array set a {name {} family {} size {} color {} scheme {} bold 0 italic 0 underline 0 color {}}
foreach node1 [$node childNodes] {
switch -- [$node1 nodeName] {
b {
set a(bold) 1
}
i {
set a(italic) 1
}
u {
set a(underline) 1
}
sz {
if {[$node1 hasAttribute val]} {
set a(size) [$node1 getAttribute val]
}
}
color {
if {[$node1 hasAttribute auto]} {
set a(color) [list auto [$node1 getAttribute auto]]
} elseif {[$node1 hasAttribute rgb]} {
set a(color) [list rgb [$node1 getAttribute rgb]]
} elseif {[$node1 hasAttribute indexed]} {
set a(color) [list indexed [$node1 getAttribute indexed]]
} elseif {[$node1 hasAttribute theme]} {
set a(color) [list theme [$node1 getAttribute theme]]
}
}
name {
if {[$node1 hasAttribute val]} {
set a(name) [$node1 getAttribute val]
}
}
family {
if {[$node1 hasAttribute val]} {
set a(family) [$node1 getAttribute val]
}
}
scheme {
if {[$node1 hasAttribute val]} {
set a(scheme) [$node1 getAttribute val]
}
}
}
}
set wb(s,fonts,$idx) [array get a]
}
lappend wb(s,@) fonts [incr idx]
set idx -1
array unset a *
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:styleSheet/X:fills/X:fill}] {
incr idx
array set a {patterntype {} fgcolor {} bgcolor {}}
foreach node1 [$node childNodes] {
switch -- [$node1 nodeName] {
patternFill {
if {[$node1 hasAttribute patternType]} {
set a(patterntype) [$node1 getAttribute patternType]
}
foreach node2 [$node1 childNodes] {
if {[$node2 nodeName] in { fgColor bgColor}} {
if {[$node2 hasAttribute auto]} {
set a([string tolower [$node2 nodeName]]) [list auto [$node2 getAttribute auto]]
} elseif {[$node2 hasAttribute rgb]} {
set a([string tolower [$node2 nodeName]]) [list rgb [$node2 getAttribute rgb]]
} elseif {[$node2 hasAttribute indexed]} {
set a([string tolower [$node2 nodeName]]) [list indexed [$node2 getAttribute indexed]]
} elseif {[$node2 hasAttribute theme]} {
set a([string tolower [$node2 nodeName]]) [list theme [$node2 getAttribute theme]]
}
}
}
}
}
}
set wb(s,fills,$idx) [array get a]
}
lappend wb(s,@) fills [incr idx]
set idx -1
unset -nocomplain d
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:styleSheet/X:borders/X:border}] {
incr idx
set d {left {style {} color {}} right {style {} color {}} top {style {} color {}} bottom {style {} color {}} diagonal {style {} color {} direction {}}}
foreach node1 [$node childNodes] {
if {[$node1 hasAttribute style]} {
set style [$node1 getAttribute style]
} else {
set style {}
}
set color {}
foreach node2 [$node1 childNodes] {
if {[$node2 nodeName] eq {color}} {
if {[$node2 hasAttribute auto]} {
set color [list auto [$node2 getAttribute auto]]
} elseif {[$node2 hasAttribute rgb]} {
set color [list rgb [$node2 getAttribute rgb]]
} elseif {[$node2 hasAttribute indexed]} {
set color [list indexed [$node2 getAttribute indexed]]
} elseif {[$node2 hasAttribute theme]} {
set color [list theme [$node2 getAttribute theme]]
}
}
}
if {[$node1 nodeName] in {left right top bottom diagonal}} {
if {$style ne {}} {
dict set d [$node1 nodeName] style $style
}
if {$color ne {}} {
dict set d [$node1 nodeName] color $color
}
}
}
if {[$node hasAttribute diagonalUp]} {
dict set d diagonal direction up
} elseif {[$node hasAttribute diagonalDown]} {
dict set d diagonal direction down
}
set wb(s,borders,$idx) $d
}
lappend wb(s,@) borders [incr idx]
set idx -1
array unset a *
foreach node [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:styleSheet/X:cellXfs/X:xf}] {
incr idx
array set a {numfmt 0 font 0 fill 0 border 0 xf 0 horizontal {} vertical {} rotate {}}
if {[$node hasAttribute numFmtId]} {
set a(numfmt) [$node getAttribute numFmtId]
}
if {[$node hasAttribute fontId]} {
set a(font) [$node getAttribute fontId]
}
if {[$node hasAttribute fillId]} {
set a(fill) [$node getAttribute fillId]
}
if {[$node hasAttribute borderId]} {
set a(border) [$node getAttribute borderId]
}
if {[$node hasAttribute xfId]} {
set a(xf) [$node getAttribute xfId]
}
foreach node1 [$node childNodes] {
switch -- [$node1 nodeName] {
alignment {
if {[$node1 hasAttribute horizontal]} {
set a(horizontal) [$node1 getAttribute horizontal]
}
if {[$node1 hasAttribute vertical]} {
set a(vertical) [$node1 getAttribute vertical]
}
if {[$node1 hasAttribute textRotation]} {
set a(rotate) [$node1 getAttribute textRotation]
}
}
}
}
set wb(s,styles,$idx) [array get a]
}
lappend wb(s,@) styles [incr idx]
$doc delete
}
close $fd
}
### SHEET AND DATA ###
array set wb {}
foreach {sheet sid name rid target} $sheets {
set read false
if {$opts(sheets) ne {}} {
foreach pat $opts(sheets) {
if {[string match $pat $sheet]} {
set read true
break
}
}
}
if {!$read && $opts(sheetnames) ne {}} {
foreach pat $opts(sheetnames) {
if {[string match $pat $name]} {
set read true
break
}
}
}
if {!$read} continue
lappend wb(sheets) $sheet
set wb($sheet,n) $name
set wb($sheet,max_row) -1
set wb($sheet,max_column) -1
if {![catch {open [file join xlsx/xl $target] r} fd]} {
fconfigure $fd -encoding utf-8
if {![catch {dom parse [read $fd]} doc]} {
set root [$doc documentElement]
set idx -1
foreach col [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:worksheet/X:cols/X:col}] {
incr idx
foreach item {min max width style bestFit customWidth} {
if {[$col hasAttribute $item]} {
switch -- $item {
min - max {
lappend wb($sheet,col,$idx) [string tolower $item] [expr {[$col getAttribute $item] - 1}]
}
default {
lappend wb($sheet,col,$idx) [string tolower $item] [$col getAttribute $item]
}
}
} else {
lappend wb($sheet,col,$idx) [string tolower $item] 0
}
}
lappend wb($sheet,col,$idx) string 0 nozero 0 calcfit 0
}
set wb($sheet,cols) [incr idx]
foreach cell [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:worksheet/X:sheetData/X:row/X:c}] {
if {[$cell hasAttribute t]} {
set type [$cell getAttribute t]
} else {
set type n
}
set value {}
set datetime {}
switch -- $type {
n - b - d - str {
# number (default), boolean, iso-date, formula string
if {[set node [$cell selectNodes -namespaces [list X [$cell namespaceURI]] X:v/text()]] ne {}} {
set value [$node nodeValue]
if {$type eq {n} && [$cell hasAttribute s] && [string is double -strict $value]} {
set idx [$cell getAttribute s]
if {[dict exists $cellXfs($idx) nfi]} {
set numFmtId [dict get $cellXfs($idx) nfi]
if {[info exists numFmts($numFmtId)] && [dict exists $numFmts($numFmtId) dt] && [dict get $numFmts($numFmtId) dt]} {
set datetime $value
catch {clock format [expr {int(($value - 25569) * 86400.0)}] -format $opts(datefmt) -gmt 1} value
}
}
}
} else {
if {![$cell hasAttribute s]} continue
}
}
s {
# shared string
if {[set node [$cell selectNodes -namespaces [list X [$cell namespaceURI]] X:v/text()]] ne {}} {
set index [$node nodeValue]
if {[info exists sharedStrings($index)]} {
set value $sharedStrings($index)
}
} else {
if {![$cell hasAttribute s]} continue
}
}
inlineStr {
# inline string
if {[set string [$cell selectNodes -namespaces [list X [$cell namespaceURI]] X:is]] ne {}} {
foreach node [$string selectNodes -namespaces [list X [$string namespaceURI]] {X:t/text()}] {
append value [$node nodeValue]
}
foreach node [$string selectNodes -namespaces [list X [$string namespaceURI]] {*/X:t/text()}] {
append value [$node nodeValue]
}
} else {
if {![$cell hasAttribute s]} continue
}
}
e {
# error
}
}
if {[$cell hasAttribute r]} {
if {!$opts(valuesonly)} {
set wb($sheet,c,[StringToRowColumn [$cell getAttribute r]]) [$cell getAttribute r]
}
if {!$opts(valuesonly)} {
if {[$cell hasAttribute s]} {
set wb($sheet,s,[StringToRowColumn [$cell getAttribute r]]) [$cell getAttribute s]
}
}
if {!$opts(valuesonly)} {
if {[$cell hasAttribute t]} {
set wb($sheet,t,[StringToRowColumn [$cell getAttribute r]]) [$cell getAttribute t]
}
}
set wb($sheet,v,[StringToRowColumn [$cell getAttribute r]]) $value
if {!$opts(valuesonly) && $datetime ne {}} {
set wb($sheet,d,[StringToRowColumn [$cell getAttribute r]]) $datetime
}
if {!$opts(valuesonly) && [set node [$cell selectNodes -namespaces [list X [$cell namespaceURI]] X:f/text()]] ne {}} {
set wb($sheet,f,[StringToRowColumn [$cell getAttribute r]]) [$node nodeValue]
}
}
}
if {!$opts(valuesonly)} {
foreach row [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:worksheet/X:sheetData/X:row}] {
if {[$row hasAttribute r] && [$row hasAttribute ht] && [$row hasAttribute customHeight] && [$row getAttribute customHeight] == 1} {
dict set wb($sheet,rowheight) [expr {[$row getAttribute r] - 1}] [$row getAttribute ht]
}
}
}
if {!$opts(valuesonly)} {
foreach freeze [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:worksheet/X:sheetViews/X:sheetView/X:pane}] {
if {[$freeze hasAttribute topLeftCell] && [$freeze hasAttribute state] && [$freeze getAttribute state] eq {frozen}} {
set wb($sheet,freeze) [$freeze getAttribute topLeftCell]
}
}
}
if {!$opts(valuesonly)} {
foreach filter [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:worksheet/X:autoFilter}] {
if {[$filter hasAttribute ref]} {
lappend wb($sheet,filter) [$filter getAttribute ref]
}
}
}
if {!$opts(valuesonly)} {
foreach merge [$root selectNodes -namespaces [list X [$root namespaceURI]] {/X:worksheet/X:mergeCells/X:mergeCell}] {
if {[$merge hasAttribute ref]} {
lappend wb($sheet,merge) [$merge getAttribute ref]
}
}
}
$doc delete
}
close $fd
}
}
vfs::zip::Unmount $mnt xlsx
foreach cell [lsort -dictionary [array names wb *,v,*]] {
lassign [split $cell ,] sheet tag row column
if {$opts(keylist)} {
dict lappend wb($sheet,k) $row $column
}
if {$row > $wb($sheet,max_row)} {
set wb($sheet,max_row) $row
}
if {$column > $wb($sheet,max_column)} {
set wb($sheet,max_column) $column
}
}
return [array get wb]
}
#
# ooxml::xl_write
#
oo::class create ooxml::xl_write {
constructor { args } {
my variable obj
my variable cells
my variable sharedStrings
my variable fonts
my variable numFmts
my variable styles
my variable fills
my variable borders
my variable cols
if {[::ooxml::Getopt opts {creator.arg {unknown}} $args]} {
error $opts(-errmsg)
}
set obj(blockPreset) 0
set obj(encoding) utf-8
dom setResultEncoding $obj(encoding)
set obj(indent) none
set obj(creator) $opts(creator)
set obj(created) [clock format [clock seconds] -format %Y-%m-%dT%H:%M:%SZ -gmt 1]
set obj(sheets) 0
array set sheets {}
set obj(sharedStrings) 0
set sharedStrings {}
set obj(numFmts) $::ooxml::defaults(numFmts,start)
array set numFmts {}
set obj(borders) 1
set borders(0) {left {style {} color {}} right {style {} color {}} top {style {} color {}} bottom {style {} color {}} diagonal {style {} color {} direction {}}}
set obj(fills) 2
set fills(0) {patterntype none fgcolor {} bgcolor {}}
set fills(1) {patterntype gray125 fgcolor {} bgcolor {}}
set obj(fonts) 1
set fonts(0) {name Calibri family 2 size 12 color {theme 1} scheme minor bold 0 italic 0 underline 0 color {}}
set obj(styles) 1
set styles(0) {numfmt 0 font 0 fill 0 border 0 xf 0 horizontal {} vertical {} rotate {}}
set obj(cols) 0
array set cols {}
set obj(calcChain) 0
set obj(defaultdatestyle) 0
array set cells {}
return 0
}
destructor {
return 0
}
method numberformat { args } {
my variable obj
my variable numFmts
if {[::ooxml::Getopt opts {list format.arg {} general date time datetime iso8601 number decimal red separator fraction scientific percent string text} $args]} {
error $opts(-errmsg)
}
if {$opts(list)} {
array set tmp [array get ::ooxml::predefNumFmts]
array set tmp [array get numFmts]
return [array get tmp]
}
set obj(blockPreset) 1
if {$opts(general)} {
return 0
}
if {$opts(date)} {
return 14
}
if {$opts(time)} {
return 20
}
if {$opts(number)} {
if {$opts(separator)} {
if {$opts(red)} {
return 38
} else {
return 3
}
} else {
if {$opts(red)} {
return -1
} else {
return 1
}
}
}
if {$opts(decimal)} {
if {$opts(percent)} {
return 10
}
if {$opts(separator)} {
if {$opts(red)} {
return 40
} else {
return 4
}
} else {
if {$opts(red)} {
return -1
} else {
return 2
}
}
}
if {$opts(fraction)} {
return 12
}
if {$opts(scientific)} {
return 11
}
if {$opts(percent)} {
return 9
}
if {$opts(text) || $opts(string)} {
return 49
}
if {$opts(datetime)} {
set opts(format) {dd/mm/yyyy\ hh:mm;@}
}
if {$opts(iso8601)} {
set opts(format) {yyyy\-mm\-dd\ hh:mm:ss;@}
}
foreach idx [array names ::ooxml::predefNumFmts] {
if {[dict get $::ooxml::predefNumFmts($idx) fmt] eq $opts(format)} {
return $idx
}
}
foreach idx [array names numFmts] {
if {$numFmts($idx) eq $opts(format)} {
return $idx
}
}
if {$opts(format) eq {}} {
return -1
}
set idx $obj(numFmts)
set numFmts($idx) $opts(format)
incr obj(numFmts)
return $idx
}
method defaultdatestyle { style } {
my variable obj
set obj(defaultdatestyle) $style
}
method font { args } {
my variable obj
my variable fonts
array set a $fonts(0)
if {[::ooxml::Getopt opts [list list name.arg $a(name) family.arg $a(family) size.arg $a(size) color $a(color) scheme $a(scheme) bold italic underline color.arg {}] $args]} {
error $opts(-errmsg)
}
if {$opts(list)} {
return [array get fonts]
}
set obj(blockPreset) 1
if {$opts(name) eq {}} {
set opts(name) $a(name)
}
if {![string is integer -strict $opts(family)] || $opts(family) < 0} {
set opts(family) $a(family)
}
if {![string is integer -strict $opts(size)] || $opts(size) < 0} {
set opts(size) $a(size)
}
if {$opts(scheme) ni {major minor none}} {
set opts(scheme) $a(scheme)
}
set opts(color) [::ooxml::Color $opts(color)]
foreach idx [lsort -integer [array names fonts]] {
array set a $fonts($idx)
set found 1
foreach name [array names a] {
if {$a($name) ne $opts($name)} {
set found 0
break
}
}
if {$found} {
return $idx
}
}
set fonts($obj(fonts)) {}
foreach item {name family size bold italic underline color scheme} {
lappend fonts($obj(fonts)) $item $opts($item)
}
set idx $obj(fonts)
incr obj(fonts)
return $idx
}
method fill { args } {
my variable obj
my variable fills
if {[::ooxml::Getopt opts {list patterntype.arg none fgcolor.arg {} bgcolor.arg {}} $args]} {
error $opts(-errmsg)
}
if {$opts(list)} {
return [array get fills]
}
set obj(blockPreset) 1
if {$opts(patterntype) ni $::ooxml::predefPatternType} {
set opts(patterntype) none
}
set opts(fgcolor) [::ooxml::Color $opts(fgcolor)]
set opts(bgcolor) [::ooxml::Color $opts(bgcolor)]
foreach idx [lsort -integer [array names fills]] {
array set a $fills($idx)
set found 1
foreach name [array names a] {
if {$a($name) ne $opts($name)} {
set found 0
break
}
}
if {$found} {
return $idx
}
}
set fills($obj(fills)) {}
foreach item {patterntype fgcolor bgcolor} {
lappend fills($obj(fills)) $item $opts($item)
}
set idx $obj(fills)
incr obj(fills)
return $idx
}
method border { args } {
my variable obj
my variable borders
if {[::ooxml::Getopt opts {list leftstyle.arg {} leftcolor.arg {} rightstyle.arg {} rightcolor.arg {} topstyle.arg {} topcolor.arg {} bottomstyle.arg {} bottomcolor.arg {} diagonalstyle.arg {} diagonalcolor.arg {} diagonaldirection.arg {}} $args]} {
error $opts(-errmsg)
}
if {$opts(list)} {
return [array get borders]
}
set obj(blockPreset) 1
if {$opts(leftstyle) ni $::ooxml::predefBorderLineStyles || $opts(leftstyle) eq {none}} {
set opts(leftstyle) {}
}
set opts(leftcolor) [::ooxml::Color $opts(leftcolor)]
if {$opts(rightstyle) ni $::ooxml::predefBorderLineStyles || $opts(rightstyle) eq {none}} {
set opts(rightstyle) {}
}
set opts(rightcolor) [::ooxml::Color $opts(rightcolor)]
if {$opts(topstyle) ni $::ooxml::predefBorderLineStyles || $opts(topstyle) eq {none}} {
set opts(topstyle) {}
}
set opts(topcolor) [::ooxml::Color $opts(topcolor)]
if {$opts(bottomstyle) ni $::ooxml::predefBorderLineStyles || $opts(bottomstyle) eq {none}} {
set opts(bottomstyle) {}
}
set opts(bottomcolor) [::ooxml::Color $opts(bottomcolor)]
if {$opts(diagonalstyle) ni $::ooxml::predefBorderLineStyles || $opts(diagonalstyle) eq {none}} {
set opts(diagonalstyle) {}
}
set opts(diagonalcolor) [::ooxml::Color $opts(diagonalcolor)]
if {$opts(diagonaldirection) ni {up down}} {
set opts(diagonaldirection) {}
}
switch -- $opts(diagonaldirection) {
up {
set opts(diagonaldirection) diagonalUp
}
down {
set opts(diagonaldirection) diagonalDown
}
default {
set opts(diagonaldirection) {}
}
}
dict set tmp left style $opts(leftstyle)
dict set tmp left color $opts(leftcolor)
dict set tmp right style $opts(rightstyle)
dict set tmp right color $opts(rightcolor)
dict set tmp top style $opts(topstyle)
dict set tmp top color $opts(topcolor)
dict set tmp bottom style $opts(bottomstyle)
dict set tmp bottom color $opts(bottomcolor)
dict set tmp diagonal style $opts(diagonalstyle)
dict set tmp diagonal color $opts(diagonalcolor)
dict set tmp diagonal direction $opts(diagonaldirection)
foreach idx [lsort -integer [array names borders]] {
set found 1
foreach key [dict keys $tmp] {
foreach subkey [dict keys [dict get $tmp $key]] {
if {[dict get $borders($idx) $key $subkey] ne [dict get $tmp $key $subkey]} {
set found 0
break
}
}
}
if {$found} {
return $idx
}
}
set borders($obj(borders)) $tmp
set idx $obj(borders)
incr obj(borders)
return $idx
}
method style { args } {
my variable obj
my variable styles
if {[::ooxml::Getopt opts {list numfmt.arg 0 font.arg 0 fill.arg 0 border.arg 0 xf.arg 0 horizontal.arg {} vertical.arg {} rotate.arg {}} $args]} {
error $opts(-errmsg)
}
if {$opts(list)} {
return [array get styles]
}
set obj(blockPreset) 1
if {![string is integer -strict $opts(numfmt)] || $opts(numfmt) < 0} {
set opts(numfmt) 0
}
if {![string is integer -strict $opts(font)] || $opts(font) < 0} {
set opts(font) 0
}
if {![string is integer -strict $opts(fill)] || $opts(fill) < 0} {
set opts(fill) 0
}
if {![string is integer -strict $opts(border)] || $opts(border) < 0} {
set opts(border) 0
}
if {![string is integer -strict $opts(xf)] || $opts(xf) < 0} {
set opts(xf) 0
}
if {$opts(horizontal) ni {right center left}} {
set opts(horizontal) {}
}
if {$opts(vertical) ni {top center bottom}} {
set opts(vertical) {}
}
if {![string is integer -strict $opts(rotate)] || $opts(rotate) < 0 || $opts(rotate) > 360} {
set opts(rotate) {}
}
foreach idx [lsort -integer [array names styles]] {
array set a $styles($idx)
set found 1
foreach name [array names a] {
if {$a($name) ne $opts($name)} {
set found 0
break
}
}
if {$found} {
return $idx
}
}
set styles($obj(styles)) {}
foreach item {numfmt font fill border xf horizontal vertical rotate} {
lappend styles($obj(styles)) $item $opts($item)
}
set idx $obj(styles)
incr obj(styles)
return $idx
}
method worksheet { name } {
my variable obj
incr obj(sheets)
set obj(callRow,$obj(sheets)) 0
set obj(sheet,$obj(sheets)) $name
set obj(gCol,$obj(sheets)) -1
set obj(row,$obj(sheets)) -1
set obj(col,$obj(sheets)) -1
set obj(dminrow,$obj(sheets)) 4294967295
set obj(dmaxrow,$obj(sheets)) 0
set obj(dmincol,$obj(sheets)) 4294967295
set obj(dmaxcol,$obj(sheets)) 0
set obj(autofilter,$obj(sheets)) {}
set obj(freeze,$obj(sheets)) {}
set obj(merge,$obj(sheets)) {}
set obj(rowHeight,$obj(sheets)) {}
return $obj(sheets)
}
method column { sheet args } {
my variable obj
my variable cols
if {[::ooxml::Getopt opts {index.arg {} to.arg {} width.arg {} style.arg {} bestfit customwidth string nozero calcfit} $args]} {
error $opts(-errmsg)
}
lassign [split $opts(index) ,] row col
if {[string is integer -strict $opts(index)] && $opts(index) > -1} {
set obj(gCol,$sheet) $opts(index)
} elseif {[string is integer -strict $col] && $col > -1} {
set obj(gCol,$sheet) $col
} elseif {[string trim $opts(index)] eq {}} {
incr obj(gCol,$sheet)
}
set opts(index) $obj(gCol,$sheet)
if {$opts(to) eq {}} {
set opts(to) $opts(index)
} else {
set opts(to) [::ooxml::IndexToString $opts(to)]
}
set opts(index) [lindex [split $opts(index) ,] end]
set opts(to) [lindex [split $opts(to) ,] end]
if {[string is integer -strict $opts(index)]} {
set obj(gCol,$sheet) $opts(index)
}
if {![string is double -strict $opts(width)] || $opts(width) < 0} {
set opts(width) {}
}
if {![string is integer -strict $opts(style)] || $opts(style) < 0} {
set opts(style) {}
}
if {$opts(width) ne {} || ([string is integer -strict $opts(style)] && $opts(style) > 0) || $opts(bestfit) > 0} {
if {$opts(width) eq {}} {
set opts(width) $::ooxml::defaults(cols,width)
}
set cols($sheet,$opts(index)) [list min $opts(index) max $opts(to) width $opts(width) style $opts(style) bestfit $opts(bestfit) customwidth $opts(customwidth) string $opts(string) nozero $opts(nozero)]
}
set obj($sheet,cols) [llength [array names cols $sheet,*]]
return $obj(gCol,$sheet)
}
method row { sheet args } {
my variable obj
if {[::ooxml::Getopt opts {index.arg {} height.arg {}} $args]} {
error $opts(-errmsg)
}
if {![string is integer -strict $opts(height)] || $opts(height) < 1 || $opts(height) > 1024} {
set opts(height) {}
}
if {[string is integer -strict $opts(index)] && $opts(index) > -1} {
set obj(callRow,$obj(sheets)) 1
set obj(col,$obj(sheets)) -1
set obj(row,$sheet) $opts(index)
if {$opts(height) ne {}} {
dict set obj(rowHeight,$sheet) $obj(row,$sheet) $opts(height)
}
return $obj(row,$sheet)
}
if {[string trim $opts(index)] eq {}} {
set obj(callRow,$obj(sheets)) 1
set obj(col,$obj(sheets)) -1
incr obj(row,$sheet)
if {$opts(height) ne {}} {
dict set obj(rowHeight,$sheet) $obj(row,$sheet) $opts(height)
}
return $obj(row,$sheet)
}
return -1
}
method rowheight { sheet row height } {
my variable obj
if {![string is integer -strict $row] || ![string is integer -strict $height] || $height < 1 || $height > 1024} {
return -1
}
dict set obj(rowHeight,$sheet) $row $height
return $row
}
method cell { sheet {data {}} args } {
my variable obj
my variable cells
my variable cols
if {[::ooxml::Getopt opts {index.arg {} style.arg 0 formula.arg {} string nozero globalstyle height.arg {}} $args]} {
error $opts(-errmsg)
}
if {!$obj(callRow,$obj(sheets))} {
set obj(callRow,$obj(sheets)) 1
incr obj(row,$sheet)
}
lassign [split $opts(index) ,] row col
if {[string is integer -strict $opts(index)] && $opts(index) > -1} {
set obj(col,$sheet) $opts(index)
} elseif {[string is integer -strict $row] && [string is integer -strict $col] && $row > -1 && $col > -1} {
set obj(row,$sheet) $row
set obj(col,$sheet) $col
} elseif {[string trim $opts(index)] eq {}} {
incr obj(col,$sheet)
}
if {$obj(row,$sheet) < 0 || $obj(col,$sheet) < 0} {
return -1
}
if {$opts(globalstyle) && [string is integer -strict $opts(style)] && $opts(style) < 1} {
if {[info exists cols($sheet,$obj(col,$sheet))] && [dict get $cols($sheet,$obj(col,$sheet)) style] > 0} {
set opts(style) [dict get $cols($sheet,$obj(col,$sheet)) style]
}
}
if {$opts(string) == 0 && [info exists cols($sheet,$obj(col,$sheet))] && [dict get $cols($sheet,$obj(col,$sheet)) string] == 1} {
set opts(string) 1
}
if {$opts(nozero) == 0 && [info exists cols($sheet,$obj(col,$sheet))] && [dict get $cols($sheet,$obj(col,$sheet)) nozero] == 1} {
set opts(nozero) 1
}
set cell ${sheet},$obj(row,$sheet),$obj(col,$sheet)
set cells($cell) {}
if {[string is integer -strict $opts(height)] && $opts(height) > 0 && $opts(height) < 1024} {
dict set obj(rowHeight,$sheet) $obj(row,$sheet) $opts(height)
}
set data [string trimright $data]
if {$opts(nozero) && [string is double -strict $data] && $data == 0} {
set data {}
}
if {$opts(string)} {
set type s
} elseif {[set datetime [::ooxml::ScanDateTime $data]] ne {}} {
set type n
set data $datetime
if {[string is integer -strict $opts(style)] && $opts(style) < 1} {
set opts(style) $obj(defaultdatestyle)
}
} elseif {[string is double -strict $data]} {
set type n
set data [string trim $data]
if {$data in {Inf infinity NaN -NaN} || $opts(string)} {
set type s
}
} else {
set type s
}
if {[string is integer -strict $opts(style)] && $opts(style) > 0} {
lappend cells($cell) s $opts(style)
}
if {[string trim $opts(formula)] ne {}} {
lappend cells($cell) t $type
lappend cells($cell) f $opts(formula)
} else {
lappend cells($cell) v $data t $type
}
if {[string trim $data] eq {} && [string trim $opts(formula)] eq {} && ![string is integer -strict $opts(style)] && $opts(style) < 1} {
unset -nocomplain cells($cell)
} else {
if {$obj(row,$sheet) < $obj(dminrow,$sheet)} {
set obj(dminrow,$sheet) $obj(row,$sheet)
}
if {$obj(row,$sheet) > $obj(dmaxrow,$sheet)} {
set obj(dmaxrow,$sheet) $obj(row,$sheet)
}
if {$obj(col,$sheet) < $obj(dmincol,$sheet)} {
set obj(dmincol,$sheet) $obj(col,$sheet)
}
if {$obj(col,$sheet) > $obj(dmaxcol,$sheet)} {
set obj(dmaxcol,$sheet) $obj(col,$sheet)
}
}
return $obj(row,$sheet),$obj(col,$sheet)
}
method autofilter { sheet indexFrom indexTo } {
my variable obj
set indexFrom [::ooxml::IndexToString $indexFrom]
set indexTo [::ooxml::IndexToString $indexTo]
if {$indexFrom ne {} && $indexTo ne {}} {
set obj(autofilter,$sheet) $indexFrom:$indexTo
return 0
}
return 1
}
method freeze { sheet index } {
my variable obj
set index [::ooxml::IndexToString $index]
if {$index ne {}} {
set obj(freeze,$sheet) $index
return 0
}
return 1
}
method merge { sheet indexFrom indexTo } {
my variable obj
set indexFrom [::ooxml::IndexToString $indexFrom]
set indexTo [::ooxml::IndexToString $indexTo]
if {$indexFrom ne {} && $indexTo ne {} && "$indexFrom:$indexTo" ni $obj(merge,$sheet)} {
lappend obj(merge,$sheet) $indexFrom:$indexTo
return 0
}
return 1
}
method presetstyles { valName args } {
my variable obj
my variable cols
my variable fonts
my variable numFmts
my variable styles
my variable fills
my variable borders
if {$obj(blockPreset)} {
return 1
}
upvar $valName a
if {[info exists a(s,@)]} {
set obj(blockPreset) 1
if {[dict exists $a(s,@) numFmtId]} {
set obj(numFmts) [dict get $a(s,@) numFmtId]
foreach idx $a(s,numFmtsIds) {
if {[info exists a(s,numFmts,$idx)]} {
set numFmts($idx) $a(s,numFmts,$idx)
}
}
}
foreach item {fonts fills borders styles} {
if {[dict exists $a(s,@) $item]} {
upvar 0 $item ad
for {set idx 0} {$idx < [dict get $a(s,@) $item]} {incr idx} {
if {[info exists a(s,$item,$idx)]} {
set ad($idx) $a(s,$item,$idx)
}
}
set obj($item) [dict get $a(s,@) $item]
}
}
}
foreach sheet $a(sheets) {
for {set idx 0} {$idx < $a($sheet,cols)} {incr idx} {
if {[info exists a($sheet,col,$idx)]} {
set cols([expr {$sheet + 1}],$idx) $a($sheet,col,$idx)
}
}
set obj([expr {$sheet + 1}],cols) [llength [array names cols]]
}
return 0
}
method presetsheets { valName args } {
upvar $valName a
# [self object] -> my
if {[info exists a(sheets)]} {
foreach sheet $a(sheets) {
if {[set currentSheet [my worksheet $a($sheet,n)]] > -1} {
dict set a(sheetmap) $sheet $currentSheet
foreach item [lsort -dictionary [array names a $sheet,v,*]] {
lassign [split $item ,] sheet tag row col
set options [list -index $row,$col]
if {[info exists a($sheet,f,$row,$col)]} {
lappend options -formula $a($sheet,f,$row,$col)
}
if {[info exists a($sheet,t,$row,$col)] && $a($sheet,t,$row,$col) eq {s}} {
lappend options -string
}
if {[info exists a($sheet,s,$row,$col)]} {
lappend options -style $a($sheet,s,$row,$col)
}
my cell $currentSheet $a($item) {*}$options
}
if {[info exists a($sheet,rowheight)]} {
foreach {row height} $a($sheet,rowheight) {
my rowheight $currentSheet $row $height
}
}
if {[info exists a($sheet,freeze)]} {
my freeze $currentSheet $a($sheet,freeze)
}
if {[info exists a($sheet,filter)]} {
foreach item $a($sheet,filter) {
my autofilter $currentSheet {*}[split $item :]
}
}
if {[info exists a($sheet,merge)]} {
foreach item $a($sheet,merge) {
my merge $currentSheet {*}[split $item :]
}
}
}
}
}
}
method debug { args } {
foreach item $args {
catch {
my variable $item
parray $item
}
}
}
method write { file args } {
my variable obj
my variable cells
my variable sharedStrings
my variable fonts
my variable numFmts
my variable styles
my variable fills
my variable borders
my variable cols
if {[::ooxml::Getopt opts {holdcontainerdirectory} $args]} {
error $opts(-errmsg)
}
foreach {n v} [array get cells] {
if {[dict exists $v t] && [dict get $v t] eq {s} && [dict exists $v v] && [dict get $v v] ne {}} {
if {[set pos [lsearch -exact $sharedStrings [dict get $v v]]] == -1} {
lappend sharedStrings [dict get $v v]
set pos [lsearch -exact $sharedStrings [dict get $v v]]
}
set obj(sharedStrings) 1
dict set cells($n) v $pos
}
}
unset -nocomplain n v
# _rels/.rels
set doc [set obj(doc,_rels/.rels) [dom createDocument Relationships]]
set root [$doc documentElement]
set rId 0
dom createNodeCmd -tagName Relationship elementNode Tag_Relationship
$root setAttribute xmlns http://schemas.openxmlformats.org/package/2006/relationships
$root appendFromScript {
Tag_Relationship Id rId1 Type http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument Target xl/workbook.xml {}
Tag_Relationship Id rId2 Type http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties Target docProps/app.xml {}
Tag_Relationship Id rId3 Type http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties Target docProps/core.xml {}
}
# [Content_Types].xml
set doc [set obj(doc,\[Content_Types\].xml) [dom createDocument Types]]
set root [$doc documentElement]
dom createNodeCmd -tagName Default elementNode Tag_Default
dom createNodeCmd -tagName Override elementNode Tag_Override
$root setAttribute xmlns http://schemas.openxmlformats.org/package/2006/content-types
$root appendFromScript {
Tag_Default Extension xml ContentType application/xml {}
Tag_Default Extension rels ContentType application/vnd.openxmlformats-package.relationships+xml {}
Tag_Override PartName /xl/workbook.xml ContentType application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml {}
Tag_Override PartName /xl/worksheets/sheet1.xml ContentType application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml {}
for {set ws 1} {$ws <= $obj(sheets)} {incr ws} {
Tag_Override PartName /xl/theme/theme${ws}.xml ContentType application/vnd.openxmlformats-officedocument.theme+xml {}
}
Tag_Override PartName /xl/styles.xml ContentType application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml {}
if {$obj(sharedStrings) > 0} {
Tag_Override PartName /xl/sharedStrings.xml ContentType application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml {}
}
if {$obj(calcChain)} {
Tag_Override PartName /xl/calcChain.xml ContentType application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml {}
}
Tag_Override PartName /docProps/core.xml ContentType application/vnd.openxmlformats-package.core-properties+xml {}
Tag_Override PartName /docProps/app.xml ContentType application/vnd.openxmlformats-officedocument.extended-properties+xml {}
}
# docProps/app.xml
set doc [set obj(doc,docProps/app.xml) [dom createDocument Properties]]
set root [$doc documentElement]
dom createNodeCmd textNode Text
dom createNodeCmd -tagName AppVersion elementNode Tag_AppVersion
dom createNodeCmd -tagName Application elementNode Tag_Application
dom createNodeCmd -tagName Company elementNode Tag_Company
dom createNodeCmd -tagName DocSecurity elementNode Tag_DocSecurity
dom createNodeCmd -tagName HeadingPairs elementNode Tag_HeadingPairs
dom createNodeCmd -tagName HyperlinksChanged elementNode Tag_HyperlinksChanged
dom createNodeCmd -tagName LinksUpToDate elementNode Tag_LinksUpToDate
dom createNodeCmd -tagName ScaleCrop elementNode Tag_ScaleCrop
dom createNodeCmd -tagName SharedDoc elementNode Tag_SharedDoc
dom createNodeCmd -tagName TitlesOfParts elementNode Tag_TitlesOfParts
dom createNodeCmd -tagName vt:i4 elementNode Tag_vt:i4
dom createNodeCmd -tagName vt:lpstr elementNode Tag_vt:lpstr
dom createNodeCmd -tagName vt:variant elementNode Tag_vt:variant
dom createNodeCmd -tagName vt:vector elementNode Tag_vt:vector
$root setAttribute xmlns http://schemas.openxmlformats.org/officeDocument/2006/extended-properties
$root setAttribute xmlns:vt http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes
$root appendFromScript {
Tag_Application { Text {Tcl - Office Open XML - Spreadsheet} }
Tag_DocSecurity { Text 0 }
Tag_ScaleCrop { Text false }
Tag_HeadingPairs {
Tag_vt:vector size 2 baseType variant {
Tag_vt:variant {
Tag_vt:lpstr { Text [msgcat::mc Worksheets] }
}
Tag_vt:variant {
Tag_vt:i4 { Text 3 }
}
}
}
Tag_TitlesOfParts {
Tag_vt:vector size $obj(sheets) baseType lpstr {
Tag_vt:lpstr {
for {set ws 1} {$ws <= $obj(sheets)} {incr ws} {
Text [msgcat::mc Sheet]$ws
}
}
}
}
Tag_Company {}
Tag_LinksUpToDate { Text false }
Tag_SharedDoc { Text false }
Tag_HyperlinksChanged { Text false }
Tag_AppVersion { Text 1.0 }
}
# docProps/core.xml
set doc [set obj(doc,docProps/core.xml) [dom createDocument cp:coreProperties]]
set root [$doc documentElement]
dom createNodeCmd textNode Text
dom createNodeCmd -tagName cp:lastModifiedBy elementNode Tag_cp:lastModifiedBy
dom createNodeCmd -tagName dc:creator elementNode Tag_dc:creator
dom createNodeCmd -tagName dcterms:created elementNode Tag_dcterms:created
dom createNodeCmd -tagName dcterms:modified elementNode Tag_dcterms:modified
$root setAttribute xmlns:cp http://schemas.openxmlformats.org/package/2006/metadata/core-properties
$root setAttribute xmlns:dc http://purl.org/dc/elements/1.1/
$root setAttribute xmlns:dcterms http://purl.org/dc/terms/
$root setAttribute xmlns:dcmitype http://purl.org/dc/dcmitype/
$root setAttribute xmlns:xsi http://www.w3.org/2001/XMLSchema-instance
$root appendFromScript {
Tag_dc:creator { Text $obj(creator) }
Tag_cp:lastModifiedBy { Text $obj(creator) }
Tag_dcterms:created xsi:type dcterms:W3CDTF { Text $obj(created) }
Tag_dcterms:modified xsi:type dcterms:W3CDTF { Text $obj(created) }
}
# xl/_rels/workbook.xml.rels
set doc [set obj(doc,xl/_rels/workbook.xml.rels) [dom createDocument Relationships]]
set root [$doc documentElement]
dom createNodeCmd -tagName Relationship elementNode Tag_Relationship
$root setAttribute xmlns http://schemas.openxmlformats.org/package/2006/relationships
$root appendFromScript {
for {set ws 1} {$ws <= $obj(sheets)} {incr ws} {
Tag_Relationship Id rId$ws Type http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet Target worksheets/sheet${ws}.xml {}
}
set rId [incr ws -1]
Tag_Relationship Id rId[incr rId] Type http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme Target theme/theme1.xml {}
Tag_Relationship Id rId[incr rId] Type http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles Target styles.xml {}
if {$obj(sharedStrings) > 0} {
Tag_Relationship Id rId[incr rId] Type http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings Target sharedStrings.xml {}
}
if {$obj(calcChain)} {
Tag_Relationship Id rId[incr rId] Type http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain Target calcChain.xml {}
}
}
# xl/sharedStrings.xml
if {$obj(sharedStrings) > 0} {
set doc [set obj(doc,xl/sharedStrings.xml) [dom createDocument sst]]
set root [$doc documentElement]
dom createNodeCmd textNode Text
dom createNodeCmd -tagName si elementNode Tag_si
dom createNodeCmd -tagName t elementNode Tag_t
$root setAttribute xmlns http://schemas.openxmlformats.org/spreadsheetml/2006/main
$root setAttribute count [llength $sharedStrings]
$root setAttribute uniqueCount [llength $sharedStrings]
$root appendFromScript {
foreach string $sharedStrings {
Tag_si {
Tag_t { Text $string }
}
}
}
}
# xl/calcChain.xml
if {$obj(calcChain)} {
set doc [set obj(doc,xl/calcChain.xml) [dom createDocument calcChain]]
set root [$doc documentElement]
dom createNodeCmd -tagName c elementNode Tag_c
$root setAttribute xmlns http://schemas.openxmlformats.org/spreadsheetml/2006/main
$root appendFromScript {
Tag_c r C1 i 3 l 1 {}
Tag_c r A3 i 2 {}
}
}
# xl/styles.xml
set doc [set obj(doc,xl/styles.xml) [dom createDocument styleSheet]]
set root [$doc documentElement]
dom createNodeCmd -tagName alignment elementNode Tag_alignment
dom createNodeCmd -tagName b elementNode Tag_b
dom createNodeCmd -tagName bgColor elementNode Tag_bgColor
dom createNodeCmd -tagName border elementNode Tag_border
dom createNodeCmd -tagName borders elementNode Tag_borders
dom createNodeCmd -tagName bottom elementNode Tag_bottom
dom createNodeCmd -tagName cellStyle elementNode Tag_cellStyle
dom createNodeCmd -tagName cellStyleXfs elementNode Tag_cellStyleXfs
dom createNodeCmd -tagName cellStyles elementNode Tag_cellStyles
dom createNodeCmd -tagName cellXfs elementNode Tag_cellXfs
dom createNodeCmd -tagName color elementNode Tag_color
dom createNodeCmd -tagName diagonal elementNode Tag_diagonal
dom createNodeCmd -tagName dxfs elementNode Tag_dxfs
dom createNodeCmd -tagName family elementNode Tag_family
dom createNodeCmd -tagName fgColor elementNode Tag_fgColor
dom createNodeCmd -tagName fill elementNode Tag_fill
dom createNodeCmd -tagName fills elementNode Tag_fills
dom createNodeCmd -tagName font elementNode Tag_font
dom createNodeCmd -tagName fonts elementNode Tag_fonts
dom createNodeCmd -tagName i elementNode Tag_i
dom createNodeCmd -tagName left elementNode Tag_left
dom createNodeCmd -tagName name elementNode Tag_name
dom createNodeCmd -tagName numFmt elementNode Tag_numFmt
dom createNodeCmd -tagName numFmts elementNode Tag_numFmts
dom createNodeCmd -tagName patternFill elementNode Tag_patternFill
dom createNodeCmd -tagName right elementNode Tag_right
dom createNodeCmd -tagName scheme elementNode Tag_scheme
dom createNodeCmd -tagName sz elementNode Tag_sz
dom createNodeCmd -tagName tableStyles elementNode Tag_tableStyles
dom createNodeCmd -tagName top elementNode Tag_top
dom createNodeCmd -tagName u elementNode Tag_u
dom createNodeCmd -tagName xf elementNode Tag_xf
$root setAttribute xmlns http://schemas.openxmlformats.org/spreadsheetml/2006/main
$root setAttribute xmlns:mc http://schemas.openxmlformats.org/markup-compatibility/2006
$root setAttribute xmlns:x14ac http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac
$root setAttribute mc:Ignorable x14ac
$root appendFromScript {
if {$obj(numFmts) > $::ooxml::defaults(numFmts,start)} {
Tag_numFmts count [llength [array names numFmts]] {
foreach idx [lsort -integer [array names numFmts]] {
Tag_numFmt numFmtId $idx formatCode $numFmts($idx) {}
}
}
}
Tag_fonts count $obj(fonts) x14ac:knownFonts 1 {
foreach idx [lsort -integer [array names fonts]] {
Tag_font {
if {[dict get $fonts($idx) color] ne {}} {
Tag_color [lindex [dict get $fonts($idx) color] 0] [lindex [dict get $fonts($idx) color] 1]
}
if {[dict get $fonts($idx) bold] == 1} {
Tag_b {}
}
if {[dict get $fonts($idx) italic] == 1} {
Tag_i {}
}
if {[dict get $fonts($idx) underline] == 1} {
Tag_u {}
}
Tag_sz val [dict get $fonts($idx) size] {}
Tag_name val [dict get $fonts($idx) name] {}
Tag_family val [dict get $fonts($idx) family] {}
Tag_scheme val [dict get $fonts($idx) scheme] {}
}
}
}
if {$obj(fills) > 0} {
Tag_fills count $obj(fills) {
foreach idx [lsort -integer [array names fills]] {
Tag_fill {
Tag_patternFill patternType [dict get $fills($idx) patterntype] {
foreach tag {fgColor bgColor} {
set key [string tolower $tag]
if {[dict get $fills($idx) $key] ne {}} {
Tag_$tag [lindex [dict get $fills($idx) $key] 0] [lindex [dict get $fills($idx) $key] 1] {}
}
}
}
}
}
}
}
if {$obj(borders) > 0} {
Tag_borders count $obj(borders) {
foreach idx [lsort -integer [array names borders]] {
set attr {}
if {[dict exists $borders($idx) diagonal direction] && [dict get $borders($idx) diagonal direction] ne {}} {
lappend attr [string map {up diagonalUp down diagonalDown} [dict get $borders($idx) diagonal direction]] 1
}
Tag_border {*}$attr {
foreach item {left right top bottom diagonal} {
set attr {}
if {[dict exists $borders($idx) $item style] && [dict get $borders($idx) $item style] ne {}} {
lappend attr style [dict get $borders($idx) $item style]
}
Tag_$item {*}$attr {
if {[dict exists $borders($idx) $item color] && [dict get $borders($idx) $item color] ne {}} {
Tag_color [lindex [dict get $borders($idx) $item color] 0] [lindex [dict get $borders($idx) $item color] 1] {}
}
}
}
}
}
}
}
Tag_cellStyleXfs count 1 {
Tag_xf numFmtId 0 fontId 0 fillId 0 borderId 0 {}
}
Tag_cellXfs count $obj(styles) {
foreach idx [lsort -integer [array names styles]] {
set attr {}
lappend attr numFmtId [dict get $styles($idx) numfmt]
lappend attr fontId [dict get $styles($idx) font]
lappend attr fillId [dict get $styles($idx) fill]
lappend attr borderId [dict get $styles($idx) border]
lappend attr xfId [dict get $styles($idx) xf]
if {[dict get $styles($idx) numfmt] > 0} {
lappend attr applyNumberFormat 1
}
if {[dict get $styles($idx) font] > 0} {
lappend attr applyFont 1
}
if {[dict get $styles($idx) fill] > 0} {
lappend attr applyFill 1
}
if {[dict get $styles($idx) border] > 0} {
lappend attr applyBorder 1
}
# lappend attr applyProtection 1 quotePrefix 1
if {[dict get $styles($idx) horizontal] ne {} || [dict get $styles($idx) vertical] ne {} || [dict get $styles($idx) rotate] ne {}} {
lappend attr applyAlignment 1
set alignment 1
} else {
set alignment 0
}
Tag_xf {*}$attr {
set attr {}
if {$alignment} {
if {[dict get $styles($idx) horizontal] ne {}} {
lappend attr horizontal [dict get $styles($idx) horizontal]
}
if {[dict get $styles($idx) vertical] ne {}} {
lappend attr vertical [dict get $styles($idx) vertical]
}
if {[dict get $styles($idx) rotate] ne {}} {
lappend attr textRotation [dict get $styles($idx) rotate]
}
Tag_alignment {*}$attr {}
}
}
}
}
Tag_cellStyles count 1 {
Tag_cellStyle name Standard xfId 0 builtinId 0 {}
}
Tag_dxfs count 0 {}
Tag_tableStyles count 0 {}
}
# xl/theme/theme1.xml
set doc [set obj(doc,xl/theme/theme1.xml) [dom createDocument a:theme]]
set root [$doc documentElement]
dom createNodeCmd -tagName a:accent1 elementNode Tag_a:accent1
dom createNodeCmd -tagName a:accent2 elementNode Tag_a:accent2
dom createNodeCmd -tagName a:accent3 elementNode Tag_a:accent3
dom createNodeCmd -tagName a:accent4 elementNode Tag_a:accent4
dom createNodeCmd -tagName a:accent5 elementNode Tag_a:accent5
dom createNodeCmd -tagName a:accent6 elementNode Tag_a:accent6
dom createNodeCmd -tagName a:alpha elementNode Tag_a:alpha
dom createNodeCmd -tagName a:bevelT elementNode Tag_a:bevelT
dom createNodeCmd -tagName a:bgFillStyleLst elementNode Tag_a:bgFillStyleLst
dom createNodeCmd -tagName a:bodyPr elementNode Tag_a:bodyPr
dom createNodeCmd -tagName a:camera elementNode Tag_a:camera
dom createNodeCmd -tagName a:clrScheme elementNode Tag_a:clrScheme
dom createNodeCmd -tagName a:cs elementNode Tag_a:cs
dom createNodeCmd -tagName a:dk1 elementNode Tag_a:dk1
dom createNodeCmd -tagName a:dk2 elementNode Tag_a:dk2
dom createNodeCmd -tagName a:ea elementNode Tag_a:ea
dom createNodeCmd -tagName a:effectLst elementNode Tag_a:effectLst
dom createNodeCmd -tagName a:effectRef elementNode Tag_a:effectRef
dom createNodeCmd -tagName a:effectStyle elementNode Tag_a:effectStyle
dom createNodeCmd -tagName a:effectStyleLst elementNode Tag_a:effectStyleLst
dom createNodeCmd -tagName a:extraClrSchemeLst elementNode Tag_a:extraClrSchemeLst
dom createNodeCmd -tagName a:fillRef elementNode Tag_a:fillRef
dom createNodeCmd -tagName a:fillStyleLst elementNode Tag_a:fillStyleLst
dom createNodeCmd -tagName a:fillToRect elementNode Tag_a:fillToRect
dom createNodeCmd -tagName a:fmtScheme elementNode Tag_a:fmtScheme
dom createNodeCmd -tagName a:folHlink elementNode Tag_a:folHlink
dom createNodeCmd -tagName a:font elementNode Tag_a:font
dom createNodeCmd -tagName a:fontRef elementNode Tag_a:fontRef
dom createNodeCmd -tagName a:fontScheme elementNode Tag_a:fontScheme
dom createNodeCmd -tagName a:gradFill elementNode Tag_a:gradFill
dom createNodeCmd -tagName a:gs elementNode Tag_a:gs
dom createNodeCmd -tagName a:gsLst elementNode Tag_a:gsLst
dom createNodeCmd -tagName a:hlink elementNode Tag_a:hlink
dom createNodeCmd -tagName a:latin elementNode Tag_a:latin
dom createNodeCmd -tagName a:lightRig elementNode Tag_a:lightRig
dom createNodeCmd -tagName a:lin elementNode Tag_a:lin
dom createNodeCmd -tagName a:ln elementNode Tag_a:ln
dom createNodeCmd -tagName a:lnDef elementNode Tag_a:lnDef
dom createNodeCmd -tagName a:lnRef elementNode Tag_a:lnRef
dom createNodeCmd -tagName a:lnStyleLst elementNode Tag_a:lnStyleLst
dom createNodeCmd -tagName a:lstStyle elementNode Tag_a:lstStyle
dom createNodeCmd -tagName a:lt1 elementNode Tag_a:lt1
dom createNodeCmd -tagName a:lt2 elementNode Tag_a:lt2
dom createNodeCmd -tagName a:majorFont elementNode Tag_a:majorFont
dom createNodeCmd -tagName a:minorFont elementNode Tag_a:minorFont
dom createNodeCmd -tagName a:objectDefaults elementNode Tag_a:objectDefaults
dom createNodeCmd -tagName a:outerShdw elementNode Tag_a:outerShdw
dom createNodeCmd -tagName a:path elementNode Tag_a:path
dom createNodeCmd -tagName a:prstDash elementNode Tag_a:prstDash
dom createNodeCmd -tagName a:rot elementNode Tag_a:rot
dom createNodeCmd -tagName a:satMod elementNode Tag_a:satMod
dom createNodeCmd -tagName a:scene3d elementNode Tag_a:scene3d
dom createNodeCmd -tagName a:schemeClr elementNode Tag_a:schemeClr
dom createNodeCmd -tagName a:shade elementNode Tag_a:shade
dom createNodeCmd -tagName a:solidFill elementNode Tag_a:solidFill
dom createNodeCmd -tagName a:sp3d elementNode Tag_a:sp3d
dom createNodeCmd -tagName a:spDef elementNode Tag_a:spDef
dom createNodeCmd -tagName a:spPr elementNode Tag_a:spPr
dom createNodeCmd -tagName a:srgbClr elementNode Tag_a:srgbClr
dom createNodeCmd -tagName a:style elementNode Tag_a:style
dom createNodeCmd -tagName a:sysClr elementNode Tag_a:sysClr
dom createNodeCmd -tagName a:themeElements elementNode Tag_a:themeElements
dom createNodeCmd -tagName a:tint elementNode Tag_a:tint
$root setAttribute xmlns:a http://schemas.openxmlformats.org/drawingml/2006/main
$root setAttribute name Office-Design
$root appendFromScript {
Tag_a:themeElements {
Tag_a:clrScheme name Office {
Tag_a:dk1 {
Tag_a:sysClr val windowText lastClr 000000 {}
}
Tag_a:lt1 {
Tag_a:sysClr val window lastClr FFFFFF {}
}
Tag_a:dk2 {
Tag_a:srgbClr val 1F497D {}
}
Tag_a:lt2 {
Tag_a:srgbClr val EEECE1 {}
}
Tag_a:accent1 {
Tag_a:srgbClr val 4F81BD {}
}
Tag_a:accent2 {
Tag_a:srgbClr val C0504D {}
}
Tag_a:accent3 {
Tag_a:srgbClr val 9BBB59 {}
}
Tag_a:accent4 {
Tag_a:srgbClr val 8064A2 {}
}
Tag_a:accent5 {
Tag_a:srgbClr val 4BACC6 {}
}
Tag_a:accent6 {
Tag_a:srgbClr val F79646 {}
}
Tag_a:hlink {
Tag_a:srgbClr val 0000FF {}
}
Tag_a:folHlink {
Tag_a:srgbClr val 800080 {}
}
}
Tag_a:fontScheme name Office {
Tag_a:majorFont {
Tag_a:latin typeface Cambria {}
Tag_a:ea typeface {} {}
Tag_a:cs typeface {} {}
Tag_a:font script Jpan typeface \uFF2D\uFF33\u0020\uFF30\u30B4\u30B7\u30C3\u30AF {}
Tag_a:font script Hang typeface \uB9D1\uC740\u0020\uACE0\uB515 {}
Tag_a:font script Hans typeface \u5B8B\u4F53 {}
Tag_a:font script Hant typeface \u65B0\u7D30\u660E\u9AD4 {}
Tag_a:font script Arab typeface {Times New Roman} {}
Tag_a:font script Hebr typeface {Times New Roman} {}
Tag_a:font script Thai typeface Tahoma {}
Tag_a:font script Ethi typeface Nyala {}
Tag_a:font script Beng typeface Vrinda {}
Tag_a:font script Gujr typeface Shruti {}
Tag_a:font script Khmr typeface MoolBoran {}
Tag_a:font script Knda typeface Tunga {}
Tag_a:font script Guru typeface Raavi {}
Tag_a:font script Cans typeface Euphemia {}
Tag_a:font script Cher typeface {Plantagenet Cherokee} {}
Tag_a:font script Yiii typeface {Microsoft Yi Baiti} {}
Tag_a:font script Tibt typeface {Microsoft Himalaya} {}
Tag_a:font script Thaa typeface {MV Boli} {}
Tag_a:font script Deva typeface Mangal {}
Tag_a:font script Telu typeface Gautami {}
Tag_a:font script Taml typeface Latha {}
Tag_a:font script Syrc typeface {Estrangelo Edessa} {}
Tag_a:font script Orya typeface Kalinga {}
Tag_a:font script Mlym typeface Kartika {}
Tag_a:font script Laoo typeface DokChampa {}
Tag_a:font script Sinh typeface {Iskoola Pota} {}
Tag_a:font script Mong typeface {Mongolian Baiti} {}
Tag_a:font script Viet typeface {Times New Roman} {}
Tag_a:font script Uigh typeface {Microsoft Uighur} {}
Tag_a:font script Geor typeface Sylfaen {}
}
Tag_a:minorFont {
Tag_a:latin typeface Calibri {}
Tag_a:ea typeface {} {}
Tag_a:cs typeface {} {}
Tag_a:font script Jpan typeface \uFF2D\uFF33\u0020\uFF30\u30B4\u30B7\u30C3\u30AF {}
Tag_a:font script Hang typeface \uB9D1\uC740\u0020\uACE0\uB515 {}
Tag_a:font script Hans typeface \u5B8B\u4F53 {}
Tag_a:font script Hant typeface \u65B0\u7D30\u660E\u9AD4 {}
Tag_a:font script Arab typeface Arial {}
Tag_a:font script Hebr typeface Arial {}
Tag_a:font script Thai typeface Tahoma {}
Tag_a:font script Ethi typeface Nyala {}
Tag_a:font script Beng typeface Vrinda {}
Tag_a:font script Gujr typeface Shruti {}
Tag_a:font script Khmr typeface DaunPenh {}
Tag_a:font script Knda typeface Tunga {}
Tag_a:font script Guru typeface Raavi {}
Tag_a:font script Cans typeface Euphemia {}
Tag_a:font script Cher typeface {Plantagenet Cherokee} {}
Tag_a:font script Yiii typeface {Microsoft Yi Baiti} {}
Tag_a:font script Tibt typeface {Microsoft Himalaya} {}
Tag_a:font script Thaa typeface {MV Boli} {}
Tag_a:font script Deva typeface Mangal {}
Tag_a:font script Telu typeface Gautami {}
Tag_a:font script Taml typeface Latha {}
Tag_a:font script Syrc typeface {Estrangelo Edessa} {}
Tag_a:font script Orya typeface Kalinga {}
Tag_a:font script Mlym typeface Kartika {}
Tag_a:font script Laoo typeface DokChampa {}
Tag_a:font script Sinh typeface {Iskoola Pota} {}
Tag_a:font script Mong typeface {Mongolian Baiti} {}
Tag_a:font script Viet typeface Arial {}
Tag_a:font script Uigh typeface {Microsoft Uighur} {}
Tag_a:font script Geor typeface Sylfaen {}
}
}
Tag_a:fmtScheme name Office {
Tag_a:fillStyleLst {
Tag_a:solidFill {
Tag_a:schemeClr val phClr {}
}
Tag_a:gradFill rotWithShape 1 {
Tag_a:gsLst {
Tag_a:gs pos 0 {
Tag_a:schemeClr val phClr {
Tag_a:tint val 50000 {}
Tag_a:satMod val 300000 {}
}
}
Tag_a:gs pos 35000 {
Tag_a:schemeClr val phClr {
Tag_a:tint val 37000 {}
Tag_a:satMod val 300000 {}
}
}
Tag_a:gs pos 100000 {
Tag_a:schemeClr val phClr {
Tag_a:tint val 15000 {}
Tag_a:satMod val 350000 {}
}
}
}
Tag_a:lin ang 16200000 scaled 1 {}
}
Tag_a:gradFill rotWithShape 1 {
Tag_a:gsLst {
Tag_a:gs pos 0 {
Tag_a:schemeClr val phClr {
Tag_a:tint val 100000 {}
Tag_a:shade val 100000 {}
Tag_a:satMod val 130000 {}
}
}
Tag_a:gs pos 100000 {
Tag_a:schemeClr val phClr {
Tag_a:tint val 50000 {}
Tag_a:shade val 100000 {}
Tag_a:satMod val 350000 {}
}
}
}
Tag_a:lin ang 16200000 scaled 0 {}
}
}
Tag_a:lnStyleLst {
Tag_a:ln w 9525 cap flat cmpd sng algn ctr {
Tag_a:solidFill {
Tag_a:schemeClr val phClr {
Tag_a:shade val 95000 {
}
Tag_a:satMod val 105000 {
}
}
}
Tag_a:prstDash val solid {}
}
Tag_a:ln w 25400 cap flat cmpd sng algn ctr {
Tag_a:solidFill {
Tag_a:schemeClr val phClr {}
}
Tag_a:prstDash val solid {}
}
Tag_a:ln w 38100 cap flat cmpd sng algn ctr {
Tag_a:solidFill {
Tag_a:schemeClr val phClr {}
}
Tag_a:prstDash val solid {}
}
}
Tag_a:effectStyleLst {
Tag_a:effectStyle {
Tag_a:effectLst {
Tag_a:outerShdw blurRad 40000 dist 20000 dir 5400000 rotWithShape 0 {
Tag_a:srgbClr val 000000 {
Tag_a:alpha val 38000 {}
}
}
}
}
Tag_a:effectStyle {
Tag_a:effectLst {
Tag_a:outerShdw blurRad 40000 dist 23000 dir 5400000 rotWithShape 0 {
Tag_a:srgbClr val 000000 {
Tag_a:alpha val 35000 {}
}
}
}
}
Tag_a:effectStyle {
Tag_a:effectLst {
Tag_a:outerShdw blurRad 40000 dist 23000 dir 5400000 rotWithShape 0 {
Tag_a:srgbClr val 000000 {
Tag_a:alpha val 35000 {}
}
}
}
Tag_a:scene3d {
Tag_a:camera prst orthographicFront {
Tag_a:rot lat 0 lon 0 rev 0 {
}
}
Tag_a:lightRig rig threePt dir t {
Tag_a:rot lat 0 lon 0 rev 1200000 {
}
}
}
Tag_a:sp3d {
Tag_a:bevelT w 63500 h 25400 {}
}
}
}
Tag_a:bgFillStyleLst {
Tag_a:solidFill {
Tag_a:schemeClr val phClr {}
}
Tag_a:gradFill rotWithShape 1 {
Tag_a:gsLst {
Tag_a:gs pos 0 {
Tag_a:schemeClr val phClr {
Tag_a:tint val 40000 {}
Tag_a:satMod val 350000 {}
}
}
Tag_a:gs pos 40000 {
Tag_a:schemeClr val phClr {
Tag_a:tint val 45000 {}
Tag_a:shade val 99000 {}
Tag_a:satMod val 350000 {}
}
}
Tag_a:gs pos 100000 {
Tag_a:schemeClr val phClr {
Tag_a:shade val 20000 {}
Tag_a:satMod val 255000 {}
}
}
}
Tag_a:path path circle {
Tag_a:fillToRect l 50000 t -80000 r 50000 b 180000 {}
}
}
Tag_a:gradFill rotWithShape 1 {
Tag_a:gsLst {
Tag_a:gs pos 0 {
Tag_a:schemeClr val phClr {
Tag_a:tint val 80000 {}
Tag_a:satMod val 300000 {}
}
}
Tag_a:gs pos 100000 {
Tag_a:schemeClr val phClr {
Tag_a:shade val 30000 {}
Tag_a:satMod val 200000 {}
}
}
}
Tag_a:path path circle {
Tag_a:fillToRect l 50000 t 50000 r 50000 b 50000 {}
}
}
}
}
}
Tag_a:objectDefaults {
Tag_a:spDef {
Tag_a:spPr {}
Tag_a:bodyPr {}
Tag_a:lstStyle {}
Tag_a:style {
Tag_a:lnRef idx 1 {
Tag_a:schemeClr val accent1 {}
}
Tag_a:fillRef idx 3 {
Tag_a:schemeClr val accent1 {}
}
Tag_a:effectRef idx 2 {
Tag_a:schemeClr val accent1 {}
}
Tag_a:fontRef idx minor {
Tag_a:schemeClr val lt1 {}
}
}
}
Tag_a:lnDef {
Tag_a:spPr {}
Tag_a:bodyPr {}
Tag_a:lstStyle {}
Tag_a:style {
Tag_a:lnRef idx 2 {
Tag_a:schemeClr val accent1 {}
}
Tag_a:fillRef idx 0 {
Tag_a:schemeClr val accent1 {}
}
Tag_a:effectRef idx 1 {
Tag_a:schemeClr val accent1 {}
}
Tag_a:fontRef idx minor {
Tag_a:schemeClr val tx1 {}
}
}
}
}
Tag_a:extraClrSchemeLst {}
}
# xl/workbook.xml
set doc [set obj(doc,xl/workbook.xml) [dom createDocument workbook]]
set root [$doc documentElement]
dom createNodeCmd textNode Text
dom createNodeCmd -tagName bookViews elementNode Tag_bookViews
dom createNodeCmd -tagName calcPr elementNode Tag_calcPr
dom createNodeCmd -tagName definedName elementNode Tag_definedName
dom createNodeCmd -tagName definedNames elementNode Tag_definedNames
dom createNodeCmd -tagName fileVersion elementNode Tag_fileVersion
dom createNodeCmd -tagName sheet elementNode Tag_sheet
dom createNodeCmd -tagName sheets elementNode Tag_sheets
dom createNodeCmd -tagName workbookPr elementNode Tag_workbookPr
dom createNodeCmd -tagName workbookView elementNode Tag_workbookView
$root setAttribute xmlns http://schemas.openxmlformats.org/spreadsheetml/2006/main
$root setAttribute xmlns:r http://schemas.openxmlformats.org/officeDocument/2006/relationships
$root appendFromScript {
Tag_fileVersion appName xl lastEdited 5 lowestEdited 5 rupBuild 5000 {}
Tag_workbookPr showInkAnnotation 0 autoCompressPictures 0 {}
Tag_bookViews {
Tag_workbookView activeTab 1 {}
}
Tag_sheets {
for {set ws 1} {$ws <= $obj(sheets)} {incr ws} {
Tag_sheet name $obj(sheet,$ws) sheetId $ws r:id rId$ws {}
}
}
if {0} {
Tag_definedNames {
Tag_definedName name _xlnm._FilterDatabase localSheetId 0 hidden 1 { Text Blatt1!$A$1:$C$1 }
}
}
Tag_calcPr calcId 140000 concurrentCalc 0 {}
# fullCalcOnLoad 1
}
# xl/worksheets/sheet1.xml SHEET
dom createNodeCmd textNode Text
dom createNodeCmd -tagName autoFilter elementNode Tag_autoFilter
dom createNodeCmd -tagName c elementNode Tag_c
dom createNodeCmd -tagName col elementNode Tag_col
dom createNodeCmd -tagName cols elementNode Tag_cols
dom createNodeCmd -tagName dimension elementNode Tag_dimension
dom createNodeCmd -tagName mergeCell elementNode Tag_mergeCell
dom createNodeCmd -tagName mergeCells elementNode Tag_mergeCells
dom createNodeCmd -tagName pageMargins elementNode Tag_pageMargins
dom createNodeCmd -tagName pane elementNode Tag_pane
dom createNodeCmd -tagName row elementNode Tag_row
dom createNodeCmd -tagName sheetData elementNode Tag_sheetData
dom createNodeCmd -tagName sheetFormatPr elementNode Tag_sheetFormatPr
dom createNodeCmd -tagName sheetView elementNode Tag_sheetView
dom createNodeCmd -tagName sheetViews elementNode Tag_sheetViews
dom createNodeCmd -tagName v elementNode Tag_v
for {set ws 1} {$ws <= $obj(sheets)} {incr ws} {
set doc [set obj(doc,xl/worksheets/sheet$ws.xml) [dom createDocument worksheet]]
set root [$doc documentElement]
$root setAttribute xmlns http://schemas.openxmlformats.org/spreadsheetml/2006/main
$root setAttribute xmlns:r http://schemas.openxmlformats.org/officeDocument/2006/relationships
$root setAttribute xmlns:mc http://schemas.openxmlformats.org/markup-compatibility/2006
$root setAttribute xmlns:x14ac http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac
$root setAttribute mc:Ignorable x14ac
$root appendFromScript {
Tag_dimension ref [::ooxml::RowColumnToString $obj(dminrow,$ws),$obj(dmincol,$ws)]:[::ooxml::RowColumnToString $obj(dmaxrow,$ws),$obj(dmaxcol,$ws)] {}
Tag_sheetViews {
Tag_sheetView workbookViewId 0 {
if {$obj(freeze,$ws) ne {}} {
lassign [split [::ooxml::StringToRowColumn $obj(freeze,$ws)] ,] row col
Tag_pane xSplit $col ySplit $row topLeftCell $obj(freeze,$ws) state frozen {}
}
}
}
Tag_sheetFormatPr baseColWidth 10 defaultRowHeight 16 x14ac:dyDescent 0.2 {}
if {[info exists obj($ws,cols)] && $obj($ws,cols) > 0} {
Tag_cols {}
}
Tag_sheetData {
set lastRow -1
set rows {}
foreach idx [lsort -dictionary [array names cells $ws,*,*]] {
lassign [split $idx ,] sheet row col
lappend rows $row
}
foreach row [lsort -unique -integer $rows] {
set maxCol $col
if {$row != $lastRow} {
set lastRow $row
set minCol $col
}
set attr {}
if {[dict exists $obj(rowHeight,$ws) $row]} {
lappend attr ht [dict get $obj(rowHeight,$ws) $row] customHeight 1
}
# lappend attr spans [expr {$minCol + 1}]:[expr {$maxCol + 1}]
Tag_row r [expr {$row + 1}] {*}$attr {
foreach idx [lsort -dictionary [array names cells $ws,$row,*]] {
lassign [split $idx ,] sheet row col
if {([dict exists $cells($idx) v] && [string trim [dict get $cells($idx) v]] ne {}) || ([dict exists $cells($idx) f] && [string trim [dict get $cells($idx) f]] ne {})} {
set attr {}
if {[dict exists $cells($idx) s] && [dict get $cells($idx) s] > 0} {
lappend attr s [dict get $cells($idx) s]
}
if {[dict exists $cells($idx) t] && [dict get $cells($idx) t] ne {n}} {
lappend attr t [dict get $cells($idx) t]
}
Tag_c r [::ooxml::RowColumnToString $row,$col] {*}$attr {
if {[dict exists $cells($idx) v] && [dict get $cells($idx) v] ne {}} {
Tag_v { Text [dict get $cells($idx) v] }
}
if {[dict exists $cells($idx) f] && [dict get $cells($idx) f] ne {}} {
Tag_f { Text [dict get $cells($idx) f] }
}
}
} elseif {[dict exists $cells($idx) s] && [string is integer -strict [dict get $cells($idx) s]] && [dict get $cells($idx) s] > 0} {
Tag_c r [::ooxml::RowColumnToString $row,$col] s [dict get $cells($idx) s] {}
}
}
}
}
}
if {$obj(autofilter,$ws) ne {}} {
Tag_autoFilter ref $obj(autofilter,$ws) {}
}
if {[info exists obj(merge,$ws)] && $obj(merge,$ws) ne {}} {
Tag_mergeCells count [llength $obj(merge,$ws)] {
foreach item $obj(merge,$ws) {
Tag_mergeCell ref $item {}
}
}
}
Tag_pageMargins left 0.75 right 0.75 top 1 bottom 1 header 0.5 footer 0.5 {}
}
if {[set colsNode [$root selectNodes {/worksheet/cols}]] ne {}} {
if {[info exists obj($ws,cols)] && $obj($ws,cols) > 0} {
$colsNode appendFromScript {
foreach idx [lsort -dictionary [array names cols $ws,*]] {
set attr {}
lappend attr min [expr {[dict get $cols($idx) min] + 1}] max [expr {[dict get $cols($idx) max] + 1}]
if {[dict get $cols($idx) width] ne {}} {
lappend attr width [dict get $cols($idx) width]
if {[dict get $cols($idx) width] != $::ooxml::defaults(cols,width)} {
dict set $cols($idx) customwidth 1
}
}
if {[dict get $cols($idx) style] ne {} && [dict get $cols($idx) style] > 0} {
lappend attr style [dict get $cols($idx) style]
}
if {[dict get $cols($idx) bestfit] == 1} {
lappend attr bestFit [dict get $cols($idx) bestfit]
}
if {[dict get $cols($idx) customwidth] == 1} {
lappend attr customWidth [dict get $cols($idx) customwidth]
}
Tag_col {*}$attr {}
}
}
}
}
}
# Content-Type application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
set file [string trim $file]
if {$file eq {}} {
set file {spreadsheetml.xlsx}
}
if {[file extension $file] ne {.xlsx}} {
append file {.xlsx}
}
set path [file dirname $file]
set uid [format xl_%X [clock microseconds]]
set filesToZip {}
foreach {tag doc} [array get obj doc,*] {
lappend filesToZip [set docname [lindex [split $tag ,] 1]]
set xmlfile [file join $path $uid $docname]
file mkdir [file dirname $xmlfile]
if {![catch {open $xmlfile w} fd]} {
fconfigure $fd -encoding utf-8
#puts $fd "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
puts $fd [[$doc documentElement] asXML -indent $obj(indent) -xmlDeclaration 1 -encString [string toupper $obj(encoding)]]
close $fd
$doc delete
}
}
set pwd [pwd]
cd [file join $path $uid]
if {$path eq {.}} {
set file [file join .. $file]
}
::ooxml::Zip $file . $filesToZip
cd $pwd
if {!$opts(holdcontainerdirectory)} {
file delete -force [file join $path $uid]
}
return 0
}
}
#
# ooxml::tablelist_to_xl
#
proc ::ooxml::tablelist_to_xl { lb args } {
variable defaults
if {![winfo exists $lb]} {
tk_messageBox -message [msgcat::mc {Tablelist does not exists!}]
return
}
if {[::ooxml::Getopt opts [list callback.arg {::ooxml::tablelist_to_xl_callback} path.arg $defaults(path) file.arg {tablelist.xlsx} creator.arg {unknown} name.arg {Tablelist1} rootonly addtimestamp] $args]} {
error $opts(-errmsg)
}
if {[string trim $opts(path)] eq {}} {
set opts(path) {.}
}
if {[string trim $opts(file)] eq {}} {
set opts(file) {tablelist.xlsx}
}
if {[file extension $opts(file)] eq {.xlsx}} {
set opts(file) [file tail [file rootname $opts(file)]]
}
if {$opts(addtimestamp)} {
append opts(file) _[clock format [clock seconds] -format %Y%m%dT%H%M%S]
}
append opts(file) {.xlsx}
set file [tk_getSaveFile -confirmoverwrite 1 -filetypes {{{Excel Office Open XML} {.xlsx}}} -initialdir $opts(path) -initialfile $opts(file) -parent . -title "Excel Office Open XML"]
if {$file eq {}} {
tk_messageBox -message [msgcat::mc {No file selected!}]
return
}
set spreadsheet [::ooxml::xl_write new -creator $opts(creator)]
if {[set sheet [$spreadsheet worksheet $opts(name)]] > -1} {
set columncount [expr {[$lb columncount] - 1}]
if {$columncount > 0} {
$spreadsheet autofilter $sheet 0,0 0,$columncount
}
set titlecolumns [$lb cget -titlecolumns]
if {$titlecolumns > 0} {
$spreadsheet freeze $sheet 1,$titlecolumns
}
set col -1
set title SETUP
set width 0
set align {}
set sortmode {}
set hide 1
$opts(callback) $spreadsheet $sheet $columncount $col $title $width $align $sortmode $hide
$spreadsheet row $sheet
for {set col 0} {$col <= $columncount} {incr col} {
set title [$lb columncget $col -title]
set width [$lb columncget $col -width]
set align [$lb columncget $col -align]
set sortmode [$lb columncget $col -sortmode]
set hide [$lb columncget $col -hide]
if {[info commands $opts(callback)] eq $opts(callback)} {
$opts(callback) $spreadsheet $sheet $columncount $col $title $width $align $sortmode $hide
}
$spreadsheet cell $sheet $title
}
if {$opts(rootonly)} {
foreach row [$lb get [$lb childkeys root]] {
$spreadsheet row $sheet
set idx 0
foreach col $row {
if {[string trim $col] ne {}} {
$spreadsheet cell $sheet $col -index $idx
}
incr idx
}
}
} else {
foreach row [$lb get 0 end] {
$spreadsheet row $sheet
set idx 0
foreach col $row {
if {[string trim $col] ne {}} {
$spreadsheet cell $sheet $col -index $idx
}
incr idx
}
}
}
$spreadsheet write $file
}
}
proc ::ooxml::tablelist_to_xl_callback { spreadsheet sheet maxcol column title width align sortmode hide } {
set left 0
set center [$spreadsheet style -horizontal center]
set right [$spreadsheet style -horizontal right]
set date [$spreadsheet style -numfmt [$spreadsheet numberformat -datetime]]
set decimal [$spreadsheet style -numfmt [$spreadsheet numberformat -decimal -red]]
set text [$spreadsheet style -numfmt [$spreadsheet numberformat -string]]
if {$column == -1} {
$spreadsheet defaultdatestyle $date
} else {
switch -- $align {
center {
$spreadsheet column $sheet -index $column -style $center
}
right {
$spreadsheet column $sheet -index $column -style $right
}
default {
$spreadsheet column $sheet -index $column -style $left
}
}
}
}
package provide ooxml 1.1