file.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. package xlsx
  2. import (
  3. "archive/zip"
  4. "bytes"
  5. "encoding/xml"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "os"
  10. "strconv"
  11. "strings"
  12. )
  13. // File is a high level structure providing a slice of Sheet structs
  14. // to the user.
  15. type File struct {
  16. worksheets map[string]*zip.File
  17. referenceTable *RefTable
  18. Date1904 bool
  19. styles *xlsxStyleSheet
  20. Sheets []*Sheet
  21. Sheet map[string]*Sheet
  22. theme *theme
  23. DefinedNames []*xlsxDefinedName
  24. }
  25. const NoRowLimit int = -1
  26. // Create a new File
  27. func NewFile() *File {
  28. return &File{
  29. Sheet: make(map[string]*Sheet),
  30. Sheets: make([]*Sheet, 0),
  31. DefinedNames: make([]*xlsxDefinedName, 0),
  32. }
  33. }
  34. // OpenFile() take the name of an XLSX file and returns a populated
  35. // xlsx.File struct for it.
  36. func OpenFile(fileName string) (file *File, err error) {
  37. return OpenFileWithRowLimit(fileName, NoRowLimit)
  38. }
  39. // OpenFileWithRowLimit() will open the file, but will only read the specified number of rows.
  40. // If you save this file, it will be truncated to the number of rows specified.
  41. func OpenFileWithRowLimit(fileName string, rowLimit int) (file *File, err error) {
  42. var z *zip.ReadCloser
  43. z, err = zip.OpenReader(fileName)
  44. if err != nil {
  45. return nil, err
  46. }
  47. return ReadZipWithRowLimit(z, rowLimit)
  48. }
  49. // OpenBinary() take bytes of an XLSX file and returns a populated
  50. // xlsx.File struct for it.
  51. func OpenBinary(bs []byte) (*File, error) {
  52. return OpenBinaryWithRowLimit(bs, NoRowLimit)
  53. }
  54. // OpenBinaryWithRowLimit() take bytes of an XLSX file and returns a populated
  55. // xlsx.File struct for it.
  56. func OpenBinaryWithRowLimit(bs []byte, rowLimit int) (*File, error) {
  57. r := bytes.NewReader(bs)
  58. return OpenReaderAtWithRowLimit(r, int64(r.Len()), rowLimit)
  59. }
  60. // OpenReaderAt() take io.ReaderAt of an XLSX file and returns a populated
  61. // xlsx.File struct for it.
  62. func OpenReaderAt(r io.ReaderAt, size int64) (*File, error) {
  63. return OpenReaderAtWithRowLimit(r, size, NoRowLimit)
  64. }
  65. // OpenReaderAtWithRowLimit() take io.ReaderAt of an XLSX file and returns a populated
  66. // xlsx.File struct for it.
  67. func OpenReaderAtWithRowLimit(r io.ReaderAt, size int64, rowLimit int) (*File, error) {
  68. file, err := zip.NewReader(r, size)
  69. if err != nil {
  70. return nil, err
  71. }
  72. return ReadZipReaderWithRowLimit(file, rowLimit)
  73. }
  74. // A convenient wrapper around File.ToSlice, FileToSlice will
  75. // return the raw data contained in an Excel XLSX file as three
  76. // dimensional slice. The first index represents the sheet number,
  77. // the second the row number, and the third the cell number.
  78. //
  79. // For example:
  80. //
  81. // var mySlice [][][]string
  82. // var value string
  83. // mySlice = xlsx.FileToSlice("myXLSX.xlsx")
  84. // value = mySlice[0][0][0]
  85. //
  86. // Here, value would be set to the raw value of the cell A1 in the
  87. // first sheet in the XLSX file.
  88. func FileToSlice(path string) ([][][]string, error) {
  89. f, err := OpenFile(path)
  90. if err != nil {
  91. return nil, err
  92. }
  93. return f.ToSlice()
  94. }
  95. // FileToSliceUnmerged is a wrapper around File.ToSliceUnmerged.
  96. // It returns the raw data contained in an Excel XLSX file as three
  97. // dimensional slice. Merged cells will be unmerged. Covered cells become the
  98. // values of theirs origins.
  99. func FileToSliceUnmerged(path string) ([][][]string, error) {
  100. f, err := OpenFile(path)
  101. if err != nil {
  102. return nil, err
  103. }
  104. return f.ToSliceUnmerged()
  105. }
  106. // Save the File to an xlsx file at the provided path.
  107. func (f *File) Save(path string) (err error) {
  108. target, err := os.Create(path)
  109. if err != nil {
  110. return err
  111. }
  112. err = f.Write(target)
  113. if err != nil {
  114. return err
  115. }
  116. return target.Close()
  117. }
  118. // Write the File to io.Writer as xlsx
  119. func (f *File) Write(writer io.Writer) (err error) {
  120. parts, err := f.MarshallParts()
  121. if err != nil {
  122. return
  123. }
  124. zipWriter := zip.NewWriter(writer)
  125. for partName, part := range parts {
  126. w, err := zipWriter.Create(partName)
  127. if err != nil {
  128. return err
  129. }
  130. _, err = w.Write([]byte(part))
  131. if err != nil {
  132. return err
  133. }
  134. }
  135. return zipWriter.Close()
  136. }
  137. // Add a new Sheet, with the provided name, to a File
  138. func (f *File) AddSheet(sheetName string) (*Sheet, error) {
  139. if _, exists := f.Sheet[sheetName]; exists {
  140. return nil, fmt.Errorf("duplicate sheet name '%s'.", sheetName)
  141. }
  142. if len(sheetName) >= 31 {
  143. return nil, fmt.Errorf("sheet name must be less than 31 characters long. It is currently '%d' characters long", len(sheetName))
  144. }
  145. sheet := &Sheet{
  146. Name: sheetName,
  147. File: f,
  148. Selected: len(f.Sheets) == 0,
  149. }
  150. f.Sheet[sheetName] = sheet
  151. f.Sheets = append(f.Sheets, sheet)
  152. return sheet, nil
  153. }
  154. // Appends an existing Sheet, with the provided name, to a File
  155. func (f *File) AppendSheet(sheet Sheet, sheetName string) (*Sheet, error) {
  156. if _, exists := f.Sheet[sheetName]; exists {
  157. return nil, fmt.Errorf("duplicate sheet name '%s'.", sheetName)
  158. }
  159. sheet.Name = sheetName
  160. sheet.File = f
  161. sheet.Selected = len(f.Sheets) == 0
  162. f.Sheet[sheetName] = &sheet
  163. f.Sheets = append(f.Sheets, &sheet)
  164. return &sheet, nil
  165. }
  166. func (f *File) makeWorkbook() xlsxWorkbook {
  167. return xlsxWorkbook{
  168. FileVersion: xlsxFileVersion{AppName: "Go XLSX"},
  169. WorkbookPr: xlsxWorkbookPr{ShowObjects: "all"},
  170. BookViews: xlsxBookViews{
  171. WorkBookView: []xlsxWorkBookView{
  172. {
  173. ShowHorizontalScroll: true,
  174. ShowSheetTabs: true,
  175. ShowVerticalScroll: true,
  176. TabRatio: 204,
  177. WindowHeight: 8192,
  178. WindowWidth: 16384,
  179. XWindow: "0",
  180. YWindow: "0",
  181. },
  182. },
  183. },
  184. Sheets: xlsxSheets{Sheet: make([]xlsxSheet, len(f.Sheets))},
  185. CalcPr: xlsxCalcPr{
  186. IterateCount: 100,
  187. RefMode: "A1",
  188. Iterate: false,
  189. IterateDelta: 0.001,
  190. },
  191. }
  192. }
  193. // Some tools that read XLSX files have very strict requirements about
  194. // the structure of the input XML. In particular both Numbers on the Mac
  195. // and SAS dislike inline XML namespace declarations, or namespace
  196. // prefixes that don't match the ones that Excel itself uses. This is a
  197. // problem because the Go XML library doesn't multiple namespace
  198. // declarations in a single element of a document. This function is a
  199. // horrible hack to fix that after the XML marshalling is completed.
  200. func replaceRelationshipsNameSpace(workbookMarshal string) string {
  201. newWorkbook := strings.Replace(workbookMarshal, `xmlns:relationships="http://schemas.openxmlformats.org/officeDocument/2006/relationships" relationships:id`, `r:id`, -1)
  202. // Dirty hack to fix issues #63 and #91; encoding/xml currently
  203. // "doesn't allow for additional namespaces to be defined in the
  204. // root element of the document," as described by @tealeg in the
  205. // comments for #63.
  206. oldXmlns := `<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`
  207. newXmlns := `<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">`
  208. return strings.Replace(newWorkbook, oldXmlns, newXmlns, 1)
  209. }
  210. // Construct a map of file name to XML content representing the file
  211. // in terms of the structure of an XLSX file.
  212. func (f *File) MarshallParts() (map[string]string, error) {
  213. var parts map[string]string
  214. var refTable *RefTable = NewSharedStringRefTable()
  215. refTable.isWrite = true
  216. var workbookRels WorkBookRels = make(WorkBookRels)
  217. var err error
  218. var workbook xlsxWorkbook
  219. var types xlsxTypes = MakeDefaultContentTypes()
  220. marshal := func(thing interface{}) (string, error) {
  221. body, err := xml.Marshal(thing)
  222. if err != nil {
  223. return "", err
  224. }
  225. return xml.Header + string(body), nil
  226. }
  227. parts = make(map[string]string)
  228. workbook = f.makeWorkbook()
  229. sheetIndex := 1
  230. if f.styles == nil {
  231. f.styles = newXlsxStyleSheet(f.theme)
  232. }
  233. f.styles.reset()
  234. if len(f.Sheets) == 0 {
  235. err := errors.New("Workbook must contains atleast one worksheet")
  236. return nil, err
  237. }
  238. for _, sheet := range f.Sheets {
  239. xSheet := sheet.makeXLSXSheet(refTable, f.styles)
  240. rId := fmt.Sprintf("rId%d", sheetIndex)
  241. sheetId := strconv.Itoa(sheetIndex)
  242. sheetPath := fmt.Sprintf("worksheets/sheet%d.xml", sheetIndex)
  243. partName := "xl/" + sheetPath
  244. types.Overrides = append(
  245. types.Overrides,
  246. xlsxOverride{
  247. PartName: "/" + partName,
  248. ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"})
  249. workbookRels[rId] = sheetPath
  250. workbook.Sheets.Sheet[sheetIndex-1] = xlsxSheet{
  251. Name: sheet.Name,
  252. SheetId: sheetId,
  253. Id: rId,
  254. State: "visible"}
  255. parts[partName], err = marshal(xSheet)
  256. if err != nil {
  257. return parts, err
  258. }
  259. sheetIndex++
  260. }
  261. workbookMarshal, err := marshal(workbook)
  262. if err != nil {
  263. return parts, err
  264. }
  265. workbookMarshal = replaceRelationshipsNameSpace(workbookMarshal)
  266. parts["xl/workbook.xml"] = workbookMarshal
  267. if err != nil {
  268. return parts, err
  269. }
  270. parts["_rels/.rels"] = TEMPLATE__RELS_DOT_RELS
  271. parts["docProps/app.xml"] = TEMPLATE_DOCPROPS_APP
  272. // TODO - do this properly, modification and revision information
  273. parts["docProps/core.xml"] = TEMPLATE_DOCPROPS_CORE
  274. parts["xl/theme/theme1.xml"] = TEMPLATE_XL_THEME_THEME
  275. xSST := refTable.makeXLSXSST()
  276. parts["xl/sharedStrings.xml"], err = marshal(xSST)
  277. if err != nil {
  278. return parts, err
  279. }
  280. xWRel := workbookRels.MakeXLSXWorkbookRels()
  281. parts["xl/_rels/workbook.xml.rels"], err = marshal(xWRel)
  282. if err != nil {
  283. return parts, err
  284. }
  285. parts["[Content_Types].xml"], err = marshal(types)
  286. if err != nil {
  287. return parts, err
  288. }
  289. parts["xl/styles.xml"], err = f.styles.Marshal()
  290. if err != nil {
  291. return parts, err
  292. }
  293. return parts, nil
  294. }
  295. // Return the raw data contained in the File as three
  296. // dimensional slice. The first index represents the sheet number,
  297. // the second the row number, and the third the cell number.
  298. //
  299. // For example:
  300. //
  301. // var mySlice [][][]string
  302. // var value string
  303. // mySlice = xlsx.FileToSlice("myXLSX.xlsx")
  304. // value = mySlice[0][0][0]
  305. //
  306. // Here, value would be set to the raw value of the cell A1 in the
  307. // first sheet in the XLSX file.
  308. func (f *File) ToSlice() (output [][][]string, err error) {
  309. output = [][][]string{}
  310. for _, sheet := range f.Sheets {
  311. s := [][]string{}
  312. for _, row := range sheet.Rows {
  313. if row == nil {
  314. continue
  315. }
  316. r := []string{}
  317. for _, cell := range row.Cells {
  318. str, err := cell.FormattedValue()
  319. if err != nil {
  320. // Recover from strconv.NumError if the value is an empty string,
  321. // and insert an empty string in the output.
  322. if numErr, ok := err.(*strconv.NumError); ok && numErr.Num == "" {
  323. str = ""
  324. } else {
  325. return output, err
  326. }
  327. }
  328. r = append(r, str)
  329. }
  330. s = append(s, r)
  331. }
  332. output = append(output, s)
  333. }
  334. return output, nil
  335. }
  336. // ToSliceUnmerged returns the raw data contained in the File as three
  337. // dimensional slice (s. method ToSlice).
  338. // A covered cell become the value of its origin cell.
  339. // Example: table where A1:A2 merged.
  340. // | 01.01.2011 | Bread | 20 |
  341. // | | Fish | 70 |
  342. // This sheet will be converted to the slice:
  343. // [ [01.01.2011 Bread 20]
  344. // [01.01.2011 Fish 70] ]
  345. func (f *File) ToSliceUnmerged() (output [][][]string, err error) {
  346. output, err = f.ToSlice()
  347. if err != nil {
  348. return nil, err
  349. }
  350. for s, sheet := range f.Sheets {
  351. for r, row := range sheet.Rows {
  352. for c, cell := range row.Cells {
  353. if cell.HMerge > 0 {
  354. for i := c + 1; i <= c+cell.HMerge; i++ {
  355. output[s][r][i] = output[s][r][c]
  356. }
  357. }
  358. if cell.VMerge > 0 {
  359. for i := r + 1; i <= r+cell.VMerge; i++ {
  360. output[s][i][c] = output[s][r][c]
  361. }
  362. }
  363. }
  364. }
  365. }
  366. return output, nil
  367. }