lib.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package xlsx
  2. import (
  3. "archive/zip"
  4. "io"
  5. "os"
  6. "xml"
  7. )
  8. // XLSXReaderError is the standard error type for otherwise undefined
  9. // errors in the XSLX reading process.
  10. type XLSXReaderError struct {
  11. Error string
  12. }
  13. // String() returns a string value from an XLSXReaderError struct in
  14. // order that it might comply with the os.Error interface.
  15. func (e *XLSXReaderError) String() string {
  16. return e.Error
  17. }
  18. // Cell is a high level structure intended to provide user access to
  19. // the contents of Cell within an xlsx.Row.
  20. type Cell struct {
  21. data string
  22. }
  23. // Row is a high level structure indended to provide user access to a
  24. // row within a xlsx.Sheet. An xlsx.Row contains a slice of xlsx.Cell.
  25. type Row struct {
  26. Cells []*Cell
  27. }
  28. // Sheet is a high level structure intended to provide user access to
  29. // the contents of a particular sheet within an XLSX file.
  30. type Sheet struct {
  31. Rows []*Row
  32. }
  33. // File is a high level structure providing a slice of Sheet structs
  34. // to the user.
  35. type File struct {
  36. worksheets map[string] *zip.File
  37. referenceTable []string
  38. Sheets []*Sheet
  39. }
  40. // readRowsFromSheet is an internal helper function that extracts the
  41. // rows from a XSLXWorksheet, poulates them with Cells and resolves
  42. // the value references from the reference table and stores them in
  43. func readRowsFromSheet(worksheet *XLSXWorksheet, reftable []string) []*Row {
  44. var rows []*Row
  45. rows = make([]*Row, len(worksheet.SheetData.Row))
  46. for i, rawrow := range worksheet.SheetData.Row {
  47. row := new(Row)
  48. row.Cells = make([]*Cell, len(rawrow.C))
  49. for j, rawcell := range rawrow.C {
  50. cell := new(Cell)
  51. cell.data = rawcell.V.Data
  52. row.Cells[j] = cell
  53. }
  54. rows[i] = row
  55. }
  56. return rows
  57. }
  58. // readSheetsFromZipFile is an internal helper function that loops
  59. // over the Worksheets defined in the XSLXWorkbook and loads them into
  60. // Sheet objects stored in the Sheets slice of a xlsx.File struct.
  61. func readSheetsFromZipFile(f *zip.File, file *File) ([]*Sheet, os.Error) {
  62. var workbook *XLSXWorkbook
  63. var error os.Error
  64. var rc io.ReadCloser
  65. workbook = new(XLSXWorkbook)
  66. rc, error = f.Open()
  67. if error != nil {
  68. return nil, error
  69. }
  70. error = xml.Unmarshal(rc, workbook)
  71. if error != nil {
  72. return nil, error
  73. }
  74. sheets := make([]*Sheet, len(workbook.Sheets.Sheet))
  75. for i, rawsheet := range workbook.Sheets.Sheet {
  76. worksheet, error := getWorksheetFromSheet(rawsheet, file.worksheets)
  77. if error != nil {
  78. return nil, error
  79. }
  80. sheet := new(Sheet)
  81. sheet.Rows = readRowsFromSheet(worksheet, file.referenceTable)
  82. sheets[i] = sheet
  83. }
  84. return sheets, nil
  85. }
  86. // readSharedStringsFromZipFile() is an internal helper function to
  87. // extract a reference table from the sharedStrings.xml file within
  88. // the XLSX zip file.
  89. func readSharedStringsFromZipFile(f *zip.File) ([]string, os.Error) {
  90. var sst *XLSXSST
  91. var error os.Error
  92. var rc io.ReadCloser
  93. var reftable []string
  94. rc, error = f.Open()
  95. if error != nil {
  96. return nil, error
  97. }
  98. sst = new(XLSXSST)
  99. error = xml.Unmarshal(rc, sst)
  100. if error != nil {
  101. return nil, error
  102. }
  103. reftable = MakeSharedStringRefTable(sst)
  104. return reftable, nil
  105. }
  106. // OpenFile() take the name of an XLSX file and returns a populated
  107. // xlsx.File struct for it.
  108. func OpenFile(filename string) (x *File, e os.Error) {
  109. var f *zip.ReadCloser
  110. var error os.Error
  111. var file *File
  112. var v *zip.File
  113. var workbook *zip.File
  114. var sharedStrings *zip.File
  115. var reftable []string
  116. var worksheets map[string]*zip.File
  117. f, error = zip.OpenReader(filename)
  118. if error != nil {
  119. return nil, error
  120. }
  121. file = new(File)
  122. worksheets = make(map[string]*zip.File, len(f.File))
  123. for _, v = range f.File {
  124. switch v.Name {
  125. case "xl/sharedStrings.xml":
  126. sharedStrings = v
  127. case "xl/workbook.xml":
  128. workbook = v
  129. default:
  130. if len(v.Name) > 12 {
  131. if v.Name[0:13] == "xl/worksheets" {
  132. worksheets[v.Name[14:len(v.Name)-4]]= v
  133. }
  134. }
  135. }
  136. }
  137. file.worksheets = worksheets
  138. reftable, error = readSharedStringsFromZipFile(sharedStrings)
  139. if error != nil {
  140. return nil, error
  141. }
  142. if reftable == nil {
  143. error := new(XLSXReaderError)
  144. error.Error = "No valid sharedStrings.xml found in XLSX file"
  145. return nil, error
  146. }
  147. file.referenceTable = reftable
  148. sheets, error := readSheetsFromZipFile(workbook, file)
  149. if error != nil {
  150. return nil, error
  151. }
  152. if sheets == nil {
  153. error := new(XLSXReaderError)
  154. error.Error = "No sheets found in XLSX File"
  155. return nil, error
  156. }
  157. file.Sheets = sheets
  158. f.Close()
  159. return file, nil
  160. }