cell.go 7.5 KB

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