cell.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. package excelize
  2. import (
  3. "encoding/xml"
  4. "fmt"
  5. "reflect"
  6. "strconv"
  7. "strings"
  8. "time"
  9. )
  10. const (
  11. // STCellFormulaTypeArray defined the formula is an array formula.
  12. STCellFormulaTypeArray = "array"
  13. // STCellFormulaTypeDataTable defined the formula is a data table formula.
  14. STCellFormulaTypeDataTable = "dataTable"
  15. // STCellFormulaTypeNormal defined the formula is a regular cell formula.
  16. STCellFormulaTypeNormal = "normal"
  17. // STCellFormulaTypeShared defined the formula is part of a shared formula.
  18. STCellFormulaTypeShared = "shared"
  19. )
  20. // mergeCellsParser provides a function to check merged cells in worksheet by
  21. // given axis.
  22. func (f *File) mergeCellsParser(xlsx *xlsxWorksheet, axis string) string {
  23. axis = strings.ToUpper(axis)
  24. if xlsx.MergeCells != nil {
  25. for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
  26. if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
  27. axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0]
  28. }
  29. }
  30. }
  31. return axis
  32. }
  33. // SetCellValue provides a function to set value of a cell. The following
  34. // shows the supported data types:
  35. //
  36. // int
  37. // int8
  38. // int16
  39. // int32
  40. // int64
  41. // uint
  42. // uint8
  43. // uint16
  44. // uint32
  45. // uint64
  46. // float32
  47. // float64
  48. // string
  49. // []byte
  50. // time.Duration
  51. // time.Time
  52. // bool
  53. // nil
  54. //
  55. // Note that default date format is m/d/yy h:mm of time.Time type value. You can
  56. // set numbers format by SetCellStyle() method.
  57. func (f *File) SetCellValue(sheet, axis string, value interface{}) {
  58. switch t := value.(type) {
  59. case float32:
  60. f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(float32)), 'f', -1, 32))
  61. case float64:
  62. f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(float64)), 'f', -1, 64))
  63. case string:
  64. f.SetCellStr(sheet, axis, t)
  65. case []byte:
  66. f.SetCellStr(sheet, axis, string(t))
  67. case time.Duration:
  68. f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(time.Duration).Seconds()/86400), 'f', -1, 32))
  69. f.setDefaultTimeStyle(sheet, axis, 21)
  70. case time.Time:
  71. f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(timeToExcelTime(timeToUTCTime(value.(time.Time)))), 'f', -1, 64))
  72. f.setDefaultTimeStyle(sheet, axis, 22)
  73. case nil:
  74. f.SetCellStr(sheet, axis, "")
  75. case bool:
  76. f.SetCellBool(sheet, axis, bool(value.(bool)))
  77. default:
  78. f.setCellIntValue(sheet, axis, value)
  79. }
  80. }
  81. // setCellIntValue provides a function to set int value of a cell.
  82. func (f *File) setCellIntValue(sheet, axis string, value interface{}) {
  83. switch value.(type) {
  84. case int:
  85. f.SetCellInt(sheet, axis, value.(int))
  86. case int8:
  87. f.SetCellInt(sheet, axis, int(value.(int8)))
  88. case int16:
  89. f.SetCellInt(sheet, axis, int(value.(int16)))
  90. case int32:
  91. f.SetCellInt(sheet, axis, int(value.(int32)))
  92. case int64:
  93. f.SetCellInt(sheet, axis, int(value.(int64)))
  94. case uint:
  95. f.SetCellInt(sheet, axis, int(value.(uint)))
  96. case uint8:
  97. f.SetCellInt(sheet, axis, int(value.(uint8)))
  98. case uint16:
  99. f.SetCellInt(sheet, axis, int(value.(uint16)))
  100. case uint32:
  101. f.SetCellInt(sheet, axis, int(value.(uint32)))
  102. case uint64:
  103. f.SetCellInt(sheet, axis, int(value.(uint64)))
  104. default:
  105. f.SetCellStr(sheet, axis, fmt.Sprintf("%v", value))
  106. }
  107. }
  108. // SetCellBool provides a function to set bool type value of a cell by given
  109. // worksheet name, cell coordinates and cell value.
  110. func (f *File) SetCellBool(sheet, axis string, value bool) {
  111. xlsx := f.workSheetReader(sheet)
  112. axis = f.mergeCellsParser(xlsx, axis)
  113. col := string(strings.Map(letterOnlyMapF, axis))
  114. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  115. if err != nil {
  116. return
  117. }
  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. xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
  125. xlsx.SheetData.Row[xAxis].C[yAxis].T = "b"
  126. if value {
  127. xlsx.SheetData.Row[xAxis].C[yAxis].V = "1"
  128. } else {
  129. xlsx.SheetData.Row[xAxis].C[yAxis].V = "0"
  130. }
  131. }
  132. // GetCellValue provides a function to get formatted value from cell by given
  133. // worksheet name and axis in XLSX file. If it is possible to apply a format
  134. // to the cell value, it will do so, if not then an error will be returned,
  135. // along with the raw value of the cell.
  136. func (f *File) GetCellValue(sheet, axis string) string {
  137. xlsx := f.workSheetReader(sheet)
  138. axis = f.mergeCellsParser(xlsx, axis)
  139. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  140. if err != nil {
  141. return ""
  142. }
  143. xAxis := row - 1
  144. rows := len(xlsx.SheetData.Row)
  145. if rows > 1 {
  146. lastRow := xlsx.SheetData.Row[rows-1].R
  147. if lastRow >= rows {
  148. rows = lastRow
  149. }
  150. }
  151. if rows < xAxis {
  152. return ""
  153. }
  154. for k := range xlsx.SheetData.Row {
  155. if xlsx.SheetData.Row[k].R == row {
  156. for i := range xlsx.SheetData.Row[k].C {
  157. if axis == xlsx.SheetData.Row[k].C[i].R {
  158. val, _ := xlsx.SheetData.Row[k].C[i].getValueFrom(f, f.sharedStringsReader())
  159. return val
  160. }
  161. }
  162. }
  163. }
  164. return ""
  165. }
  166. // formattedValue provides a function to returns a value after formatted. If
  167. // it is possible to apply a format to the cell value, it will do so, if not
  168. // then an error will be returned, along with the raw value of the cell.
  169. func (f *File) formattedValue(s int, v string) string {
  170. if s == 0 {
  171. return v
  172. }
  173. styleSheet := f.stylesReader()
  174. ok := builtInNumFmtFunc[styleSheet.CellXfs.Xf[s].NumFmtID]
  175. if ok != nil {
  176. return ok(styleSheet.CellXfs.Xf[s].NumFmtID, v)
  177. }
  178. return v
  179. }
  180. // GetCellStyle provides a function to get cell style index by given worksheet
  181. // name and cell coordinates.
  182. func (f *File) GetCellStyle(sheet, axis string) int {
  183. xlsx := f.workSheetReader(sheet)
  184. axis = f.mergeCellsParser(xlsx, axis)
  185. col := string(strings.Map(letterOnlyMapF, axis))
  186. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  187. if err != nil {
  188. return 0
  189. }
  190. xAxis := row - 1
  191. yAxis := TitleToNumber(col)
  192. rows := xAxis + 1
  193. cell := yAxis + 1
  194. completeRow(xlsx, rows, cell)
  195. completeCol(xlsx, rows, cell)
  196. return f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
  197. }
  198. // GetCellFormula provides a function to get formula from cell by given
  199. // worksheet name and axis in XLSX file.
  200. func (f *File) GetCellFormula(sheet, axis string) string {
  201. xlsx := f.workSheetReader(sheet)
  202. axis = f.mergeCellsParser(xlsx, axis)
  203. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  204. if err != nil {
  205. return ""
  206. }
  207. xAxis := row - 1
  208. rows := len(xlsx.SheetData.Row)
  209. if rows > 1 {
  210. lastRow := xlsx.SheetData.Row[rows-1].R
  211. if lastRow >= rows {
  212. rows = lastRow
  213. }
  214. }
  215. if rows < xAxis {
  216. return ""
  217. }
  218. for k := range xlsx.SheetData.Row {
  219. if xlsx.SheetData.Row[k].R == row {
  220. for i := range xlsx.SheetData.Row[k].C {
  221. if axis == xlsx.SheetData.Row[k].C[i].R {
  222. if xlsx.SheetData.Row[k].C[i].F.T == STCellFormulaTypeShared {
  223. return getSharedForumula(xlsx, xlsx.SheetData.Row[k].C[i].F.Si)
  224. }
  225. if xlsx.SheetData.Row[k].C[i].F != nil {
  226. return xlsx.SheetData.Row[k].C[i].F.Content
  227. }
  228. }
  229. }
  230. }
  231. }
  232. return ""
  233. }
  234. // getSharedForumula find a cell contains the same formula as another cell,
  235. // the "shared" value can be used for the t attribute and the si attribute can
  236. // be used to refer to the cell containing the formula. Two formulas are
  237. // considered to be the same when their respective representations in
  238. // R1C1-reference notation, are the same.
  239. //
  240. // Note that this function not validate ref tag to check the cell if or not in
  241. // allow area, and always return origin shared formula.
  242. func getSharedForumula(xlsx *xlsxWorksheet, si string) string {
  243. for k := range xlsx.SheetData.Row {
  244. for i := range xlsx.SheetData.Row[k].C {
  245. if xlsx.SheetData.Row[k].C[i].F == nil {
  246. continue
  247. }
  248. if xlsx.SheetData.Row[k].C[i].F.T != STCellFormulaTypeShared {
  249. continue
  250. }
  251. if xlsx.SheetData.Row[k].C[i].F.Si != si {
  252. continue
  253. }
  254. if xlsx.SheetData.Row[k].C[i].F.Ref != "" {
  255. return xlsx.SheetData.Row[k].C[i].F.Content
  256. }
  257. }
  258. }
  259. return ""
  260. }
  261. // SetCellFormula provides a function to set cell formula by given string and
  262. // worksheet name.
  263. func (f *File) SetCellFormula(sheet, axis, formula string) {
  264. xlsx := f.workSheetReader(sheet)
  265. axis = f.mergeCellsParser(xlsx, axis)
  266. col := string(strings.Map(letterOnlyMapF, axis))
  267. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  268. if err != nil {
  269. return
  270. }
  271. xAxis := row - 1
  272. yAxis := TitleToNumber(col)
  273. rows := xAxis + 1
  274. cell := yAxis + 1
  275. completeRow(xlsx, rows, cell)
  276. completeCol(xlsx, rows, cell)
  277. if xlsx.SheetData.Row[xAxis].C[yAxis].F != nil {
  278. xlsx.SheetData.Row[xAxis].C[yAxis].F.Content = formula
  279. } else {
  280. f := xlsxF{
  281. Content: formula,
  282. }
  283. xlsx.SheetData.Row[xAxis].C[yAxis].F = &f
  284. }
  285. }
  286. // SetCellHyperLink provides a function to set cell hyperlink by given
  287. // worksheet name and link URL address. LinkType defines two types of
  288. // hyperlink "External" for web site or "Location" for moving to one of cell
  289. // in this workbook. The below is example for external link.
  290. //
  291. // xlsx.SetCellHyperLink("Sheet1", "A3", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
  292. // // Set underline and font color style for the cell.
  293. // style, _ := xlsx.NewStyle(`{"font":{"color":"#1265BE","underline":"single"}}`)
  294. // xlsx.SetCellStyle("Sheet1", "A3", "A3", style)
  295. //
  296. // A this is another example for "Location":
  297. //
  298. // xlsx.SetCellHyperLink("Sheet1", "A3", "Sheet1!A40", "Location")
  299. //
  300. func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) {
  301. xlsx := f.workSheetReader(sheet)
  302. axis = f.mergeCellsParser(xlsx, axis)
  303. linkTypes := map[string]xlsxHyperlink{
  304. "External": {},
  305. "Location": {Location: link},
  306. }
  307. hyperlink, ok := linkTypes[linkType]
  308. if !ok || axis == "" {
  309. return
  310. }
  311. hyperlink.Ref = axis
  312. if linkType == "External" {
  313. rID := f.addSheetRelationships(sheet, SourceRelationshipHyperLink, link, linkType)
  314. hyperlink.RID = "rId" + strconv.Itoa(rID)
  315. }
  316. if xlsx.Hyperlinks == nil {
  317. xlsx.Hyperlinks = &xlsxHyperlinks{}
  318. }
  319. xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink, hyperlink)
  320. }
  321. // GetCellHyperLink provides a function to get cell hyperlink by given
  322. // worksheet name and axis. Boolean type value link will be ture if the cell
  323. // has a hyperlink and the target is the address of the hyperlink. Otherwise,
  324. // the value of link will be false and the value of the target will be a blank
  325. // string. For example get hyperlink of Sheet1!H6:
  326. //
  327. // link, target := xlsx.GetCellHyperLink("Sheet1", "H6")
  328. //
  329. func (f *File) GetCellHyperLink(sheet, axis string) (bool, string) {
  330. var link bool
  331. var target string
  332. xlsx := f.workSheetReader(sheet)
  333. axis = f.mergeCellsParser(xlsx, axis)
  334. if xlsx.Hyperlinks == nil || axis == "" {
  335. return link, target
  336. }
  337. for h := range xlsx.Hyperlinks.Hyperlink {
  338. if xlsx.Hyperlinks.Hyperlink[h].Ref == axis {
  339. link = true
  340. target = xlsx.Hyperlinks.Hyperlink[h].Location
  341. if xlsx.Hyperlinks.Hyperlink[h].RID != "" {
  342. target = f.getSheetRelationshipsTargetByID(sheet, xlsx.Hyperlinks.Hyperlink[h].RID)
  343. }
  344. }
  345. }
  346. return link, target
  347. }
  348. // MergeCell provides a function to merge cells by given coordinate area and
  349. // sheet name. For example create a merged cell of D3:E9 on Sheet1:
  350. //
  351. // xlsx.MergeCell("Sheet1", "D3", "E9")
  352. //
  353. // If you create a merged cell that overlaps with another existing merged cell,
  354. // those merged cells that already exist will be removed.
  355. func (f *File) MergeCell(sheet, hcell, vcell string) {
  356. if hcell == vcell {
  357. return
  358. }
  359. hcell = strings.ToUpper(hcell)
  360. vcell = strings.ToUpper(vcell)
  361. // Coordinate conversion, convert C1:B3 to 2,0,1,2.
  362. hcol := string(strings.Map(letterOnlyMapF, hcell))
  363. hrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, hcell))
  364. hyAxis := hrow - 1
  365. hxAxis := TitleToNumber(hcol)
  366. vcol := string(strings.Map(letterOnlyMapF, vcell))
  367. vrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, vcell))
  368. vyAxis := vrow - 1
  369. vxAxis := TitleToNumber(vcol)
  370. if vxAxis < hxAxis {
  371. hcell, vcell = vcell, hcell
  372. vxAxis, hxAxis = hxAxis, vxAxis
  373. }
  374. if vyAxis < hyAxis {
  375. hcell, vcell = vcell, hcell
  376. vyAxis, hyAxis = hyAxis, vyAxis
  377. }
  378. xlsx := f.workSheetReader(sheet)
  379. if xlsx.MergeCells != nil {
  380. mergeCell := xlsxMergeCell{}
  381. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  382. mergeCell.Ref = ToAlphaString(hxAxis) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis) + strconv.Itoa(vyAxis+1)
  383. // Delete the merged cells of the overlapping area.
  384. for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
  385. if checkCellInArea(hcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0], mergeCell.Ref) {
  386. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
  387. } else if checkCellInArea(vcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[1], mergeCell.Ref) {
  388. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
  389. }
  390. }
  391. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &mergeCell)
  392. } else {
  393. mergeCell := xlsxMergeCell{}
  394. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  395. mergeCell.Ref = ToAlphaString(hxAxis) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis) + strconv.Itoa(vyAxis+1)
  396. mergeCells := xlsxMergeCells{}
  397. mergeCells.Cells = append(mergeCells.Cells, &mergeCell)
  398. xlsx.MergeCells = &mergeCells
  399. }
  400. }
  401. // SetCellInt provides a function to set int type value of a cell by given
  402. // worksheet name, cell coordinates and cell value.
  403. func (f *File) SetCellInt(sheet, axis string, value int) {
  404. xlsx := f.workSheetReader(sheet)
  405. axis = f.mergeCellsParser(xlsx, axis)
  406. col := string(strings.Map(letterOnlyMapF, axis))
  407. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  408. if err != nil {
  409. return
  410. }
  411. xAxis := row - 1
  412. yAxis := TitleToNumber(col)
  413. rows := xAxis + 1
  414. cell := yAxis + 1
  415. completeRow(xlsx, rows, cell)
  416. completeCol(xlsx, rows, cell)
  417. xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
  418. xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
  419. xlsx.SheetData.Row[xAxis].C[yAxis].V = strconv.Itoa(value)
  420. }
  421. // prepareCellStyle provides a function to prepare style index of cell in
  422. // worksheet by given column index and style index.
  423. func (f *File) prepareCellStyle(xlsx *xlsxWorksheet, col, style int) int {
  424. if xlsx.Cols != nil && style == 0 {
  425. for _, v := range xlsx.Cols.Col {
  426. if v.Min <= col && col <= v.Max {
  427. style = v.Style
  428. }
  429. }
  430. }
  431. return style
  432. }
  433. // SetCellStr provides a function to set string type value of a cell. Total
  434. // number of characters that a cell can contain 32767 characters.
  435. func (f *File) SetCellStr(sheet, axis, value string) {
  436. xlsx := f.workSheetReader(sheet)
  437. axis = f.mergeCellsParser(xlsx, axis)
  438. if len(value) > 32767 {
  439. value = value[0:32767]
  440. }
  441. col := string(strings.Map(letterOnlyMapF, axis))
  442. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  443. if err != nil {
  444. return
  445. }
  446. xAxis := row - 1
  447. yAxis := TitleToNumber(col)
  448. rows := xAxis + 1
  449. cell := yAxis + 1
  450. completeRow(xlsx, rows, cell)
  451. completeCol(xlsx, rows, cell)
  452. // Leading space(s) character detection.
  453. if len(value) > 0 {
  454. if value[0] == 32 {
  455. xlsx.SheetData.Row[xAxis].C[yAxis].XMLSpace = xml.Attr{
  456. Name: xml.Name{Space: NameSpaceXML, Local: "space"},
  457. Value: "preserve",
  458. }
  459. }
  460. }
  461. xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
  462. xlsx.SheetData.Row[xAxis].C[yAxis].T = "str"
  463. xlsx.SheetData.Row[xAxis].C[yAxis].V = value
  464. }
  465. // SetCellDefault provides a function to set string type value of a cell as
  466. // default format without escaping the cell.
  467. func (f *File) SetCellDefault(sheet, axis, value string) {
  468. xlsx := f.workSheetReader(sheet)
  469. axis = f.mergeCellsParser(xlsx, axis)
  470. col := string(strings.Map(letterOnlyMapF, axis))
  471. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  472. if err != nil {
  473. return
  474. }
  475. xAxis := row - 1
  476. yAxis := TitleToNumber(col)
  477. rows := xAxis + 1
  478. cell := yAxis + 1
  479. completeRow(xlsx, rows, cell)
  480. completeCol(xlsx, rows, cell)
  481. xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
  482. xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
  483. xlsx.SheetData.Row[xAxis].C[yAxis].V = value
  484. }
  485. // SetSheetRow writes an array to row by given worksheet name, starting
  486. // coordinate and a pointer to array type 'slice'. For example, writes an
  487. // array to row 6 start with the cell B6 on Sheet1:
  488. //
  489. // xlsx.SetSheetRow("Sheet1", "B6", &[]interface{}{"1", nil, 2})
  490. //
  491. func (f *File) SetSheetRow(sheet, axis string, slice interface{}) {
  492. xlsx := f.workSheetReader(sheet)
  493. axis = f.mergeCellsParser(xlsx, axis)
  494. col := string(strings.Map(letterOnlyMapF, axis))
  495. row, err := strconv.Atoi(strings.Map(intOnlyMapF, axis))
  496. if err != nil {
  497. return
  498. }
  499. // Make sure 'slice' is a Ptr to Slice
  500. v := reflect.ValueOf(slice)
  501. if v.Kind() != reflect.Ptr {
  502. return
  503. }
  504. v = v.Elem()
  505. if v.Kind() != reflect.Slice {
  506. return
  507. }
  508. xAxis := row - 1
  509. yAxis := TitleToNumber(col)
  510. rows := xAxis + 1
  511. cell := yAxis + 1
  512. completeRow(xlsx, rows, cell)
  513. completeCol(xlsx, rows, cell)
  514. idx := 0
  515. for i := cell - 1; i < v.Len()+cell-1; i++ {
  516. c := ToAlphaString(i) + strconv.Itoa(row)
  517. f.SetCellValue(sheet, c, v.Index(idx).Interface())
  518. idx++
  519. }
  520. }
  521. // checkCellInArea provides a function to determine if a given coordinate is
  522. // within an area.
  523. func checkCellInArea(cell, area string) bool {
  524. cell = strings.ToUpper(cell)
  525. area = strings.ToUpper(area)
  526. ref := strings.Split(area, ":")
  527. if len(ref) < 2 {
  528. return false
  529. }
  530. from := ref[0]
  531. to := ref[1]
  532. col, row := getCellColRow(cell)
  533. fromCol, fromRow := getCellColRow(from)
  534. toCol, toRow := getCellColRow(to)
  535. return axisLowerOrEqualThan(fromCol, col) && axisLowerOrEqualThan(col, toCol) && axisLowerOrEqualThan(fromRow, row) && axisLowerOrEqualThan(row, toRow)
  536. }