From 5993a07422b6ace5230f562551f014180a83515a Mon Sep 17 00:00:00 2001 From: jaby Date: Tue, 14 Jul 2020 17:05:43 +0200 Subject: [PATCH] Fix issue 665 (#666) --- calc.go | 17 +++++++++++++++++ calc_test.go | 26 ++++++++++++++++++++++++++ sheet.go | 2 +- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/calc.go b/calc.go index 86f7cff..f86b12c 100644 --- a/calc.go +++ b/calc.go @@ -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") } diff --git a/sheet.go b/sheet.go index bbe84c2..20bf7c7 100644 --- a/sheet.go +++ b/sheet.go @@ -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)