lib.go 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001
  1. package xlsx
  2. import (
  3. "archive/zip"
  4. "encoding/xml"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "path"
  9. "strconv"
  10. "strings"
  11. )
  12. // XLSXReaderError is the standard error type for otherwise undefined
  13. // errors in the XSLX reading process.
  14. type XLSXReaderError struct {
  15. Err string
  16. }
  17. // Error returns a string value from an XLSXReaderError struct in order
  18. // that it might comply with the builtin.error interface.
  19. func (e *XLSXReaderError) Error() string {
  20. return e.Err
  21. }
  22. // getRangeFromString is an internal helper function that converts
  23. // XLSX internal range syntax to a pair of integers. For example,
  24. // the range string "1:3" yield the upper and lower intergers 1 and 3.
  25. func getRangeFromString(rangeString string) (lower int, upper int, error error) {
  26. var parts []string
  27. parts = strings.SplitN(rangeString, ":", 2)
  28. if parts[0] == "" {
  29. error = errors.New(fmt.Sprintf("Invalid range '%s'\n", rangeString))
  30. }
  31. if parts[1] == "" {
  32. error = errors.New(fmt.Sprintf("Invalid range '%s'\n", rangeString))
  33. }
  34. lower, error = strconv.Atoi(parts[0])
  35. if error != nil {
  36. error = errors.New(fmt.Sprintf("Invalid range (not integer in lower bound) %s\n", rangeString))
  37. }
  38. upper, error = strconv.Atoi(parts[1])
  39. if error != nil {
  40. error = errors.New(fmt.Sprintf("Invalid range (not integer in upper bound) %s\n", rangeString))
  41. }
  42. return lower, upper, error
  43. }
  44. // lettersToNumeric is used to convert a character based column
  45. // reference to a zero based numeric column identifier.
  46. func lettersToNumeric(letters string) int {
  47. sum, mul, n := 0, 1, 0
  48. for i := len(letters) - 1; i >= 0; i, mul, n = i-1, mul*26, 1 {
  49. c := letters[i]
  50. switch {
  51. case 'A' <= c && c <= 'Z':
  52. n += int(c - 'A')
  53. case 'a' <= c && c <= 'z':
  54. n += int(c - 'a')
  55. }
  56. sum += n * mul
  57. }
  58. return sum
  59. }
  60. // Get the largestDenominator that is a multiple of a basedDenominator
  61. // and fits at least once into a given numerator.
  62. func getLargestDenominator(numerator, multiple, baseDenominator, power int) (int, int) {
  63. if numerator/multiple == 0 {
  64. return 1, power
  65. }
  66. next, nextPower := getLargestDenominator(
  67. numerator, multiple*baseDenominator, baseDenominator, power+1)
  68. if next > multiple {
  69. return next, nextPower
  70. }
  71. return multiple, power
  72. }
  73. // Convers a list of numbers representing a column into a alphabetic
  74. // representation, as used in the spreadsheet.
  75. func formatColumnName(colId []int) string {
  76. lastPart := len(colId) - 1
  77. result := ""
  78. for n, part := range colId {
  79. if n == lastPart {
  80. // The least significant number is in the
  81. // range 0-25, all other numbers are 1-26,
  82. // hence we use a differente offset for the
  83. // last part.
  84. result += string(part + 65)
  85. } else {
  86. // Don't output leading 0s, as there is no
  87. // representation of 0 in this format.
  88. if part > 0 {
  89. result += string(part + 64)
  90. }
  91. }
  92. }
  93. return result
  94. }
  95. func smooshBase26Slice(b26 []int) []int {
  96. // Smoosh values together, eliminating 0s from all but the
  97. // least significant part.
  98. lastButOnePart := len(b26) - 2
  99. for i := lastButOnePart; i > 0; i-- {
  100. part := b26[i]
  101. if part == 0 {
  102. greaterPart := b26[i-1]
  103. if greaterPart > 0 {
  104. b26[i-1] = greaterPart - 1
  105. b26[i] = 26
  106. }
  107. }
  108. }
  109. return b26
  110. }
  111. func intToBase26(x int) (parts []int) {
  112. // Excel column codes are pure evil - in essence they're just
  113. // base26, but they don't represent the number 0.
  114. b26Denominator, _ := getLargestDenominator(x, 1, 26, 0)
  115. // This loop terminates because integer division of 1 / 26
  116. // returns 0.
  117. for d := b26Denominator; d > 0; d = d / 26 {
  118. value := x / d
  119. remainder := x % d
  120. parts = append(parts, value)
  121. x = remainder
  122. }
  123. return parts
  124. }
  125. // numericToLetters is used to convert a zero based, numeric column
  126. // indentifier into a character code.
  127. func numericToLetters(colRef int) string {
  128. parts := intToBase26(colRef)
  129. return formatColumnName(smooshBase26Slice(parts))
  130. }
  131. // letterOnlyMapF is used in conjunction with strings.Map to return
  132. // only the characters A-Z and a-z in a string
  133. func letterOnlyMapF(rune rune) rune {
  134. switch {
  135. case 'A' <= rune && rune <= 'Z':
  136. return rune
  137. case 'a' <= rune && rune <= 'z':
  138. return rune - 32
  139. }
  140. return -1
  141. }
  142. // intOnlyMapF is used in conjunction with strings.Map to return only
  143. // the numeric portions of a string.
  144. func intOnlyMapF(rune rune) rune {
  145. if rune >= 48 && rune < 58 {
  146. return rune
  147. }
  148. return -1
  149. }
  150. // GetCoordsFromCellIDString returns the zero based cartesian
  151. // coordinates from a cell name in Excel format, e.g. the cellIDString
  152. // "A1" returns 0, 0 and the "B3" return 1, 2.
  153. func GetCoordsFromCellIDString(cellIDString string) (x, y int, error error) {
  154. var letterPart string = strings.Map(letterOnlyMapF, cellIDString)
  155. y, error = strconv.Atoi(strings.Map(intOnlyMapF, cellIDString))
  156. if error != nil {
  157. return x, y, error
  158. }
  159. y -= 1 // Zero based
  160. x = lettersToNumeric(letterPart)
  161. return x, y, error
  162. }
  163. // GetCellIDStringFromCoords returns the Excel format cell name that
  164. // represents a pair of zero based cartesian coordinates.
  165. func GetCellIDStringFromCoords(x, y int) string {
  166. letterPart := numericToLetters(x)
  167. numericPart := y + 1
  168. return fmt.Sprintf("%s%d", letterPart, numericPart)
  169. }
  170. // getMaxMinFromDimensionRef return the zero based cartesian maximum
  171. // and minimum coordinates from the dimension reference embedded in a
  172. // XLSX worksheet. For example, the dimension reference "A1:B2"
  173. // returns "0,0", "1,1".
  174. func getMaxMinFromDimensionRef(ref string) (minx, miny, maxx, maxy int, err error) {
  175. var parts []string
  176. parts = strings.Split(ref, ":")
  177. minx, miny, err = GetCoordsFromCellIDString(parts[0])
  178. if err != nil {
  179. return -1, -1, -1, -1, err
  180. }
  181. maxx, maxy, err = GetCoordsFromCellIDString(parts[1])
  182. if err != nil {
  183. return -1, -1, -1, -1, err
  184. }
  185. return
  186. }
  187. // calculateMaxMinFromWorkSheet works out the dimensions of a spreadsheet
  188. // that doesn't have a DimensionRef set. The only case currently
  189. // known where this is true is with XLSX exported from Google Docs.
  190. func calculateMaxMinFromWorksheet(worksheet *xlsxWorksheet) (minx, miny, maxx, maxy int, err error) {
  191. // Note, this method could be very slow for large spreadsheets.
  192. var x, y int
  193. var maxVal int
  194. maxVal = int(^uint(0) >> 1)
  195. minx = maxVal
  196. miny = maxVal
  197. maxy = 0
  198. maxx = 0
  199. for _, row := range worksheet.SheetData.Row {
  200. for _, cell := range row.C {
  201. x, y, err = GetCoordsFromCellIDString(cell.R)
  202. if err != nil {
  203. return -1, -1, -1, -1, err
  204. }
  205. if x < minx {
  206. minx = x
  207. }
  208. if x > maxx {
  209. maxx = x
  210. }
  211. if y < miny {
  212. miny = y
  213. }
  214. if y > maxy {
  215. maxy = y
  216. }
  217. }
  218. }
  219. if minx == maxVal {
  220. minx = 0
  221. }
  222. if miny == maxVal {
  223. miny = 0
  224. }
  225. return
  226. }
  227. // makeRowFromSpan will, when given a span expressed as a string,
  228. // return an empty Row large enough to encompass that span and
  229. // populate it with empty cells. All rows start from cell 1 -
  230. // regardless of the lower bound of the span.
  231. func makeRowFromSpan(spans string, sheet *Sheet) *Row {
  232. var error error
  233. var upper int
  234. var row *Row
  235. var cell *Cell
  236. row = new(Row)
  237. row.Sheet = sheet
  238. _, upper, error = getRangeFromString(spans)
  239. if error != nil {
  240. panic(error)
  241. }
  242. error = nil
  243. row.Cells = make([]*Cell, upper)
  244. for i := 0; i < upper; i++ {
  245. cell = new(Cell)
  246. cell.Value = ""
  247. row.Cells[i] = cell
  248. }
  249. return row
  250. }
  251. // makeRowFromRaw returns the Row representation of the xlsxRow.
  252. func makeRowFromRaw(rawrow xlsxRow, sheet *Sheet) *Row {
  253. var upper int
  254. var row *Row
  255. var cell *Cell
  256. row = new(Row)
  257. row.Sheet = sheet
  258. upper = -1
  259. for _, rawcell := range rawrow.C {
  260. if rawcell.R != "" {
  261. x, _, error := GetCoordsFromCellIDString(rawcell.R)
  262. if error != nil {
  263. panic(fmt.Sprintf("Invalid Cell Coord, %s\n", rawcell.R))
  264. }
  265. if x > upper {
  266. upper = x
  267. }
  268. continue
  269. }
  270. upper++
  271. }
  272. upper++
  273. row.OutlineLevel = rawrow.OutlineLevel
  274. row.Cells = make([]*Cell, upper)
  275. for i := 0; i < upper; i++ {
  276. cell = new(Cell)
  277. cell.Value = ""
  278. row.Cells[i] = cell
  279. }
  280. return row
  281. }
  282. func makeEmptyRow(sheet *Sheet) *Row {
  283. row := new(Row)
  284. row.Cells = make([]*Cell, 0)
  285. row.Sheet = sheet
  286. return row
  287. }
  288. type sharedFormula struct {
  289. x, y int
  290. formula string
  291. }
  292. func formulaForCell(rawcell xlsxC, sharedFormulas map[int]sharedFormula) string {
  293. var res string
  294. f := rawcell.F
  295. if f == nil {
  296. return ""
  297. }
  298. if f.T == "shared" {
  299. x, y, err := GetCoordsFromCellIDString(rawcell.R)
  300. if err != nil {
  301. res = f.Content
  302. } else {
  303. if f.Ref != "" {
  304. res = f.Content
  305. sharedFormulas[f.Si] = sharedFormula{x, y, res}
  306. } else {
  307. sharedFormula := sharedFormulas[f.Si]
  308. dx := x - sharedFormula.x
  309. dy := y - sharedFormula.y
  310. orig := []byte(sharedFormula.formula)
  311. var start, end int
  312. var stringLiteral bool
  313. for end = 0; end < len(orig); end++ {
  314. c := orig[end]
  315. if c == '"' {
  316. stringLiteral = !stringLiteral
  317. }
  318. if stringLiteral {
  319. continue // Skip characters in quotes
  320. }
  321. if c >= 'A' && c <= 'Z' || c == '$' {
  322. res += string(orig[start:end])
  323. start = end
  324. end++
  325. foundNum := false
  326. for ; end < len(orig); end++ {
  327. idc := orig[end]
  328. if idc >= '0' && idc <= '9' || idc == '$' {
  329. foundNum = true
  330. } else if idc >= 'A' && idc <= 'Z' {
  331. if foundNum {
  332. break
  333. }
  334. } else {
  335. break
  336. }
  337. }
  338. if foundNum {
  339. cellID := string(orig[start:end])
  340. res += shiftCell(cellID, dx, dy)
  341. start = end
  342. }
  343. }
  344. }
  345. if start < len(orig) {
  346. res += string(orig[start:])
  347. }
  348. }
  349. }
  350. } else {
  351. res = f.Content
  352. }
  353. return strings.Trim(res, " \t\n\r")
  354. }
  355. // shiftCell returns the cell shifted according to dx and dy taking into consideration of absolute
  356. // references with dollar sign ($)
  357. func shiftCell(cellID string, dx, dy int) string {
  358. fx, fy, _ := GetCoordsFromCellIDString(cellID)
  359. // Is fixed column?
  360. fixedCol := strings.Index(cellID, "$") == 0
  361. // Is fixed row?
  362. fixedRow := strings.LastIndex(cellID, "$") > 0
  363. if !fixedCol {
  364. // Shift column
  365. fx += dx
  366. }
  367. if !fixedRow {
  368. // Shift row
  369. fy += dy
  370. }
  371. // New shifted cell
  372. shiftedCellID := GetCellIDStringFromCoords(fx, fy)
  373. if !fixedCol && !fixedRow {
  374. return shiftedCellID
  375. }
  376. // There are absolute references, need to put the $ back into the formula.
  377. letterPart := strings.Map(letterOnlyMapF, shiftedCellID)
  378. numberPart := strings.Map(intOnlyMapF, shiftedCellID)
  379. result := ""
  380. if fixedCol {
  381. result += "$"
  382. }
  383. result += letterPart
  384. if fixedRow {
  385. result += "$"
  386. }
  387. result += numberPart
  388. return result
  389. }
  390. // fillCellData attempts to extract a valid value, usable in
  391. // CSV form from the raw cell value. Note - this is not actually
  392. // general enough - we should support retaining tabs and newlines.
  393. func fillCellData(rawcell xlsxC, reftable *RefTable, sharedFormulas map[int]sharedFormula, cell *Cell) {
  394. var data = rawcell.V
  395. if len(data) > 0 {
  396. vval := strings.Trim(data, " \t\n\r")
  397. switch rawcell.T {
  398. case "s": // Shared String
  399. ref, error := strconv.Atoi(vval)
  400. if error != nil {
  401. panic(error)
  402. }
  403. cell.Value = reftable.ResolveSharedString(ref)
  404. cell.cellType = CellTypeString
  405. case "b": // Boolean
  406. cell.Value = vval
  407. cell.cellType = CellTypeBool
  408. case "e": // Error
  409. cell.Value = vval
  410. cell.formula = formulaForCell(rawcell, sharedFormulas)
  411. cell.cellType = CellTypeError
  412. default:
  413. if rawcell.F == nil {
  414. // Numeric
  415. cell.Value = vval
  416. cell.cellType = CellTypeNumeric
  417. } else {
  418. // Formula
  419. cell.Value = vval
  420. cell.formula = formulaForCell(rawcell, sharedFormulas)
  421. cell.cellType = CellTypeFormula
  422. }
  423. }
  424. } else {
  425. if rawcell.Is != nil {
  426. fillCellDataFromInlineString(rawcell, cell)
  427. }
  428. }
  429. }
  430. // fillCellDataFromInlineString attempts to get inline string data and put it into a Cell.
  431. func fillCellDataFromInlineString(rawcell xlsxC, cell *Cell) {
  432. if rawcell.Is.T != "" {
  433. cell.Value = strings.Trim(rawcell.Is.T, " \t\n\r")
  434. cell.cellType = CellTypeInline
  435. } else {
  436. cell.Value = ""
  437. for _, r := range rawcell.Is.R {
  438. cell.Value += r.T
  439. }
  440. }
  441. }
  442. // readRowsFromSheet is an internal helper function that extracts the
  443. // rows from a XSLXWorksheet, populates them with Cells and resolves
  444. // the value references from the reference table and stores them in
  445. // the rows and columns.
  446. func readRowsFromSheet(Worksheet *xlsxWorksheet, file *File, sheet *Sheet) ([]*Row, []*Col, int, int) {
  447. var rows []*Row
  448. var cols []*Col
  449. var row *Row
  450. var minCol, maxCol, minRow, maxRow, colCount, rowCount int
  451. var reftable *RefTable
  452. var err error
  453. var insertRowIndex, insertColIndex int
  454. sharedFormulas := map[int]sharedFormula{}
  455. if len(Worksheet.SheetData.Row) == 0 {
  456. return nil, nil, 0, 0
  457. }
  458. reftable = file.referenceTable
  459. if len(Worksheet.Dimension.Ref) > 0 && len(strings.Split(Worksheet.Dimension.Ref, ":")) == 2 {
  460. minCol, minRow, maxCol, maxRow, err = getMaxMinFromDimensionRef(Worksheet.Dimension.Ref)
  461. } else {
  462. minCol, minRow, maxCol, maxRow, err = calculateMaxMinFromWorksheet(Worksheet)
  463. }
  464. if err != nil {
  465. panic(err.Error())
  466. }
  467. rowCount = maxRow + 1
  468. colCount = maxCol + 1
  469. rows = make([]*Row, rowCount)
  470. cols = make([]*Col, colCount)
  471. insertRowIndex = minRow
  472. for i := range cols {
  473. cols[i] = &Col{
  474. Hidden: false,
  475. }
  476. }
  477. if Worksheet.Cols != nil {
  478. // Columns can apply to a range, for convenience we expand the
  479. // ranges out into individual column definitions.
  480. for _, rawcol := range Worksheet.Cols.Col {
  481. // Note, below, that sometimes column definitions can
  482. // exist outside the defined dimensions of the
  483. // spreadsheet - we deliberately exclude these
  484. // columns.
  485. for i := rawcol.Min; i <= rawcol.Max && i <= colCount; i++ {
  486. col := &Col{
  487. Min: rawcol.Min,
  488. Max: rawcol.Max,
  489. Hidden: rawcol.Hidden,
  490. Width: rawcol.Width,
  491. OutlineLevel: rawcol.OutlineLevel}
  492. cols[i-1] = col
  493. if file.styles != nil {
  494. col.style = file.styles.getStyle(rawcol.Style)
  495. col.numFmt = file.styles.getNumberFormat(rawcol.Style)
  496. }
  497. }
  498. }
  499. }
  500. // insert leading empty rows that is in front of minRow
  501. for rowIndex := 0; rowIndex < minRow; rowIndex++ {
  502. rows[rowIndex] = makeEmptyRow(sheet)
  503. }
  504. numRows := len(rows)
  505. for rowIndex := 0; rowIndex < len(Worksheet.SheetData.Row); rowIndex++ {
  506. rawrow := Worksheet.SheetData.Row[rowIndex]
  507. // Some spreadsheets will omit blank rows from the
  508. // stored data
  509. for rawrow.R > (insertRowIndex + 1) {
  510. // Put an empty Row into the array
  511. if insertRowIndex < numRows {
  512. rows[insertRowIndex] = makeEmptyRow(sheet)
  513. }
  514. insertRowIndex++
  515. }
  516. // range is not empty and only one range exist
  517. if len(rawrow.Spans) != 0 && strings.Count(rawrow.Spans, ":") == 1 {
  518. row = makeRowFromSpan(rawrow.Spans, sheet)
  519. } else {
  520. row = makeRowFromRaw(rawrow, sheet)
  521. }
  522. row.Hidden = rawrow.Hidden
  523. height, err := strconv.ParseFloat(rawrow.Ht, 64)
  524. if err == nil {
  525. row.Height = height
  526. }
  527. row.isCustom = rawrow.CustomHeight
  528. row.OutlineLevel = rawrow.OutlineLevel
  529. insertColIndex = minCol
  530. for _, rawcell := range rawrow.C {
  531. h, v, err := Worksheet.MergeCells.getExtent(rawcell.R)
  532. if err != nil {
  533. panic(err.Error())
  534. }
  535. x, _, _ := GetCoordsFromCellIDString(rawcell.R)
  536. // K1000000: Prevent panic when the range specified in the spreadsheet
  537. // view exceeds the actual number of columns in the dataset.
  538. // Some spreadsheets will omit blank cells
  539. // from the data.
  540. for x > insertColIndex {
  541. // Put an empty Cell into the array
  542. if insertColIndex < len(row.Cells) {
  543. row.Cells[insertColIndex] = new(Cell)
  544. }
  545. insertColIndex++
  546. }
  547. cellX := insertColIndex
  548. if cellX < len(row.Cells) {
  549. cell := row.Cells[cellX]
  550. cell.HMerge = h
  551. cell.VMerge = v
  552. fillCellData(rawcell, reftable, sharedFormulas, cell)
  553. if file.styles != nil {
  554. cell.style = file.styles.getStyle(rawcell.S)
  555. cell.NumFmt = file.styles.getNumberFormat(rawcell.S)
  556. }
  557. cell.date1904 = file.Date1904
  558. // Cell is considered hidden if the row or the column of this cell is hidden
  559. cell.Hidden = rawrow.Hidden || (len(cols) > cellX && cols[cellX].Hidden)
  560. insertColIndex++
  561. }
  562. }
  563. if len(rows) > insertRowIndex {
  564. rows[insertRowIndex] = row
  565. }
  566. insertRowIndex++
  567. }
  568. return rows, cols, colCount, rowCount
  569. }
  570. type indexedSheet struct {
  571. Index int
  572. Sheet *Sheet
  573. Error error
  574. }
  575. func readSheetViews(xSheetViews xlsxSheetViews) []SheetView {
  576. if xSheetViews.SheetView == nil || len(xSheetViews.SheetView) == 0 {
  577. return nil
  578. }
  579. sheetViews := []SheetView{}
  580. for _, xSheetView := range xSheetViews.SheetView {
  581. sheetView := SheetView{}
  582. if xSheetView.Pane != nil {
  583. xlsxPane := xSheetView.Pane
  584. pane := &Pane{}
  585. pane.XSplit = xlsxPane.XSplit
  586. pane.YSplit = xlsxPane.YSplit
  587. pane.TopLeftCell = xlsxPane.TopLeftCell
  588. pane.ActivePane = xlsxPane.ActivePane
  589. pane.State = xlsxPane.State
  590. sheetView.Pane = pane
  591. }
  592. sheetViews = append(sheetViews, sheetView)
  593. }
  594. return sheetViews
  595. }
  596. // readSheetFromFile is the logic of converting a xlsxSheet struct
  597. // into a Sheet struct. This work can be done in parallel and so
  598. // readSheetsFromZipFile will spawn an instance of this function per
  599. // sheet and get the results back on the provided channel.
  600. func readSheetFromFile(sc chan *indexedSheet, index int, rsheet xlsxSheet, fi *File, sheetXMLMap map[string]string) (errRes error) {
  601. result := &indexedSheet{Index: index, Sheet: nil, Error: nil}
  602. defer func() {
  603. if e := recover(); e != nil {
  604. switch e.(type) {
  605. case error:
  606. result.Error = e.(error)
  607. errRes = e.(error)
  608. default:
  609. result.Error = errors.New("unexpected error")
  610. }
  611. // The only thing here, is if one close the channel. but its not the case
  612. sc <- result
  613. }
  614. }()
  615. worksheet, error := getWorksheetFromSheet(rsheet, fi.worksheets, sheetXMLMap)
  616. if error != nil {
  617. result.Error = error
  618. sc <- result
  619. return error
  620. }
  621. sheet := new(Sheet)
  622. sheet.File = fi
  623. sheet.Rows, sheet.Cols, sheet.MaxCol, sheet.MaxRow = readRowsFromSheet(worksheet, fi, sheet)
  624. sheet.Hidden = rsheet.State == sheetStateHidden || rsheet.State == sheetStateVeryHidden
  625. sheet.SheetViews = readSheetViews(worksheet.SheetViews)
  626. sheet.SheetFormat.DefaultColWidth = worksheet.SheetFormatPr.DefaultColWidth
  627. sheet.SheetFormat.DefaultRowHeight = worksheet.SheetFormatPr.DefaultRowHeight
  628. sheet.SheetFormat.OutlineLevelCol = worksheet.SheetFormatPr.OutlineLevelCol
  629. sheet.SheetFormat.OutlineLevelRow = worksheet.SheetFormatPr.OutlineLevelRow
  630. result.Sheet = sheet
  631. sc <- result
  632. return nil
  633. }
  634. // readSheetsFromZipFile is an internal helper function that loops
  635. // over the Worksheets defined in the XSLXWorkbook and loads them into
  636. // Sheet objects stored in the Sheets slice of a xlsx.File struct.
  637. func readSheetsFromZipFile(f *zip.File, file *File, sheetXMLMap map[string]string) (map[string]*Sheet, []*Sheet, error) {
  638. var workbook *xlsxWorkbook
  639. var err error
  640. var rc io.ReadCloser
  641. var decoder *xml.Decoder
  642. var sheetCount int
  643. workbook = new(xlsxWorkbook)
  644. rc, err = f.Open()
  645. if err != nil {
  646. return nil, nil, err
  647. }
  648. decoder = xml.NewDecoder(rc)
  649. err = decoder.Decode(workbook)
  650. if err != nil {
  651. return nil, nil, err
  652. }
  653. file.Date1904 = workbook.WorkbookPr.Date1904
  654. for entryNum := range workbook.DefinedNames.DefinedName {
  655. file.DefinedNames = append(file.DefinedNames, &workbook.DefinedNames.DefinedName[entryNum])
  656. }
  657. // Only try and read sheets that have corresponding files.
  658. // Notably this excludes chartsheets don't right now
  659. var workbookSheets []xlsxSheet
  660. for _, sheet := range workbook.Sheets.Sheet {
  661. if f := worksheetFileForSheet(sheet, file.worksheets, sheetXMLMap); f != nil {
  662. workbookSheets = append(workbookSheets, sheet)
  663. }
  664. }
  665. sheetCount = len(workbookSheets)
  666. sheetsByName := make(map[string]*Sheet, sheetCount)
  667. sheets := make([]*Sheet, sheetCount)
  668. sheetChan := make(chan *indexedSheet, sheetCount)
  669. go func() {
  670. defer close(sheetChan)
  671. err = nil
  672. for i, rawsheet := range workbookSheets {
  673. if err := readSheetFromFile(sheetChan, i, rawsheet, file, sheetXMLMap); err != nil {
  674. return
  675. }
  676. }
  677. }()
  678. for j := 0; j < sheetCount; j++ {
  679. sheet := <-sheetChan
  680. if sheet.Error != nil {
  681. return nil, nil, sheet.Error
  682. }
  683. sheetName := workbookSheets[sheet.Index].Name
  684. sheetsByName[sheetName] = sheet.Sheet
  685. sheet.Sheet.Name = sheetName
  686. sheets[sheet.Index] = sheet.Sheet
  687. }
  688. return sheetsByName, sheets, nil
  689. }
  690. // readSharedStringsFromZipFile() is an internal helper function to
  691. // extract a reference table from the sharedStrings.xml file within
  692. // the XLSX zip file.
  693. func readSharedStringsFromZipFile(f *zip.File) (*RefTable, error) {
  694. var sst *xlsxSST
  695. var error error
  696. var rc io.ReadCloser
  697. var decoder *xml.Decoder
  698. var reftable *RefTable
  699. // In a file with no strings it's possible that
  700. // sharedStrings.xml doesn't exist. In this case the value
  701. // passed as f will be nil.
  702. if f == nil {
  703. return nil, nil
  704. }
  705. rc, error = f.Open()
  706. if error != nil {
  707. return nil, error
  708. }
  709. sst = new(xlsxSST)
  710. decoder = xml.NewDecoder(rc)
  711. error = decoder.Decode(sst)
  712. if error != nil {
  713. return nil, error
  714. }
  715. reftable = MakeSharedStringRefTable(sst)
  716. return reftable, nil
  717. }
  718. // readStylesFromZipFile() is an internal helper function to
  719. // extract a style table from the style.xml file within
  720. // the XLSX zip file.
  721. func readStylesFromZipFile(f *zip.File, theme *theme) (*xlsxStyleSheet, error) {
  722. var style *xlsxStyleSheet
  723. var error error
  724. var rc io.ReadCloser
  725. var decoder *xml.Decoder
  726. rc, error = f.Open()
  727. if error != nil {
  728. return nil, error
  729. }
  730. style = newXlsxStyleSheet(theme)
  731. decoder = xml.NewDecoder(rc)
  732. error = decoder.Decode(style)
  733. if error != nil {
  734. return nil, error
  735. }
  736. buildNumFmtRefTable(style)
  737. return style, nil
  738. }
  739. func buildNumFmtRefTable(style *xlsxStyleSheet) {
  740. for _, numFmt := range style.NumFmts.NumFmt {
  741. // We do this for the side effect of populating the NumFmtRefTable.
  742. style.addNumFmt(numFmt)
  743. }
  744. }
  745. func readThemeFromZipFile(f *zip.File) (*theme, error) {
  746. rc, err := f.Open()
  747. if err != nil {
  748. return nil, err
  749. }
  750. var themeXml xlsxTheme
  751. err = xml.NewDecoder(rc).Decode(&themeXml)
  752. if err != nil {
  753. return nil, err
  754. }
  755. return newTheme(themeXml), nil
  756. }
  757. type WorkBookRels map[string]string
  758. func (w *WorkBookRels) MakeXLSXWorkbookRels() xlsxWorkbookRels {
  759. relCount := len(*w)
  760. xWorkbookRels := xlsxWorkbookRels{}
  761. xWorkbookRels.Relationships = make([]xlsxWorkbookRelation, relCount+3)
  762. for k, v := range *w {
  763. index, err := strconv.Atoi(k[3:])
  764. if err != nil {
  765. panic(err.Error())
  766. }
  767. xWorkbookRels.Relationships[index-1] = xlsxWorkbookRelation{
  768. Id: k,
  769. Target: v,
  770. Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"}
  771. }
  772. relCount++
  773. sheetId := fmt.Sprintf("rId%d", relCount)
  774. xWorkbookRels.Relationships[relCount-1] = xlsxWorkbookRelation{
  775. Id: sheetId,
  776. Target: "sharedStrings.xml",
  777. Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"}
  778. relCount++
  779. sheetId = fmt.Sprintf("rId%d", relCount)
  780. xWorkbookRels.Relationships[relCount-1] = xlsxWorkbookRelation{
  781. Id: sheetId,
  782. Target: "theme/theme1.xml",
  783. Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"}
  784. relCount++
  785. sheetId = fmt.Sprintf("rId%d", relCount)
  786. xWorkbookRels.Relationships[relCount-1] = xlsxWorkbookRelation{
  787. Id: sheetId,
  788. Target: "styles.xml",
  789. Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"}
  790. return xWorkbookRels
  791. }
  792. // readWorkbookRelationsFromZipFile is an internal helper function to
  793. // extract a map of relationship ID strings to the name of the
  794. // worksheet.xml file they refer to. The resulting map can be used to
  795. // reliably derefence the worksheets in the XLSX file.
  796. func readWorkbookRelationsFromZipFile(workbookRels *zip.File) (WorkBookRels, error) {
  797. var sheetXMLMap WorkBookRels
  798. var wbRelationships *xlsxWorkbookRels
  799. var rc io.ReadCloser
  800. var decoder *xml.Decoder
  801. var err error
  802. rc, err = workbookRels.Open()
  803. if err != nil {
  804. return nil, err
  805. }
  806. decoder = xml.NewDecoder(rc)
  807. wbRelationships = new(xlsxWorkbookRels)
  808. err = decoder.Decode(wbRelationships)
  809. if err != nil {
  810. return nil, err
  811. }
  812. sheetXMLMap = make(WorkBookRels)
  813. for _, rel := range wbRelationships.Relationships {
  814. if strings.HasSuffix(rel.Target, ".xml") && rel.Type == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" {
  815. _, filename := path.Split(rel.Target)
  816. sheetXMLMap[rel.Id] = strings.Replace(filename, ".xml", "", 1)
  817. }
  818. }
  819. return sheetXMLMap, nil
  820. }
  821. // ReadZip() takes a pointer to a zip.ReadCloser and returns a
  822. // xlsx.File struct populated with its contents. In most cases
  823. // ReadZip is not used directly, but is called internally by OpenFile.
  824. func ReadZip(f *zip.ReadCloser) (*File, error) {
  825. defer f.Close()
  826. return ReadZipReader(&f.Reader)
  827. }
  828. // ReadZipReader() can be used to read an XLSX in memory without
  829. // touching the filesystem.
  830. func ReadZipReader(r *zip.Reader) (*File, error) {
  831. var err error
  832. var file *File
  833. var reftable *RefTable
  834. var sharedStrings *zip.File
  835. var sheetXMLMap map[string]string
  836. var sheetsByName map[string]*Sheet
  837. var sheets []*Sheet
  838. var style *xlsxStyleSheet
  839. var styles *zip.File
  840. var themeFile *zip.File
  841. var v *zip.File
  842. var workbook *zip.File
  843. var workbookRels *zip.File
  844. var worksheets map[string]*zip.File
  845. file = NewFile()
  846. // file.numFmtRefTable = make(map[int]xlsxNumFmt, 1)
  847. worksheets = make(map[string]*zip.File, len(r.File))
  848. for _, v = range r.File {
  849. switch v.Name {
  850. case "xl/sharedStrings.xml":
  851. sharedStrings = v
  852. case "xl/workbook.xml":
  853. workbook = v
  854. case "xl/_rels/workbook.xml.rels":
  855. workbookRels = v
  856. case "xl/styles.xml":
  857. styles = v
  858. case "xl/theme/theme1.xml":
  859. themeFile = v
  860. default:
  861. if len(v.Name) > 14 {
  862. if v.Name[0:13] == "xl/worksheets" {
  863. worksheets[v.Name[14:len(v.Name)-4]] = v
  864. }
  865. }
  866. }
  867. }
  868. if workbookRels == nil {
  869. return nil, fmt.Errorf("xl/_rels/workbook.xml.rels not found in input xlsx.")
  870. }
  871. sheetXMLMap, err = readWorkbookRelationsFromZipFile(workbookRels)
  872. if err != nil {
  873. return nil, err
  874. }
  875. if len(worksheets) == 0 {
  876. return nil, fmt.Errorf("Input xlsx contains no worksheets.")
  877. }
  878. file.worksheets = worksheets
  879. reftable, err = readSharedStringsFromZipFile(sharedStrings)
  880. if err != nil {
  881. return nil, err
  882. }
  883. file.referenceTable = reftable
  884. if themeFile != nil {
  885. theme, err := readThemeFromZipFile(themeFile)
  886. if err != nil {
  887. return nil, err
  888. }
  889. file.theme = theme
  890. }
  891. if styles != nil {
  892. style, err = readStylesFromZipFile(styles, file.theme)
  893. if err != nil {
  894. return nil, err
  895. }
  896. file.styles = style
  897. }
  898. sheetsByName, sheets, err = readSheetsFromZipFile(workbook, file, sheetXMLMap)
  899. if err != nil {
  900. return nil, err
  901. }
  902. if sheets == nil {
  903. readerErr := new(XLSXReaderError)
  904. readerErr.Err = "No sheets found in XLSX File"
  905. return nil, readerErr
  906. }
  907. file.Sheet = sheetsByName
  908. file.Sheets = sheets
  909. return file, nil
  910. }