-
Notifications
You must be signed in to change notification settings - Fork 820
/
xmlWorkbook.go
228 lines (203 loc) · 8.53 KB
/
xmlWorkbook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
package xlsx
import (
"archive/zip"
"encoding/xml"
"fmt"
"io"
)
const (
// sheet state values as defined by
// http://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.sheetstatevalues.aspx
sheetStateVisible = "visible"
sheetStateHidden = "hidden"
sheetStateVeryHidden = "veryHidden"
)
// xmlxWorkbookRels contains xmlxWorkbookRelations
// which maps sheet id and sheet XML
type xlsxWorkbookRels struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`
Relationships []xlsxWorkbookRelation `xml:"Relationship"`
}
// xmlxWorkbookRelation maps sheet id and xl/worksheets/sheet%d.xml
type xlsxWorkbookRelation struct {
Id string `xml:",attr"`
Target string `xml:",attr"`
Type string `xml:",attr"`
}
// xlsxWorkbook directly maps the workbook element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
// currently I have not checked it for completeness - it does as much
// as I need.
type xlsxWorkbook struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main workbook"`
FileVersion xlsxFileVersion `xml:"fileVersion"`
WorkbookPr xlsxWorkbookPr `xml:"workbookPr"`
WorkbookProtection xlsxWorkbookProtection `xml:"workbookProtection"`
BookViews xlsxBookViews `xml:"bookViews"`
Sheets xlsxSheets `xml:"sheets"`
DefinedNames xlsxDefinedNames `xml:"definedNames"`
CalcPr xlsxCalcPr `xml:"calcPr"`
}
// xlsxWorkbookProtection directly maps the workbookProtection element from the
// namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main
// - currently I have not checked it for completeness - it does as
// much as I need.
type xlsxWorkbookProtection struct {
// We don't need this, yet.
}
// xlsxFileVersion directly maps the fileVersion element from the
// namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main
// - currently I have not checked it for completeness - it does as
// much as I need.
type xlsxFileVersion struct {
AppName string `xml:"appName,attr,omitempty"`
LastEdited string `xml:"lastEdited,attr,omitempty"`
LowestEdited string `xml:"lowestEdited,attr,omitempty"`
RupBuild string `xml:"rupBuild,attr,omitempty"`
}
// xlsxWorkbookPr directly maps the workbookPr element from the
// namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main
// - currently I have not checked it for completeness - it does as
// much as I need.
type xlsxWorkbookPr struct {
DefaultThemeVersion string `xml:"defaultThemeVersion,attr,omitempty"`
BackupFile bool `xml:"backupFile,attr,omitempty"`
ShowObjects string `xml:"showObjects,attr,omitempty"`
Date1904 bool `xml:"date1904,attr"`
}
// xlsxBookViews directly maps the bookViews element from the
// namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main
// - currently I have not checked it for completeness - it does as
// much as I need.
type xlsxBookViews struct {
WorkBookView []xlsxWorkBookView `xml:"workbookView"`
}
// xlsxWorkBookView directly maps the workbookView element from the
// namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main
// - currently I have not checked it for completeness - it does as
// much as I need.
type xlsxWorkBookView struct {
ActiveTab int `xml:"activeTab,attr,omitempty"`
FirstSheet int `xml:"firstSheet,attr,omitempty"`
ShowHorizontalScroll bool `xml:"showHorizontalScroll,attr,omitempty"`
ShowVerticalScroll bool `xml:"showVerticalScroll,attr,omitempty"`
ShowSheetTabs bool `xml:"showSheetTabs,attr,omitempty"`
TabRatio int `xml:"tabRatio,attr,omitempty"`
WindowHeight int `xml:"windowHeight,attr,omitempty"`
WindowWidth int `xml:"windowWidth,attr,omitempty"`
XWindow string `xml:"xWindow,attr,omitempty"`
YWindow string `xml:"yWindow,attr,omitempty"`
}
// xlsxSheets directly maps the sheets element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
// currently I have not checked it for completeness - it does as much
// as I need.
type xlsxSheets struct {
Sheet []xlsxSheet `xml:"sheet"`
}
// xlsxSheet directly maps the sheet element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
// currently I have not checked it for completeness - it does as much
// as I need.
type xlsxSheet struct {
Name string `xml:"name,attr,omitempty"`
SheetId string `xml:"sheetId,attr,omitempty"`
Id string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"`
State string `xml:"state,attr,omitempty"`
}
// xlsxDefinedNames directly maps the definedNames element from the
// namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main
// - currently I have not checked it for completeness - it does as
// much as I need.
type xlsxDefinedNames struct {
DefinedName []xlsxDefinedName `xml:"definedName"`
}
// xlsxDefinedName directly maps the definedName element from the
// namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main
// - currently I have not checked it for completeness - it does as
// much as I need.
// for a descriptions of the attributes see
// https://msdn.microsoft.com/en-us/library/office/documentformat.openxml.spreadsheet.definedname.aspx
type xlsxDefinedName struct {
Data string `xml:",chardata"`
Name string `xml:"name,attr"`
Comment string `xml:"comment,attr,omitempty"`
CustomMenu string `xml:"customMenu,attr,omitempty"`
Description string `xml:"description,attr,omitempty"`
Help string `xml:"help,attr,omitempty"`
ShortcutKey string `xml:"shortcutKey,attr,omitempty"`
StatusBar string `xml:"statusBar,attr,omitempty"`
LocalSheetID int `xml:"localSheetId,attr"`
FunctionGroupID int `xml:"functionGroupId,attr,omitempty"`
Function bool `xml:"function,attr,omitempty"`
Hidden bool `xml:"hidden,attr,omitempty"`
VbProcedure bool `xml:"vbProcedure,attr,omitempty"`
PublishToServer bool `xml:"publishToServer,attr,omitempty"`
WorkbookParameter bool `xml:"workbookParameter,attr,omitempty"`
Xlm bool `xml:"xml,attr,omitempty"`
}
// xlsxCalcPr directly maps the calcPr element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
// currently I have not checked it for completeness - it does as much
// as I need.
type xlsxCalcPr struct {
CalcId string `xml:"calcId,attr,omitempty"`
IterateCount int `xml:"iterateCount,attr,omitempty"`
RefMode string `xml:"refMode,attr,omitempty"`
Iterate bool `xml:"iterate,attr,omitempty"`
IterateDelta float64 `xml:"iterateDelta,attr,omitempty"`
}
// Helper function to lookup the file corresponding to a xlsxSheet object in the worksheets map
func worksheetFileForSheet(sheet xlsxSheet, worksheets map[string]*zip.File, sheetXMLMap map[string]string) *zip.File {
sheetName, ok := sheetXMLMap[sheet.Id]
if !ok {
if sheet.SheetId != "" {
sheetName = fmt.Sprintf("sheet%s", sheet.SheetId)
} else {
sheetName = fmt.Sprintf("sheet%s", sheet.Id)
}
}
return worksheets[sheetName]
}
// getWorksheetFromSheet() is an internal helper function to open a
// sheetN.xml file, referred to by an xlsx.xlsxSheet struct, from the XLSX
// file and unmarshal it an xlsx.xlsxWorksheet struct
func getWorksheetFromSheet(sheet xlsxSheet, worksheets map[string]*zip.File, sheetXMLMap map[string]string, rowLimit int, valueOnly bool) (*xlsxWorksheet, error) {
var r io.Reader
var decoder *xml.Decoder
var worksheet *xlsxWorksheet
var err error
wrap := func(err error) (*xlsxWorksheet, error) {
return nil, fmt.Errorf("getWorksheetFromSheet: %w", err)
}
worksheet = new(xlsxWorksheet)
f := worksheetFileForSheet(sheet, worksheets, sheetXMLMap)
if f == nil {
return wrap(fmt.Errorf("unable to find sheet '%s'", sheet))
}
if rc, err := f.Open(); err != nil {
return wrap(fmt.Errorf("file.Open: %w", err))
} else {
defer rc.Close()
r = rc
}
if rowLimit != NoRowLimit {
r, err = truncateSheetXML(r, rowLimit)
if err != nil {
return wrap(err)
}
}
if valueOnly {
r, err = truncateSheetXMLValueOnly(r)
if err != nil {
return wrap(err)
}
}
decoder = xml.NewDecoder(r)
err = decoder.Decode(worksheet)
if err != nil {
return wrap(fmt.Errorf("xml.Decoder.Decode: %w", err))
}
worksheet.mapMergeCells()
return worksheet, nil
}