cell.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package excelize
  2. import (
  3. "encoding/xml"
  4. "strconv"
  5. "strings"
  6. )
  7. // mergeCellsParser provides function to check merged cells in worksheet by
  8. // given axis.
  9. func (f *File) mergeCellsParser(xlsx *xlsxWorksheet, axis string) {
  10. if xlsx.MergeCells != nil {
  11. for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
  12. if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
  13. axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0]
  14. }
  15. }
  16. }
  17. }
  18. // GetCellValue provides function to get formatted value from cell by given
  19. // sheet index and axis in XLSX file. If it is possible to apply a format to the
  20. // cell value, it will do so, if not then an error will be returned, along with
  21. // the raw value of the cell.
  22. func (f *File) GetCellValue(sheet, axis string) string {
  23. xlsx := f.workSheetReader(sheet)
  24. axis = strings.ToUpper(axis)
  25. f.mergeCellsParser(xlsx, axis)
  26. row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  27. xAxis := row - 1
  28. rows := len(xlsx.SheetData.Row)
  29. if rows > 1 {
  30. lastRow := xlsx.SheetData.Row[rows-1].R
  31. if lastRow >= rows {
  32. rows = lastRow
  33. }
  34. }
  35. if rows < xAxis {
  36. return ""
  37. }
  38. for _, v := range xlsx.SheetData.Row {
  39. if v.R != row {
  40. continue
  41. }
  42. for _, r := range v.C {
  43. if axis != r.R {
  44. continue
  45. }
  46. switch r.T {
  47. case "s":
  48. shardStrings := xlsxSST{}
  49. xlsxSI := 0
  50. xlsxSI, _ = strconv.Atoi(r.V)
  51. xml.Unmarshal([]byte(f.readXML("xl/sharedStrings.xml")), &shardStrings)
  52. return f.formattedValue(r.S, shardStrings.SI[xlsxSI].T)
  53. case "str":
  54. return f.formattedValue(r.S, r.V)
  55. default:
  56. return f.formattedValue(r.S, r.V)
  57. }
  58. }
  59. }
  60. return ""
  61. }
  62. // formattedValue provides function to returns a value after formatted. If it is
  63. // possible to apply a format to the cell value, it will do so, if not then an
  64. // error will be returned, along with the raw value of the cell.
  65. func (f *File) formattedValue(s int, v string) string {
  66. if s == 0 {
  67. return v
  68. }
  69. var styleSheet xlsxStyleSheet
  70. xml.Unmarshal([]byte(f.readXML("xl/styles.xml")), &styleSheet)
  71. ok := builtInNumFmtFunc[styleSheet.CellXfs.Xf[s].NumFmtID]
  72. if ok != nil {
  73. return ok(styleSheet.CellXfs.Xf[s].NumFmtID, v)
  74. }
  75. return v
  76. }
  77. // GetCellFormula provides function to get formula from cell by given sheet
  78. // index and axis in XLSX file.
  79. func (f *File) GetCellFormula(sheet, axis string) string {
  80. xlsx := f.workSheetReader(sheet)
  81. axis = strings.ToUpper(axis)
  82. f.mergeCellsParser(xlsx, axis)
  83. row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  84. xAxis := row - 1
  85. rows := len(xlsx.SheetData.Row)
  86. if rows > 1 {
  87. lastRow := xlsx.SheetData.Row[rows-1].R
  88. if lastRow >= rows {
  89. rows = lastRow
  90. }
  91. }
  92. if rows < xAxis {
  93. return ""
  94. }
  95. for _, v := range xlsx.SheetData.Row {
  96. if v.R != row {
  97. continue
  98. }
  99. for _, f := range v.C {
  100. if axis != f.R {
  101. continue
  102. }
  103. if f.F != nil {
  104. return f.F.Content
  105. }
  106. }
  107. }
  108. return ""
  109. }
  110. // SetCellFormula provides function to set cell formula by given string and
  111. // sheet index.
  112. func (f *File) SetCellFormula(sheet, axis, formula string) {
  113. xlsx := f.workSheetReader(sheet)
  114. axis = strings.ToUpper(axis)
  115. f.mergeCellsParser(xlsx, axis)
  116. col := string(strings.Map(letterOnlyMapF, axis))
  117. row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  118. xAxis := row - 1
  119. yAxis := titleToNumber(col)
  120. rows := xAxis + 1
  121. cell := yAxis + 1
  122. completeRow(xlsx, rows, cell)
  123. completeCol(xlsx, rows, cell)
  124. if xlsx.SheetData.Row[xAxis].C[yAxis].F != nil {
  125. xlsx.SheetData.Row[xAxis].C[yAxis].F.Content = formula
  126. } else {
  127. f := xlsxF{
  128. Content: formula,
  129. }
  130. xlsx.SheetData.Row[xAxis].C[yAxis].F = &f
  131. }
  132. }
  133. // SetCellHyperLink provides function to set cell hyperlink by given sheet index
  134. // and link URL address. Only support external link currently.
  135. func (f *File) SetCellHyperLink(sheet, axis, link string) {
  136. xlsx := f.workSheetReader(sheet)
  137. axis = strings.ToUpper(axis)
  138. f.mergeCellsParser(xlsx, axis)
  139. rID := f.addSheetRelationships(sheet, SourceRelationshipHyperLink, link, "External")
  140. hyperlink := xlsxHyperlink{
  141. Ref: axis,
  142. RID: "rId" + strconv.Itoa(rID),
  143. }
  144. if xlsx.Hyperlinks != nil {
  145. xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink, hyperlink)
  146. } else {
  147. hyperlinks := xlsxHyperlinks{}
  148. hyperlinks.Hyperlink = append(hyperlinks.Hyperlink, hyperlink)
  149. xlsx.Hyperlinks = &hyperlinks
  150. }
  151. }
  152. // MergeCell provides function to merge cells by given coordinate area and sheet
  153. // name. For example create a merged cell of D3:E9 on Sheet1:
  154. //
  155. // xlsx.MergeCell("sheet1", "D3", "E9")
  156. //
  157. // If you create a merged cell that overlaps with another existing merged cell,
  158. // those merged cells that already exist will be removed.
  159. func (f *File) MergeCell(sheet, hcell, vcell string) {
  160. if hcell == vcell {
  161. return
  162. }
  163. hcell = strings.ToUpper(hcell)
  164. vcell = strings.ToUpper(vcell)
  165. // Coordinate conversion, convert C1:B3 to 2,0,1,2.
  166. hcol := string(strings.Map(letterOnlyMapF, hcell))
  167. hrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, hcell))
  168. hyAxis := hrow - 1
  169. hxAxis := titleToNumber(hcol)
  170. vcol := string(strings.Map(letterOnlyMapF, vcell))
  171. vrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, vcell))
  172. vyAxis := vrow - 1
  173. vxAxis := titleToNumber(vcol)
  174. if vxAxis < hxAxis {
  175. hcell, vcell = vcell, hcell
  176. vxAxis, hxAxis = hxAxis, vxAxis
  177. }
  178. if vyAxis < hyAxis {
  179. hcell, vcell = vcell, hcell
  180. vyAxis, hyAxis = hyAxis, vyAxis
  181. }
  182. xlsx := f.workSheetReader(sheet)
  183. if xlsx.MergeCells != nil {
  184. mergeCell := xlsxMergeCell{}
  185. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  186. mergeCell.Ref = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1)
  187. // Delete the merged cells of the overlapping area.
  188. for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
  189. if checkCellInArea(hcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0], mergeCell.Ref) {
  190. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
  191. } else if checkCellInArea(vcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[1], mergeCell.Ref) {
  192. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
  193. }
  194. }
  195. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &mergeCell)
  196. } else {
  197. mergeCell := xlsxMergeCell{}
  198. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  199. mergeCell.Ref = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1)
  200. mergeCells := xlsxMergeCells{}
  201. mergeCells.Cells = append(mergeCells.Cells, &mergeCell)
  202. xlsx.MergeCells = &mergeCells
  203. }
  204. }
  205. // checkCellInArea provides function to determine if a given coordinate is
  206. // within an area.
  207. func checkCellInArea(cell, area string) bool {
  208. result := false
  209. cell = strings.ToUpper(cell)
  210. col := string(strings.Map(letterOnlyMapF, cell))
  211. row, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
  212. xAxis := row - 1
  213. yAxis := titleToNumber(col)
  214. ref := strings.Split(area, ":")
  215. hCol := string(strings.Map(letterOnlyMapF, ref[0]))
  216. hRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, ref[0]))
  217. hyAxis := hRow - 1
  218. hxAxis := titleToNumber(hCol)
  219. vCol := string(strings.Map(letterOnlyMapF, ref[1]))
  220. vRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, ref[1]))
  221. vyAxis := vRow - 1
  222. vxAxis := titleToNumber(vCol)
  223. if hxAxis <= yAxis && yAxis <= vxAxis && hyAxis <= xAxis && xAxis <= vyAxis {
  224. result = true
  225. }
  226. return result
  227. }