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