diff options
Diffstat (limited to 'cell.go')
-rw-r--r-- | cell.go | 151 |
1 files changed, 124 insertions, 27 deletions
@@ -30,8 +30,10 @@ const ( CellTypeBool CellTypeDate CellTypeError + CellTypeFormula + CellTypeInlineString CellTypeNumber - CellTypeString + CellTypeSharedString ) const ( @@ -51,9 +53,9 @@ var cellTypes = map[string]CellType{ "d": CellTypeDate, "n": CellTypeNumber, "e": CellTypeError, - "s": CellTypeString, - "str": CellTypeString, - "inlineStr": CellTypeString, + "s": CellTypeSharedString, + "str": CellTypeFormula, + "inlineStr": CellTypeInlineString, } // GetCellValue provides a function to get formatted value from cell by given @@ -235,8 +237,7 @@ func (f *File) setCellTimeFunc(sheet, cell string, value time.Time) error { date1904 = wb.WorkbookPr.Date1904 } var isNum bool - c.T, c.V, isNum, err = setCellTime(value, date1904) - if err != nil { + if isNum, err = c.setCellTime(value, date1904); err != nil { return err } if isNum { @@ -247,7 +248,7 @@ func (f *File) setCellTimeFunc(sheet, cell string, value time.Time) error { // setCellTime prepares cell type and Excel time by given Go time.Time type // timestamp. -func setCellTime(value time.Time, date1904 bool) (t string, b string, isNum bool, err error) { +func (c *xlsxC) setCellTime(value time.Time, date1904 bool) (isNum bool, err error) { var excelTime float64 _, offset := value.In(value.Location()).Zone() value = value.Add(time.Duration(offset) * time.Second) @@ -256,9 +257,9 @@ func setCellTime(value time.Time, date1904 bool) (t string, b string, isNum bool } isNum = excelTime > 0 if isNum { - t, b = setCellDefault(strconv.FormatFloat(excelTime, 'f', -1, 64)) + c.setCellDefault(strconv.FormatFloat(excelTime, 'f', -1, 64)) } else { - t, b = setCellDefault(value.Format(time.RFC3339Nano)) + c.setCellDefault(value.Format(time.RFC3339Nano)) } return } @@ -435,14 +436,14 @@ func (f *File) setSharedString(val string) (int, error) { sst.Count++ sst.UniqueCount++ t := xlsxT{Val: val} - _, val, t.Space = setCellStr(val) + val, t.Space = trimCellValue(val) sst.SI = append(sst.SI, xlsxSI{T: &t}) f.sharedStringsMap[val] = sst.UniqueCount - 1 return sst.UniqueCount - 1, nil } -// setCellStr provides a function to set string type to cell. -func setCellStr(value string) (t string, v string, ns xml.Attr) { +// trimCellValue provides a function to set string type to cell. +func trimCellValue(value string) (v string, ns xml.Attr) { if len(value) > TotalCellChars { value = value[:TotalCellChars] } @@ -458,10 +459,117 @@ func setCellStr(value string) (t string, v string, ns xml.Attr) { } } } - t, v = "str", bstrMarshal(value) + v = bstrMarshal(value) return } +// setCellValue set cell data type and value for (inline) rich string cell or +// formula cell. +func (c *xlsxC) setCellValue(val string) { + if c.F != nil { + c.setStr(val) + return + } + c.setInlineStr(val) +} + +// setInlineStr set cell data type and value which containing an (inline) rich +// string. +func (c *xlsxC) setInlineStr(val string) { + c.T, c.V, c.IS = "inlineStr", "", &xlsxSI{T: &xlsxT{}} + c.IS.T.Val, c.IS.T.Space = trimCellValue(val) +} + +// setStr set cell data type and value which containing a formula string. +func (c *xlsxC) setStr(val string) { + c.T, c.IS = "str", nil + c.V, c.XMLSpace = trimCellValue(val) +} + +// getCellDate parse cell value which containing a boolean. +func (c *xlsxC) getCellBool(f *File, raw bool) (string, error) { + if !raw { + if c.V == "1" { + return "TRUE", nil + } + if c.V == "0" { + return "FALSE", nil + } + } + return f.formattedValue(c.S, c.V, raw), nil +} + +// setCellDefault prepares cell type and string type cell value by a given +// string. +func (c *xlsxC) setCellDefault(value string) { + if ok, _, _ := isNumeric(value); !ok { + c.setInlineStr(value) + c.IS.T.Val = value + return + } + c.V = value +} + +// getCellDate parse cell value which contains a date in the ISO 8601 format. +func (c *xlsxC) getCellDate(f *File, raw bool) (string, error) { + if !raw { + layout := "20060102T150405.999" + if strings.HasSuffix(c.V, "Z") { + layout = "20060102T150405Z" + if strings.Contains(c.V, "-") { + layout = "2006-01-02T15:04:05Z" + } + } else if strings.Contains(c.V, "-") { + layout = "2006-01-02 15:04:05Z" + } + if timestamp, err := time.Parse(layout, strings.ReplaceAll(c.V, ",", ".")); err == nil { + excelTime, _ := timeToExcelTime(timestamp, false) + c.V = strconv.FormatFloat(excelTime, 'G', 15, 64) + } + } + return f.formattedValue(c.S, c.V, raw), nil +} + +// getValueFrom return a value from a column/row cell, this function is +// intended to be used with for range on rows an argument with the spreadsheet +// opened file. +func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) { + f.Lock() + defer f.Unlock() + switch c.T { + case "b": + return c.getCellBool(f, raw) + case "d": + return c.getCellDate(f, raw) + case "s": + if c.V != "" { + xlsxSI := 0 + xlsxSI, _ = strconv.Atoi(c.V) + if _, ok := f.tempFiles.Load(defaultXMLPathSharedStrings); ok { + return f.formattedValue(c.S, f.getFromStringItem(xlsxSI), raw), nil + } + if len(d.SI) > xlsxSI { + return f.formattedValue(c.S, d.SI[xlsxSI].String(), raw), nil + } + } + return f.formattedValue(c.S, c.V, raw), nil + case "inlineStr": + if c.IS != nil { + return f.formattedValue(c.S, c.IS.String(), raw), nil + } + return f.formattedValue(c.S, c.V, raw), nil + default: + if isNum, precision, decimal := isNumeric(c.V); isNum && !raw { + if precision > 15 { + c.V = strconv.FormatFloat(decimal, 'G', 15, 64) + } else { + c.V = strconv.FormatFloat(decimal, 'f', -1, 64) + } + } + return f.formattedValue(c.S, c.V, raw), nil + } +} + // SetCellDefault provides a function to set string type value of a cell as // default format without escaping the cell. func (f *File) SetCellDefault(sheet, cell, value string) error { @@ -476,22 +584,11 @@ func (f *File) SetCellDefault(sheet, cell, value string) error { ws.Lock() defer ws.Unlock() c.S = f.prepareCellStyle(ws, col, row, c.S) - c.T, c.V = setCellDefault(value) - c.IS = nil + c.setCellDefault(value) f.removeFormula(c, ws, sheet) return err } -// setCellDefault prepares cell type and string type cell value by a given -// string. -func setCellDefault(value string) (t string, v string) { - if ok, _, _ := isNumeric(value); !ok { - t = "str" - } - v = value - return -} - // GetCellFormula provides a function to get formula from cell by given // worksheet name and cell reference in spreadsheet. func (f *File) GetCellFormula(sheet, cell string) (string, error) { @@ -625,7 +722,7 @@ func (f *File) SetCellFormula(sheet, cell, formula string, opts ...FormulaOpts) c.F.Ref = *opt.Ref } } - c.IS = nil + c.T, c.IS = "str", nil return err } @@ -900,7 +997,7 @@ func setRichText(runs []RichTextRun) ([]xlsxR, error) { return textRuns, ErrCellCharsLength } run := xlsxR{T: &xlsxT{}} - _, run.T.Val, run.T.Space = setCellStr(textRun.Text) + run.T.Val, run.T.Space = trimCellValue(textRun.Text) fnt := textRun.Font if fnt != nil { run.RPr = newRpr(fnt) |