diff options
author | jaby <peter.de.velder@ilias-solutions.com> | 2020-07-14 17:05:43 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-14 23:05:43 +0800 |
commit | 5993a07422b6ace5230f562551f014180a83515a (patch) | |
tree | 2429c3a1d2b151fd40587807c75b7c110bb4fe75 | |
parent | 0aa15106947965bdae9daae7571a4a3f569bf32d (diff) |
Fix issue 665 (#666)
-rw-r--r-- | calc.go | 17 | ||||
-rw-r--r-- | calc_test.go | 26 | ||||
-rw-r--r-- | sheet.go | 2 |
3 files changed, 44 insertions, 1 deletions
@@ -453,11 +453,28 @@ func isOperatorPrefixToken(token efp.Token) bool { return false } +func (f *File) getDefinedNameRefTo(definedNameName string, currentSheet string) (refTo string) { + for _, definedName := range f.GetDefinedName() { + if definedName.Name == definedNameName { + refTo = definedName.RefersTo + // worksheet scope takes precedence over scope workbook when both definedNames exist + if definedName.Scope == currentSheet { + break + } + } + } + return refTo +} + // parseToken parse basic arithmetic operator priority and evaluate based on // operators and operands. func (f *File) parseToken(sheet string, token efp.Token, opdStack, optStack *Stack) error { // parse reference: must reference at here if token.TSubType == efp.TokenSubTypeRange { + refTo := f.getDefinedNameRefTo(token.TValue, sheet) + if refTo != "" { + token.TValue = refTo + } result, err := f.parseReference(sheet, token.TValue) if err != nil { return errors.New(formulaErrorNAME) diff --git a/calc_test.go b/calc_test.go index 283b9c2..4298aa7 100644 --- a/calc_test.go +++ b/calc_test.go @@ -790,4 +790,30 @@ func TestCalcCellValue(t *testing.T) { _, err = f.CalcCellValue("Sheet1", "A1") assert.EqualError(t, err, "not support UNSUPPORT function") assert.NoError(t, f.SaveAs(filepath.Join("test", "TestCalcCellValue.xlsx"))) + +} + +func TestCalcCellValueWithDefinedName(t *testing.T) { + cellData := [][]interface{}{ + {"A1 value", "B1 value", nil}, + } + prepareData := func() *File { + f := NewFile() + for r, row := range cellData { + for c, value := range row { + cell, _ := CoordinatesToCellName(c+1, r+1) + assert.NoError(t, f.SetCellValue("Sheet1", cell, value)) + } + } + assert.NoError(t, f.SetDefinedName(&DefinedName{Name: "defined_name1", RefersTo: "Sheet1!A1", Scope: "Workbook"})) + assert.NoError(t, f.SetDefinedName(&DefinedName{Name: "defined_name1", RefersTo: "Sheet1!B1", Scope: "Sheet1"})) + + return f + } + f := prepareData() + assert.NoError(t, f.SetCellFormula("Sheet1", "C1", "=defined_name1")) + result, err := f.CalcCellValue("Sheet1", "C1") + assert.NoError(t, err) + // DefinedName with scope WorkSheet takes precedence over DefinedName with scope Workbook, so we should get B1 value + assert.Equal(t, "B1 value", result, "=defined_name1") } @@ -1421,7 +1421,7 @@ func (f *File) GetDefinedName() []DefinedName { RefersTo: dn.Data, Scope: "Workbook", } - if dn.LocalSheetID != nil { + if dn.LocalSheetID != nil && *dn.LocalSheetID >= 0 { definedName.Scope = f.getSheetNameByID(*dn.LocalSheetID + 1) } definedNames = append(definedNames, definedName) |