summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2021-09-05 11:59:50 +0800
committerxuri <xuri.me@gmail.com>2021-09-05 11:59:50 +0800
commit32b23ef42d3ecb393e102c5f63ab5125db354435 (patch)
treee73ec4e2e062d15ca6d53407039ddb3004942995
parent2616aa88cb2b1e45c03ada60093f4dfe7fabfb87 (diff)
This closes #998
- Support text comparison in the formula, also ref #65 - `GetCellValue`, `GetRows`, `GetCols`, `Rows` and `Cols` support to specify read cell with raw value, ref #621 - Add missing properties for the cell formula - Update the unit test for the `CalcCellValue`
-rw-r--r--calc.go92
-rw-r--r--calc_test.go26
-rw-r--r--cell.go47
-rw-r--r--cell_test.go24
-rw-r--r--col.go10
-rw-r--r--excelize.go23
-rw-r--r--rows.go30
-rw-r--r--rows_test.go4
-rw-r--r--sheet.go2
-rw-r--r--xmlWorksheet.go13
10 files changed, 170 insertions, 101 deletions
diff --git a/calc.go b/calc.go
index 1fdaf6e..5661d7d 100644
--- a/calc.go
+++ b/calc.go
@@ -777,57 +777,25 @@ func calcNEq(rOpd, lOpd string, opdStack *Stack) error {
// calcL evaluate less than arithmetic operations.
func calcL(rOpd, lOpd string, opdStack *Stack) error {
- lOpdVal, err := strconv.ParseFloat(lOpd, 64)
- if err != nil {
- return err
- }
- rOpdVal, err := strconv.ParseFloat(rOpd, 64)
- if err != nil {
- return err
- }
- opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpdVal > lOpdVal)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
+ opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(strings.Compare(lOpd, rOpd) == -1)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
return nil
}
// calcLe evaluate less than or equal arithmetic operations.
func calcLe(rOpd, lOpd string, opdStack *Stack) error {
- lOpdVal, err := strconv.ParseFloat(lOpd, 64)
- if err != nil {
- return err
- }
- rOpdVal, err := strconv.ParseFloat(rOpd, 64)
- if err != nil {
- return err
- }
- opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpdVal >= lOpdVal)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
+ opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(strings.Compare(lOpd, rOpd) != 1)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
return nil
}
// calcG evaluate greater than or equal arithmetic operations.
func calcG(rOpd, lOpd string, opdStack *Stack) error {
- lOpdVal, err := strconv.ParseFloat(lOpd, 64)
- if err != nil {
- return err
- }
- rOpdVal, err := strconv.ParseFloat(rOpd, 64)
- if err != nil {
- return err
- }
- opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpdVal < lOpdVal)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
+ opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(strings.Compare(lOpd, rOpd) == 1)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
return nil
}
// calcGe evaluate greater than or equal arithmetic operations.
func calcGe(rOpd, lOpd string, opdStack *Stack) error {
- lOpdVal, err := strconv.ParseFloat(lOpd, 64)
- if err != nil {
- return err
- }
- rOpdVal, err := strconv.ParseFloat(rOpd, 64)
- if err != nil {
- return err
- }
- opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(rOpdVal <= lOpdVal)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
+ opdStack.Push(efp.Token{TValue: strings.ToUpper(strconv.FormatBool(strings.Compare(lOpd, rOpd) != -1)), TType: efp.TokenTypeOperand, TSubType: efp.TokenSubTypeNumber})
return nil
}
@@ -1214,7 +1182,7 @@ func (f *File) rangeResolver(cellRefs, cellRanges *list.List) (arg formulaArg, e
if cell, err = CoordinatesToCellName(col, row); err != nil {
return
}
- if value, err = f.GetCellValue(sheet, cell); err != nil {
+ if value, err = f.GetCellValue(sheet, cell, Options{RawCellValue: true}); err != nil {
return
}
matrixRow = append(matrixRow, formulaArg{
@@ -1233,7 +1201,7 @@ func (f *File) rangeResolver(cellRefs, cellRanges *list.List) (arg formulaArg, e
if cell, err = CoordinatesToCellName(cr.Col, cr.Row); err != nil {
return
}
- if arg.String, err = f.GetCellValue(cr.Sheet, cell); err != nil {
+ if arg.String, err = f.GetCellValue(cr.Sheet, cell, Options{RawCellValue: true}); err != nil {
return
}
arg.Type = ArgString
@@ -7749,28 +7717,33 @@ func hlookupBinarySearch(row []formulaArg, lookupValue formulaArg) (matchIdx int
return
}
-// LOOKUP function performs an approximate match lookup in a one-column or
-// one-row range, and returns the corresponding value from another one-column
-// or one-row range. The syntax of the function is:
-//
-// LOOKUP(lookup_value,lookup_vector,[result_vector])
-//
-func (fn *formulaFuncs) LOOKUP(argsList *list.List) formulaArg {
+// checkLookupArgs checking arguments, prepare lookup value, and data for the
+// formula function LOOKUP.
+func checkLookupArgs(argsList *list.List) (arrayForm bool, lookupValue, lookupVector, errArg formulaArg) {
if argsList.Len() < 2 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires at least 2 arguments")
+ errArg = newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires at least 2 arguments")
+ return
}
if argsList.Len() > 3 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires at most 3 arguments")
+ errArg = newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires at most 3 arguments")
+ return
}
- lookupValue := argsList.Front().Value.(formulaArg)
- lookupVector := argsList.Front().Next().Value.(formulaArg)
+ lookupValue = argsList.Front().Value.(formulaArg)
+ lookupVector = argsList.Front().Next().Value.(formulaArg)
if lookupVector.Type != ArgMatrix && lookupVector.Type != ArgList {
- return newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires second argument of table array")
+ errArg = newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires second argument of table array")
+ return
}
- arrayForm := lookupVector.Type == ArgMatrix
+ arrayForm = lookupVector.Type == ArgMatrix
if arrayForm && len(lookupVector.Matrix) == 0 {
- return newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires not empty range as second argument")
+ errArg = newErrorFormulaArg(formulaErrorVALUE, "LOOKUP requires not empty range as second argument")
}
+ return
+}
+
+// iterateLookupArgs iterate arguments to extract columns and calculate match
+// index for the formula function LOOKUP.
+func iterateLookupArgs(lookupValue, lookupVector formulaArg) ([]formulaArg, int, bool) {
cols, matchIdx, ok := lookupCol(lookupVector, 0), -1, false
for idx, col := range cols {
lhs := lookupValue
@@ -7796,6 +7769,21 @@ func (fn *formulaFuncs) LOOKUP(argsList *list.List) formulaArg {
matchIdx = idx - 1
}
}
+ return cols, matchIdx, ok
+}
+
+// LOOKUP function performs an approximate match lookup in a one-column or
+// one-row range, and returns the corresponding value from another one-column
+// or one-row range. The syntax of the function is:
+//
+// LOOKUP(lookup_value,lookup_vector,[result_vector])
+//
+func (fn *formulaFuncs) LOOKUP(argsList *list.List) formulaArg {
+ arrayForm, lookupValue, lookupVector, errArg := checkLookupArgs(argsList)
+ if errArg.Type == ArgError {
+ return errArg
+ }
+ cols, matchIdx, ok := iterateLookupArgs(lookupValue, lookupVector)
if ok && matchIdx == -1 {
matchIdx = len(cols) - 1
}
diff --git a/calc_test.go b/calc_test.go
index d526b34..4c32983 100644
--- a/calc_test.go
+++ b/calc_test.go
@@ -2452,17 +2452,27 @@ func TestCalcWithDefinedName(t *testing.T) {
}
func TestCalcArithmeticOperations(t *testing.T) {
+ opdStack := NewStack()
+ for _, test := range [][]string{{"1", "text", "FALSE"}, {"text", "1", "TRUE"}} {
+ assert.NoError(t, calcL(test[0], test[1], opdStack))
+ assert.Equal(t, test[2], opdStack.Peek().(efp.Token).TValue)
+ opdStack.Empty()
+ assert.NoError(t, calcLe(test[0], test[1], opdStack))
+ assert.Equal(t, test[2], opdStack.Peek().(efp.Token).TValue)
+ opdStack.Empty()
+ }
+ for _, test := range [][]string{{"1", "text", "TRUE"}, {"text", "1", "FALSE"}} {
+ assert.NoError(t, calcG(test[0], test[1], opdStack))
+ assert.Equal(t, test[2], opdStack.Peek().(efp.Token).TValue)
+ opdStack.Empty()
+ assert.NoError(t, calcGe(test[0], test[1], opdStack))
+ assert.Equal(t, test[2], opdStack.Peek().(efp.Token).TValue)
+ opdStack.Empty()
+ }
+
err := `strconv.ParseFloat: parsing "text": invalid syntax`
assert.EqualError(t, calcPow("1", "text", nil), err)
assert.EqualError(t, calcPow("text", "1", nil), err)
- assert.EqualError(t, calcL("1", "text", nil), err)
- assert.EqualError(t, calcL("text", "1", nil), err)
- assert.EqualError(t, calcLe("1", "text", nil), err)
- assert.EqualError(t, calcLe("text", "1", nil), err)
- assert.EqualError(t, calcG("1", "text", nil), err)
- assert.EqualError(t, calcG("text", "1", nil), err)
- assert.EqualError(t, calcGe("1", "text", nil), err)
- assert.EqualError(t, calcGe("text", "1", nil), err)
assert.EqualError(t, calcAdd("1", "text", nil), err)
assert.EqualError(t, calcAdd("text", "1", nil), err)
assert.EqualError(t, calcAdd("1", "text", nil), err)
diff --git a/cell.go b/cell.go
index d176991..59d3bbd 100644
--- a/cell.go
+++ b/cell.go
@@ -36,9 +36,9 @@ const (
// format to the cell value, it will do so, if not then an error will be
// returned, along with the raw value of the cell. All cells' values will be
// the same in a merged range.
-func (f *File) GetCellValue(sheet, axis string) (string, error) {
+func (f *File) GetCellValue(sheet, axis string, opts ...Options) (string, error) {
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
- val, err := c.getValueFrom(f, f.sharedStringsReader())
+ val, err := c.getValueFrom(f, f.sharedStringsReader(), parseOptions(opts...).RawCellValue)
return val, true, err
})
}
@@ -440,7 +440,6 @@ type FormulaOpts struct {
// err := f.SetCellFormula("Sheet1", "A3", "=A1:A2",
// excelize.FormulaOpts{Ref: &ref, Type: &formulaType})
//
-//
// Example 6, set shared formula "=A1+B1" for the cell "C1:C5"
// on "Sheet1", "C1" is the master cell:
//
@@ -448,6 +447,41 @@ type FormulaOpts struct {
// err := f.SetCellFormula("Sheet1", "C1", "=A1+B1",
// excelize.FormulaOpts{Ref: &ref, Type: &formulaType})
//
+// Example 7, set table formula "=SUM(Table1[[A]:[B]])" for the cell "C2"
+// on "Sheet1":
+//
+// package main
+//
+// import (
+// "fmt"
+//
+// "github.com/xuri/excelize/v2"
+// )
+//
+// func main() {
+// f := excelize.NewFile()
+// for idx, row := range [][]interface{}{{"A", "B", "C"}, {1, 2}} {
+// if err := f.SetSheetRow("Sheet1", fmt.Sprintf("A%d", idx+1), &row); err != nil {
+// fmt.Println(err)
+// return
+// }
+// }
+// if err := f.AddTable("Sheet1", "A1", "C2",
+// `{"table_name":"Table1","table_style":"TableStyleMedium2"}`); err != nil {
+// fmt.Println(err)
+// return
+// }
+// formulaType := excelize.STCellFormulaTypeDataTable
+// if err := f.SetCellFormula("Sheet1", "C2", "=SUM(Table1[[A]:[B]])",
+// excelize.FormulaOpts{Type: &formulaType}); err != nil {
+// fmt.Println(err)
+// return
+// }
+// if err := f.SaveAs("Book1.xlsx"); err != nil {
+// fmt.Println(err)
+// }
+// }
+//
func (f *File) SetCellFormula(sheet, axis, formula string, opts ...FormulaOpts) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
@@ -471,6 +505,9 @@ func (f *File) SetCellFormula(sheet, axis, formula string, opts ...FormulaOpts)
for _, o := range opts {
if o.Type != nil {
+ if *o.Type == STCellFormulaTypeDataTable {
+ return err
+ }
cellData.F.T = *o.Type
if cellData.F.T == STCellFormulaTypeShared {
if err = ws.setSharedFormula(*o.Ref); err != nil {
@@ -955,8 +992,8 @@ func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c
// formattedValue provides a function to returns a value after formatted. If
// it is possible to apply a format to the cell value, it will do so, if not
// then an error will be returned, along with the raw value of the cell.
-func (f *File) formattedValue(s int, v string) string {
- if s == 0 {
+func (f *File) formattedValue(s int, v string, raw bool) string {
+ if s == 0 || raw {
return v
}
styleSheet := f.stylesReader()
diff --git a/cell_test.go b/cell_test.go
index ad78436..d56854b 100644
--- a/cell_test.go
+++ b/cell_test.go
@@ -356,6 +356,16 @@ func TestSetCellFormula(t *testing.T) {
ref = ""
assert.EqualError(t, f.SetCellFormula("Sheet1", "D1", "=A1+C1", FormulaOpts{Ref: &ref, Type: &formulaType}), ErrParameterInvalid.Error())
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula5.xlsx")))
+
+ // Test set table formula for the cells.
+ f = NewFile()
+ for idx, row := range [][]interface{}{{"A", "B", "C"}, {1, 2}} {
+ assert.NoError(t, f.SetSheetRow("Sheet1", fmt.Sprintf("A%d", idx+1), &row))
+ }
+ assert.NoError(t, f.AddTable("Sheet1", "A1", "C2", `{"table_name":"Table1","table_style":"TableStyleMedium2"}`))
+ formulaType = STCellFormulaTypeDataTable
+ assert.NoError(t, f.SetCellFormula("Sheet1", "C2", "=SUM(Table1[[A]:[B]])", FormulaOpts{Type: &formulaType}))
+ assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellFormula6.xlsx")))
}
func TestGetCellRichText(t *testing.T) {
@@ -503,20 +513,20 @@ func TestSetCellRichText(t *testing.T) {
func TestFormattedValue2(t *testing.T) {
f := NewFile()
- v := f.formattedValue(0, "43528")
+ v := f.formattedValue(0, "43528", false)
assert.Equal(t, "43528", v)
- v = f.formattedValue(15, "43528")
+ v = f.formattedValue(15, "43528", false)
assert.Equal(t, "43528", v)
- v = f.formattedValue(1, "43528")
+ v = f.formattedValue(1, "43528", false)
assert.Equal(t, "43528", v)
customNumFmt := "[$-409]MM/DD/YYYY"
_, err := f.NewStyle(&Style{
CustomNumFmt: &customNumFmt,
})
assert.NoError(t, err)
- v = f.formattedValue(1, "43528")
+ v = f.formattedValue(1, "43528", false)
assert.Equal(t, "03/04/2019", v)
// formatted value with no built-in number format ID
@@ -524,20 +534,20 @@ func TestFormattedValue2(t *testing.T) {
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
NumFmtID: &numFmtID,
})
- v = f.formattedValue(2, "43528")
+ v = f.formattedValue(2, "43528", false)
assert.Equal(t, "43528", v)
// formatted value with invalid number format ID
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
NumFmtID: nil,
})
- _ = f.formattedValue(3, "43528")
+ _ = f.formattedValue(3, "43528", false)
// formatted value with empty number format
f.Styles.NumFmts = nil
f.Styles.CellXfs.Xf = append(f.Styles.CellXfs.Xf, xlsxXf{
NumFmtID: &numFmtID,
})
- v = f.formattedValue(1, "43528")
+ v = f.formattedValue(1, "43528", false)
assert.Equal(t, "43528", v)
}
diff --git a/col.go b/col.go
index 1e0c333..5ba5caa 100644
--- a/col.go
+++ b/col.go
@@ -34,6 +34,7 @@ const (
type Cols struct {
err error
curCol, totalCol, stashCol, totalRow int
+ rawCellValue bool
sheet string
f *File
sheetXML []byte
@@ -54,14 +55,14 @@ type Cols struct {
// fmt.Println()
// }
//
-func (f *File) GetCols(sheet string) ([][]string, error) {
+func (f *File) GetCols(sheet string, opts ...Options) ([][]string, error) {
cols, err := f.Cols(sheet)
if err != nil {
return nil, err
}
results := make([][]string, 0, 64)
for cols.Next() {
- col, _ := cols.Rows()
+ col, _ := cols.Rows(opts...)
results = append(results, col)
}
return results, nil
@@ -79,7 +80,7 @@ func (cols *Cols) Error() error {
}
// Rows return the current column's row values.
-func (cols *Cols) Rows() ([]string, error) {
+func (cols *Cols) Rows(opts ...Options) ([]string, error) {
var (
err error
inElement string
@@ -89,6 +90,7 @@ func (cols *Cols) Rows() ([]string, error) {
if cols.stashCol >= cols.curCol {
return rows, err
}
+ cols.rawCellValue = parseOptions(opts...).RawCellValue
d := cols.f.sharedStringsReader()
decoder := cols.f.xmlNewDecoder(bytes.NewReader(cols.sheetXML))
for {
@@ -123,7 +125,7 @@ func (cols *Cols) Rows() ([]string, error) {
if cellCol == cols.curCol {
colCell := xlsxC{}
_ = decoder.DecodeElement(&colCell, &xmlElement)
- val, _ := colCell.getValueFrom(cols.f, d)
+ val, _ := colCell.getValueFrom(cols.f, d, cols.rawCellValue)
rows = append(rows, val)
}
}
diff --git a/excelize.go b/excelize.go
index 11ddf92..def018b 100644
--- a/excelize.go
+++ b/excelize.go
@@ -58,9 +58,12 @@ type File struct {
type charsetTranscoderFn func(charset string, input io.Reader) (rdr io.Reader, err error)
-// Options define the options for open spreadsheet.
+// Options define the options for open and reading spreadsheet. RawCellValue
+// specify if apply the number format for the cell value or get the raw
+// value.
type Options struct {
Password string
+ RawCellValue bool
UnzipSizeLimit int64
}
@@ -119,11 +122,9 @@ func OpenReader(r io.Reader, opt ...Options) (*File, error) {
return nil, err
}
f := newFile()
- for i := range opt {
- f.options = &opt[i]
- if f.options.UnzipSizeLimit == 0 {
- f.options.UnzipSizeLimit = UnzipSizeLimit
- }
+ f.options = parseOptions(opt...)
+ if f.options.UnzipSizeLimit == 0 {
+ f.options.UnzipSizeLimit = UnzipSizeLimit
}
if bytes.Contains(b, oleIdentifier) {
b, err = Decrypt(b, f.options)
@@ -150,6 +151,16 @@ func OpenReader(r io.Reader, opt ...Options) (*File, error) {
return f, nil
}
+// parseOptions provides a function to parse the optional settings for open
+// and reading spreadsheet.
+func parseOptions(opts ...Options) *Options {
+ opt := &Options{}
+ for _, o := range opts {
+ opt = &o
+ }
+ return opt
+}
+
// CharsetTranscoder Set user defined codepage transcoder function for open
// XLSX from non UTF-8 encoding.
func (f *File) CharsetTranscoder(fn charsetTranscoderFn) *File { f.CharsetReader = fn; return f }
diff --git a/rows.go b/rows.go
index bfd7d13..057cbc8 100644
--- a/rows.go
+++ b/rows.go
@@ -43,7 +43,7 @@ import (
// fmt.Println()
// }
//
-func (f *File) GetRows(sheet string) ([][]string, error) {
+func (f *File) GetRows(sheet string, opts ...Options) ([][]string, error) {
rows, err := f.Rows(sheet)
if err != nil {
return nil, err
@@ -51,7 +51,7 @@ func (f *File) GetRows(sheet string) ([][]string, error) {
results, cur, max := make([][]string, 0, 64), 0, 0
for rows.Next() {
cur++
- row, err := rows.Columns()
+ row, err := rows.Columns(opts...)
if err != nil {
break
}
@@ -67,6 +67,7 @@ func (f *File) GetRows(sheet string) ([][]string, error) {
type Rows struct {
err error
curRow, totalRow, stashRow int
+ rawCellValue bool
sheet string
f *File
decoder *xml.Decoder
@@ -84,11 +85,12 @@ func (rows *Rows) Error() error {
}
// Columns return the current row's column values.
-func (rows *Rows) Columns() ([]string, error) {
+func (rows *Rows) Columns(opts ...Options) ([]string, error) {
var rowIterator rowXMLIterator
if rows.stashRow >= rows.curRow {
return rowIterator.columns, rowIterator.err
}
+ rows.rawCellValue = parseOptions(opts...).RawCellValue
rowIterator.rows = rows
rowIterator.d = rows.f.sharedStringsReader()
for {
@@ -109,7 +111,7 @@ func (rows *Rows) Columns() ([]string, error) {
return rowIterator.columns, rowIterator.err
}
}
- rowXMLHandler(&rowIterator, &xmlElement)
+ rowXMLHandler(&rowIterator, &xmlElement, rows.rawCellValue)
if rowIterator.err != nil {
return rowIterator.columns, rowIterator.err
}
@@ -157,7 +159,7 @@ type rowXMLIterator struct {
}
// rowXMLHandler parse the row XML element of the worksheet.
-func rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.StartElement) {
+func rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.StartElement, raw bool) {
rowIterator.err = nil
if rowIterator.inElement == "c" {
rowIterator.cellCol++
@@ -169,7 +171,7 @@ func rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.StartElement) {
}
}
blank := rowIterator.cellCol - len(rowIterator.columns)
- val, _ := colCell.getValueFrom(rowIterator.rows.f, rowIterator.d)
+ val, _ := colCell.getValueFrom(rowIterator.rows.f, rowIterator.d, raw)
if val != "" || colCell.F != nil {
rowIterator.columns = append(appendSpace(blank, rowIterator.columns), val)
}
@@ -361,7 +363,7 @@ func (f *File) sharedStringsReader() *xlsxSST {
// getValueFrom return a value from a column/row cell, this function is
// inteded to be used with for range on rows an argument with the spreadsheet
// opened file.
-func (c *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
+func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) {
f.Lock()
defer f.Unlock()
switch c.T {
@@ -370,26 +372,26 @@ func (c *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
xlsxSI := 0
xlsxSI, _ = strconv.Atoi(c.V)
if len(d.SI) > xlsxSI {
- return f.formattedValue(c.S, d.SI[xlsxSI].String()), nil
+ return f.formattedValue(c.S, d.SI[xlsxSI].String(), raw), nil
}
}
- return f.formattedValue(c.S, c.V), nil
+ return f.formattedValue(c.S, c.V, raw), nil
case "str":
- return f.formattedValue(c.S, c.V), nil
+ return f.formattedValue(c.S, c.V, raw), nil
case "inlineStr":
if c.IS != nil {
- return f.formattedValue(c.S, c.IS.String()), nil
+ return f.formattedValue(c.S, c.IS.String(), raw), nil
}
- return f.formattedValue(c.S, c.V), nil
+ return f.formattedValue(c.S, c.V, raw), nil
default:
isNum, precision := isNumeric(c.V)
if isNum && precision > 10 {
val, _ := roundPrecision(c.V)
if val != c.V {
- return f.formattedValue(c.S, val), nil
+ return f.formattedValue(c.S, val, raw), nil
}
}
- return f.formattedValue(c.S, c.V), nil
+ return f.formattedValue(c.S, c.V, raw), nil
}
}
diff --git a/rows_test.go b/rows_test.go
index a54e755..c0dc1d8 100644
--- a/rows_test.go
+++ b/rows_test.go
@@ -845,7 +845,7 @@ func TestGetValueFromInlineStr(t *testing.T) {
c := &xlsxC{T: "inlineStr"}
f := NewFile()
d := &xlsxSST{}
- val, err := c.getValueFrom(f, d)
+ val, err := c.getValueFrom(f, d, false)
assert.NoError(t, err)
assert.Equal(t, "", val)
}
@@ -865,7 +865,7 @@ func TestGetValueFromNumber(t *testing.T) {
"2.220000ddsf0000000002-r": "2.220000ddsf0000000002-r",
} {
c.V = input
- val, err := c.getValueFrom(f, d)
+ val, err := c.getValueFrom(f, d, false)
assert.NoError(t, err)
assert.Equal(t, expected, val)
}
diff --git a/sheet.go b/sheet.go
index 7e15bbe..be2e964 100644
--- a/sheet.go
+++ b/sheet.go
@@ -880,7 +880,7 @@ func (f *File) searchSheet(name, value string, regSearch bool) (result []string,
if inElement == "c" {
colCell := xlsxC{}
_ = decoder.DecodeElement(&colCell, &xmlElement)
- val, _ := colCell.getValueFrom(f, d)
+ val, _ := colCell.getValueFrom(f, d, false)
if regSearch {
regex := regexp.MustCompile(value)
if !regex.MatchString(val) {
diff --git a/xmlWorksheet.go b/xmlWorksheet.go
index a4aef4c..217f367 100644
--- a/xmlWorksheet.go
+++ b/xmlWorksheet.go
@@ -473,9 +473,18 @@ type xlsxC struct {
// contained in the character node of this element.
type xlsxF struct {
Content string `xml:",chardata"`
- T string `xml:"t,attr,omitempty"` // Formula type
+ T string `xml:"t,attr,omitempty"` // Formula type
+ Aca bool `xml:"aca,attr,omitempty"`
Ref string `xml:"ref,attr,omitempty"` // Shared formula ref
- Si *int `xml:"si,attr"` // Shared formula index
+ Dt2D bool `xml:"dt2D,attr,omitempty"`
+ Dtr bool `xml:"dtr,attr,omitempty"`
+ Del1 bool `xml:"del1,attr,omitempty"`
+ Del2 bool `xml:"del2,attr,omitempty"`
+ R1 string `xml:"r1,attr,omitempty"`
+ R2 string `xml:"r2,attr,omitempty"`
+ Ca bool `xml:"ca,attr,omitempty"`
+ Si *int `xml:"si,attr"` // Shared formula index
+ Bx bool `xml:"bx,attr,omitempty"`
}
// xlsxSheetProtection collection expresses the sheet protection options to