cell.go 7.2 KB

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