cell.go 7.6 KB

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