excelize.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package excelize
  2. import (
  3. "archive/zip"
  4. "bytes"
  5. "encoding/xml"
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. )
  10. // FileList define a populated xlsx.File struct.
  11. type FileList struct {
  12. Key string
  13. Value string
  14. }
  15. // OpenFile take the name of an XLSX file and returns a populated
  16. // xlsx.File struct for it.
  17. func OpenFile(filename string) (file []FileList, err error) {
  18. var f *zip.ReadCloser
  19. f, err = zip.OpenReader(filename)
  20. if err != nil {
  21. return nil, err
  22. }
  23. file, err = ReadZip(f)
  24. return
  25. }
  26. // SetCellInt provide function to set int type value of a cell
  27. func SetCellInt(file []FileList, sheet string, axis string, value int) []FileList {
  28. axis = strings.ToUpper(axis)
  29. var xlsx xlsxWorksheet
  30. col := getColIndex(axis)
  31. row := getRowIndex(axis)
  32. xAxis := row - 1
  33. yAxis := titleToNumber(col)
  34. name := `xl/worksheets/` + strings.ToLower(sheet) + `.xml`
  35. xml.Unmarshal([]byte(readXML(file, name)), &xlsx)
  36. rows := xAxis + 1
  37. cell := yAxis + 1
  38. xlsx = checkRow(xlsx)
  39. xlsx = completeRow(xlsx, rows, cell)
  40. xlsx = completeCol(xlsx, rows, cell)
  41. xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
  42. xlsx.SheetData.Row[xAxis].C[yAxis].V = strconv.Itoa(value)
  43. output, err := xml.Marshal(xlsx)
  44. if err != nil {
  45. fmt.Println(err)
  46. }
  47. saveFileList(file, name, replaceRelationshipsID(replaceWorkSheetsRelationshipsNameSpace(string(output))))
  48. return file
  49. }
  50. // SetCellStr provide function to set string type value of a cell
  51. func SetCellStr(file []FileList, sheet string, axis string, value string) []FileList {
  52. axis = strings.ToUpper(axis)
  53. var xlsx xlsxWorksheet
  54. col := getColIndex(axis)
  55. row := getRowIndex(axis)
  56. xAxis := row - 1
  57. yAxis := titleToNumber(col)
  58. name := `xl/worksheets/` + strings.ToLower(sheet) + `.xml`
  59. xml.Unmarshal([]byte(readXML(file, name)), &xlsx)
  60. rows := xAxis + 1
  61. cell := yAxis + 1
  62. xlsx = checkRow(xlsx)
  63. xlsx = completeRow(xlsx, rows, cell)
  64. xlsx = completeCol(xlsx, rows, cell)
  65. xlsx.SheetData.Row[xAxis].C[yAxis].T = "str"
  66. xlsx.SheetData.Row[xAxis].C[yAxis].V = value
  67. output, err := xml.Marshal(xlsx)
  68. if err != nil {
  69. fmt.Println(err)
  70. }
  71. saveFileList(file, name, replaceRelationshipsID(replaceWorkSheetsRelationshipsNameSpace(string(output))))
  72. return file
  73. }
  74. // Completion column element tags of XML in a sheet
  75. func completeCol(xlsx xlsxWorksheet, row int, cell int) xlsxWorksheet {
  76. if len(xlsx.SheetData.Row) < cell {
  77. for i := len(xlsx.SheetData.Row); i < cell; i++ {
  78. xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{
  79. R: i + 1,
  80. })
  81. }
  82. }
  83. buffer := bytes.Buffer{}
  84. for k, v := range xlsx.SheetData.Row {
  85. if len(v.C) < cell {
  86. start := len(v.C)
  87. for iii := start; iii < cell; iii++ {
  88. buffer.WriteString(toAlphaString(iii + 1))
  89. buffer.WriteString(strconv.Itoa(k + 1))
  90. xlsx.SheetData.Row[k].C = append(xlsx.SheetData.Row[k].C, xlsxC{
  91. R: buffer.String(),
  92. })
  93. buffer.Reset()
  94. }
  95. }
  96. }
  97. return xlsx
  98. }
  99. // Completion row element tags of XML in a sheet
  100. func completeRow(xlsx xlsxWorksheet, row int, cell int) xlsxWorksheet {
  101. if len(xlsx.SheetData.Row) < row {
  102. for i := len(xlsx.SheetData.Row); i < row; i++ {
  103. xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{
  104. R: i + 1,
  105. })
  106. }
  107. buffer := bytes.Buffer{}
  108. for ii := 0; ii < row; ii++ {
  109. start := len(xlsx.SheetData.Row[ii].C)
  110. if start == 0 {
  111. for iii := start; iii < cell; iii++ {
  112. buffer.WriteString(toAlphaString(iii + 1))
  113. buffer.WriteString(strconv.Itoa(ii + 1))
  114. xlsx.SheetData.Row[ii].C = append(xlsx.SheetData.Row[ii].C, xlsxC{
  115. R: buffer.String(),
  116. })
  117. buffer.Reset()
  118. }
  119. }
  120. }
  121. }
  122. return xlsx
  123. }
  124. // Replace xl/worksheets/sheet%d.xml XML tags to self-closing for compatible Office Excel 2007
  125. func replaceWorkSheetsRelationshipsNameSpace(workbookMarshal string) string {
  126. oldXmlns := `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`
  127. newXmlns := `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mx="http://schemas.microsoft.com/office/mac/excel/2008/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mv="urn:schemas-microsoft-com:mac:vml" xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main">`
  128. workbookMarshal = strings.Replace(workbookMarshal, oldXmlns, newXmlns, -1)
  129. workbookMarshal = strings.Replace(workbookMarshal, `></sheetPr>`, ` />`, -1)
  130. workbookMarshal = strings.Replace(workbookMarshal, `></dimension>`, ` />`, -1)
  131. workbookMarshal = strings.Replace(workbookMarshal, `></selection>`, ` />`, -1)
  132. workbookMarshal = strings.Replace(workbookMarshal, `></sheetFormatPr>`, ` />`, -1)
  133. workbookMarshal = strings.Replace(workbookMarshal, `></printOptions>`, ` />`, -1)
  134. workbookMarshal = strings.Replace(workbookMarshal, `></pageSetup>`, ` />`, -1)
  135. workbookMarshal = strings.Replace(workbookMarshal, `></pageMargins>`, ` />`, -1)
  136. workbookMarshal = strings.Replace(workbookMarshal, `></headerFooter>`, ` />`, -1)
  137. workbookMarshal = strings.Replace(workbookMarshal, `></drawing>`, ` />`, -1)
  138. return workbookMarshal
  139. }
  140. // Check XML tags and fix discontinuous case, for example:
  141. //
  142. // <row r="15" spans="1:22" x14ac:dyDescent="0.2">
  143. // <c r="A15" s="2" />
  144. // <c r="B15" s="2" />
  145. // <c r="F15" s="1" />
  146. // <c r="G15" s="1" />
  147. // </row>
  148. //
  149. // in this case, we should to change it to
  150. //
  151. // <row r="15" spans="1:22" x14ac:dyDescent="0.2">
  152. // <c r="A15" s="2" />
  153. // <c r="B15" s="2" />
  154. // <c r="C15" s="2" />
  155. // <c r="D15" s="2" />
  156. // <c r="E15" s="2" />
  157. // <c r="F15" s="1" />
  158. // <c r="G15" s="1" />
  159. // </row>
  160. //
  161. func checkRow(xlsx xlsxWorksheet) xlsxWorksheet {
  162. buffer := bytes.Buffer{}
  163. for k, v := range xlsx.SheetData.Row {
  164. lenCol := len(v.C)
  165. if lenCol < 1 {
  166. continue
  167. }
  168. endR := getColIndex(v.C[lenCol-1].R)
  169. endRow := getRowIndex(v.C[lenCol-1].R)
  170. endCol := titleToNumber(endR)
  171. if lenCol < endCol {
  172. oldRow := xlsx.SheetData.Row[k].C
  173. xlsx.SheetData.Row[k].C = xlsx.SheetData.Row[k].C[:0]
  174. tmp := []xlsxC{}
  175. for i := 0; i <= endCol; i++ {
  176. buffer.WriteString(toAlphaString(i + 1))
  177. buffer.WriteString(strconv.Itoa(endRow))
  178. tmp = append(tmp, xlsxC{
  179. R: buffer.String(),
  180. })
  181. buffer.Reset()
  182. }
  183. xlsx.SheetData.Row[k].C = tmp
  184. for _, y := range oldRow {
  185. colAxis := titleToNumber(getColIndex(y.R))
  186. xlsx.SheetData.Row[k].C[colAxis] = y
  187. }
  188. }
  189. }
  190. return xlsx
  191. }