cell.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. package xlsx
  2. import (
  3. "fmt"
  4. "math"
  5. "strconv"
  6. "strings"
  7. )
  8. // Cell is a high level structure intended to provide user access to
  9. // the contents of Cell within an xlsx.Row.
  10. type Cell struct {
  11. Value string
  12. styleIndex int
  13. styles *xlsxStyles
  14. numFmtRefTable map[int]xlsxNumFmt
  15. date1904 bool
  16. Hidden bool
  17. }
  18. // CellInterface defines the public API of the Cell.
  19. type CellInterface interface {
  20. String() string
  21. FormattedValue() string
  22. }
  23. // String returns the value of a Cell as a string.
  24. func (c *Cell) String() string {
  25. return c.FormattedValue()
  26. }
  27. // GetStyle returns the Style associated with a Cell
  28. func (c *Cell) GetStyle() Style {
  29. var err error
  30. style := Style{}
  31. style.Border = Border{}
  32. style.Fill = Fill{}
  33. style.Font = Font{}
  34. if c.styleIndex > -1 && c.styleIndex <= len(c.styles.CellXfs) {
  35. xf := c.styles.CellXfs[c.styleIndex]
  36. if xf.ApplyBorder {
  37. style.Border.Left = c.styles.Borders[xf.BorderId].Left.Style
  38. style.Border.Right = c.styles.Borders[xf.BorderId].Right.Style
  39. style.Border.Top = c.styles.Borders[xf.BorderId].Top.Style
  40. style.Border.Bottom = c.styles.Borders[xf.BorderId].Bottom.Style
  41. }
  42. // TODO - consider how to handle the fact that
  43. // ApplyFill can be missing. At the moment the XML
  44. // unmarshaller simply sets it to false, which creates
  45. // a bug.
  46. // if xf.ApplyFill {
  47. if xf.FillId > -1 && xf.FillId < len(c.styles.Fills) {
  48. xFill := c.styles.Fills[xf.FillId]
  49. style.Fill.PatternType = xFill.PatternFill.PatternType
  50. style.Fill.FgColor = xFill.PatternFill.FgColor.RGB
  51. style.Fill.BgColor = xFill.PatternFill.BgColor.RGB
  52. }
  53. // }
  54. if xf.ApplyFont {
  55. xfont := c.styles.Fonts[xf.FontId]
  56. style.Font.Size, err = strconv.Atoi(xfont.Sz.Val)
  57. if err != nil {
  58. panic(err.Error())
  59. }
  60. style.Font.Name = xfont.Name.Val
  61. style.Font.Family, _ = strconv.Atoi(xfont.Family.Val)
  62. style.Font.Charset, _ = strconv.Atoi(xfont.Charset.Val)
  63. }
  64. }
  65. return style
  66. }
  67. // The number format string is returnable from a cell.
  68. func (c *Cell) GetNumberFormat() string {
  69. if c.styles == nil {
  70. return ""
  71. }
  72. if c.styles.CellXfs == nil {
  73. return ""
  74. }
  75. var numberFormat string = ""
  76. if c.styleIndex > -1 && c.styleIndex <= len(c.styles.CellXfs) {
  77. xf := c.styles.CellXfs[c.styleIndex]
  78. numFmt := c.numFmtRefTable[xf.NumFmtId]
  79. numberFormat = numFmt.FormatCode
  80. }
  81. return strings.ToLower(numberFormat)
  82. }
  83. func (c *Cell) formatToTime(format string) string {
  84. f, err := strconv.ParseFloat(c.Value, 64)
  85. if err != nil {
  86. return err.Error()
  87. }
  88. return TimeFromExcelTime(f, c.date1904).Format(format)
  89. }
  90. func (c *Cell) formatToFloat(format string) string {
  91. f, err := strconv.ParseFloat(c.Value, 64)
  92. if err != nil {
  93. return err.Error()
  94. }
  95. return fmt.Sprintf(format, f)
  96. }
  97. func (c *Cell) formatToInt(format string) string {
  98. f, err := strconv.ParseFloat(c.Value, 64)
  99. if err != nil {
  100. return err.Error()
  101. }
  102. return fmt.Sprintf(format, int(f))
  103. }
  104. // Return the formatted version of the value.
  105. func (c *Cell) FormattedValue() string {
  106. var numberFormat string = c.GetNumberFormat()
  107. switch numberFormat {
  108. case "general":
  109. return c.Value
  110. case "0", "#,##0":
  111. return c.formatToInt("%d")
  112. case "0.00", "#,##0.00", "@":
  113. return c.formatToFloat("%.2f")
  114. case "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)":
  115. f, err := strconv.ParseFloat(c.Value, 64)
  116. if err != nil {
  117. return err.Error()
  118. }
  119. if f < 0 {
  120. i := int(math.Abs(f))
  121. return fmt.Sprintf("(%d)", i)
  122. }
  123. i := int(f)
  124. return fmt.Sprintf("%d", i)
  125. case "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)":
  126. f, err := strconv.ParseFloat(c.Value, 64)
  127. if err != nil {
  128. return err.Error()
  129. }
  130. if f < 0 {
  131. return fmt.Sprintf("(%.2f)", f)
  132. }
  133. return fmt.Sprintf("%.2f", f)
  134. case "0%":
  135. f, err := strconv.ParseFloat(c.Value, 64)
  136. if err != nil {
  137. return err.Error()
  138. }
  139. f = f * 100
  140. return fmt.Sprintf("%d%%", int(f))
  141. case "0.00%":
  142. f, err := strconv.ParseFloat(c.Value, 64)
  143. if err != nil {
  144. return err.Error()
  145. }
  146. f = f * 100
  147. return fmt.Sprintf("%.2f%%", f)
  148. case "0.00e+00", "##0.0e+0":
  149. return c.formatToFloat("%e")
  150. case "mm-dd-yy":
  151. return c.formatToTime("01-02-06")
  152. case "d-mmm-yy":
  153. return c.formatToTime("2-Jan-06")
  154. case "d-mmm":
  155. return c.formatToTime("2-Jan")
  156. case "mmm-yy":
  157. return c.formatToTime("Jan-06")
  158. case "h:mm am/pm":
  159. return c.formatToTime("3:04 pm")
  160. case "h:mm:ss am/pm":
  161. return c.formatToTime("3:04:05 pm")
  162. case "h:mm":
  163. return c.formatToTime("15:04")
  164. case "h:mm:ss":
  165. return c.formatToTime("15:04:05")
  166. case "m/d/yy h:mm":
  167. return c.formatToTime("1/2/06 15:04")
  168. case "mm:ss":
  169. return c.formatToTime("04:05")
  170. case "[h]:mm:ss":
  171. f, err := strconv.ParseFloat(c.Value, 64)
  172. if err != nil {
  173. return err.Error()
  174. }
  175. t := TimeFromExcelTime(f, c.date1904)
  176. if t.Hour() > 0 {
  177. return t.Format("15:04:05")
  178. }
  179. return t.Format("04:05")
  180. case "mmss.0":
  181. f, err := strconv.ParseFloat(c.Value, 64)
  182. if err != nil {
  183. return err.Error()
  184. }
  185. t := TimeFromExcelTime(f, c.date1904)
  186. return fmt.Sprintf("%0d%0d.%d", t.Minute(), t.Second(), t.Nanosecond()/1000)
  187. case "yyyy\\-mm\\-dd":
  188. return c.formatToTime("2006\\-01\\-02")
  189. case "dd/mm/yy":
  190. return c.formatToTime("02/01/06")
  191. case "hh:mm:ss":
  192. return c.formatToTime("15:04:05")
  193. case "dd/mm/yy\\ hh:mm":
  194. return c.formatToTime("02/01/06\\ 15:04")
  195. case "dd/mm/yyyy hh:mm:ss":
  196. return c.formatToTime("02/01/2006 15:04:05")
  197. case "yy-mm-dd":
  198. return c.formatToTime("06-01-02")
  199. case "d-mmm-yyyy":
  200. return c.formatToTime("2-Jan-2006")
  201. case "m/d/yy":
  202. return c.formatToTime("1/2/06")
  203. case "m/d/yyyy":
  204. return c.formatToTime("1/2/2006")
  205. case "dd-mmm-yyyy":
  206. return c.formatToTime("02-Jan-2006")
  207. case "dd/mm/yyyy":
  208. return c.formatToTime("02/01/2006")
  209. case "mm/dd/yy hh:mm am/pm":
  210. return c.formatToTime("01/02/06 03:04 pm")
  211. case "mm/dd/yyyy hh:mm:ss":
  212. return c.formatToTime("01/02/2006 15:04:05")
  213. case "yyyy-mm-dd hh:mm:ss":
  214. return c.formatToTime("2006-01-02 15:04:05")
  215. }
  216. return c.Value
  217. }
  218. func (c *Cell) SetStyle(style *Style) int {
  219. if c.styles == nil {
  220. c.styles = &xlsxStyles{}
  221. }
  222. index := len(c.styles.Fonts)
  223. xFont := xlsxFont{}
  224. xFill := xlsxFill{}
  225. xBorder := xlsxBorder{}
  226. xCellStyleXf := xlsxXf{}
  227. xCellXf := xlsxXf{}
  228. xFont.Sz.Val = strconv.Itoa(style.Font.Size)
  229. xFont.Name.Val = style.Font.Name
  230. xFont.Family.Val = strconv.Itoa(style.Font.Family)
  231. xFont.Charset.Val = strconv.Itoa(style.Font.Charset)
  232. xPatternFill := xlsxPatternFill{}
  233. xPatternFill.PatternType = style.Fill.PatternType
  234. xPatternFill.FgColor.RGB = style.Fill.FgColor
  235. xPatternFill.BgColor.RGB = style.Fill.BgColor
  236. xFill.PatternFill = xPatternFill
  237. c.styles.Fonts = append(c.styles.Fonts, xFont)
  238. c.styles.Fills = append(c.styles.Fills, xFill)
  239. c.styles.Borders = append(c.styles.Borders, xBorder)
  240. c.styles.CellStyleXfs = append(c.styles.CellStyleXfs, xCellStyleXf)
  241. c.styles.CellXfs = append(c.styles.CellXfs, xCellXf)
  242. return index
  243. }