cell.go 7.7 KB

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