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
|
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,omitempty"`
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) (*xlsxWorksheet, error) {
var r io.Reader
var decoder *xml.Decoder
var worksheet *xlsxWorksheet
var err error
worksheet = new(xlsxWorksheet)
f := worksheetFileForSheet(sheet, worksheets, sheetXMLMap)
if f == nil {
return nil, fmt.Errorf("Unable to find sheet '%s'", sheet)
}
if rc, err := f.Open(); err != nil {
return nil, err
} else {
defer rc.Close()
r = rc
}
if rowLimit != NoRowLimit {
r, err = truncateSheetXML(r, rowLimit)
if err != nil {
return nil, err
}
}
decoder = xml.NewDecoder(r)
err = decoder.Decode(worksheet)
if err != nil {
return nil, err
}
return worksheet, nil
}
|