cell.go 6.9 KB

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