Skip to content

Commit a335be7

Browse files
committed
New functions: SetDefinedName and GetDefinedName added
1 parent 5cf1c05 commit a335be7

File tree

4 files changed

+135
-20
lines changed

4 files changed

+135
-20
lines changed

excelize_test.go

+5-16
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ func TestSaveAsWrongPath(t *testing.T) {
182182
}
183183
}
184184

185+
func TestOpenReader(t *testing.T) {
186+
_, err := OpenReader(strings.NewReader(""))
187+
assert.EqualError(t, err, "zip: not a valid zip file")
188+
}
189+
185190
func TestBrokenFile(t *testing.T) {
186191
// Test write file with broken file struct.
187192
f := File{}
@@ -1033,22 +1038,6 @@ func TestHSL(t *testing.T) {
10331038
t.Log(RGBToHSL(250, 50, 100))
10341039
}
10351040

1036-
func TestSearchSheet(t *testing.T) {
1037-
f, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
1038-
if !assert.NoError(t, err) {
1039-
t.FailNow()
1040-
}
1041-
1042-
// Test search in a not exists worksheet.
1043-
t.Log(f.SearchSheet("Sheet4", ""))
1044-
// Test search a not exists value.
1045-
t.Log(f.SearchSheet("Sheet1", "X"))
1046-
t.Log(f.SearchSheet("Sheet1", "A"))
1047-
// Test search the coordinates where the numerical value in the range of
1048-
// "0-9" of Sheet1 is described by regular expression:
1049-
t.Log(f.SearchSheet("Sheet1", "[0-9]", true))
1050-
}
1051-
10521041
func TestProtectSheet(t *testing.T) {
10531042
f := NewFile()
10541043
f.ProtectSheet("Sheet1", nil)

sheet.go

+76-4
Original file line numberDiff line numberDiff line change
@@ -704,18 +704,14 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
704704
var (
705705
regSearch bool
706706
result []string
707-
inElement string
708-
r xlsxRow
709707
)
710708
for _, r := range reg {
711709
regSearch = r
712710
}
713-
714711
xlsx, err := f.workSheetReader(sheet)
715712
if err != nil {
716713
return result, err
717714
}
718-
719715
name, ok := f.sheetMap[trimSheetName(sheet)]
720716
if !ok {
721717
return result, nil
@@ -724,6 +720,17 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
724720
output, _ := xml.Marshal(f.Sheet[name])
725721
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output))
726722
}
723+
return f.searchSheet(name, value, regSearch)
724+
}
725+
726+
// searchSheet provides a function to get coordinates by given worksheet name,
727+
// cell value, and regular expression.
728+
func (f *File) searchSheet(name, value string, regSearch bool) ([]string, error) {
729+
var (
730+
inElement string
731+
result []string
732+
r xlsxRow
733+
)
727734
xml.NewDecoder(bytes.NewReader(f.readXML(name)))
728735
d := f.sharedStringsReader()
729736

@@ -1213,6 +1220,71 @@ func (f *File) GetPageLayout(sheet string, opts ...PageLayoutOptionPtr) error {
12131220
return err
12141221
}
12151222

1223+
// SetDefinedName provides a function to set the defined names of the workbook
1224+
// or worksheet. If not specified scopr, the default scope is workbook.
1225+
// For example:
1226+
//
1227+
// f.SetDefinedName(&excelize.DefinedName{
1228+
// Name: "Amount",
1229+
// RefersTo: "Sheet1!$A$2:$D$5",
1230+
// Comment: "defined name comment",
1231+
// Scope: "Sheet2",
1232+
// })
1233+
//
1234+
func (f *File) SetDefinedName(definedName *DefinedName) error {
1235+
wb := f.workbookReader()
1236+
d := xlsxDefinedName{
1237+
Name: definedName.Name,
1238+
Comment: definedName.Comment,
1239+
Data: definedName.RefersTo,
1240+
}
1241+
if definedName.Scope != "" {
1242+
if sheetID := f.GetSheetIndex(definedName.Scope); sheetID != 0 {
1243+
sheetID--
1244+
d.LocalSheetID = &sheetID
1245+
}
1246+
}
1247+
if wb.DefinedNames != nil {
1248+
for _, dn := range wb.DefinedNames.DefinedName {
1249+
var scope string
1250+
if dn.LocalSheetID != nil {
1251+
scope = f.GetSheetName(*dn.LocalSheetID + 1)
1252+
}
1253+
if scope == definedName.Scope && dn.Name == definedName.Name {
1254+
return errors.New("the same name already exists on scope")
1255+
}
1256+
}
1257+
wb.DefinedNames.DefinedName = append(wb.DefinedNames.DefinedName, d)
1258+
return nil
1259+
}
1260+
wb.DefinedNames = &xlsxDefinedNames{
1261+
DefinedName: []xlsxDefinedName{d},
1262+
}
1263+
return nil
1264+
}
1265+
1266+
// GetDefinedName provides a function to get the defined names of the workbook
1267+
// or worksheet.
1268+
func (f *File) GetDefinedName() []DefinedName {
1269+
var definedNames []DefinedName
1270+
wb := f.workbookReader()
1271+
if wb.DefinedNames != nil {
1272+
for _, dn := range wb.DefinedNames.DefinedName {
1273+
definedName := DefinedName{
1274+
Name: dn.Name,
1275+
Comment: dn.Comment,
1276+
RefersTo: dn.Data,
1277+
Scope: "Workbook",
1278+
}
1279+
if dn.LocalSheetID != nil {
1280+
definedName.Scope = f.GetSheetName(*dn.LocalSheetID + 1)
1281+
}
1282+
definedNames = append(definedNames, definedName)
1283+
}
1284+
}
1285+
return definedNames
1286+
}
1287+
12161288
// workSheetRelsReader provides a function to get the pointer to the structure
12171289
// after deserialization of xl/worksheets/_rels/sheet%d.xml.rels.
12181290
func (f *File) workSheetRelsReader(path string) *xlsxWorkbookRels {

sheet_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,29 @@ func TestPageLayoutOption(t *testing.T) {
108108
}
109109
}
110110

111+
func TestSearchSheet(t *testing.T) {
112+
f, err := excelize.OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
113+
if !assert.NoError(t, err) {
114+
t.FailNow()
115+
}
116+
// Test search in a not exists worksheet.
117+
_, err = f.SearchSheet("Sheet4", "")
118+
assert.EqualError(t, err, "sheet Sheet4 is not exist")
119+
var expected []string
120+
// Test search a not exists value.
121+
result, err := f.SearchSheet("Sheet1", "X")
122+
assert.NoError(t, err)
123+
assert.EqualValues(t, expected, result)
124+
result, err = f.SearchSheet("Sheet1", "A")
125+
assert.NoError(t, err)
126+
assert.EqualValues(t, []string{"A1"}, result)
127+
// Test search the coordinates where the numerical value in the range of
128+
// "0-9" of Sheet1 is described by regular expression:
129+
result, err = f.SearchSheet("Sheet1", "[0-9]", true)
130+
assert.NoError(t, err)
131+
assert.EqualValues(t, expected, result)
132+
}
133+
111134
func TestSetPageLayout(t *testing.T) {
112135
f := excelize.NewFile()
113136
// Test set page layout on not exists worksheet.
@@ -142,3 +165,25 @@ func TestSetHeaderFooter(t *testing.T) {
142165
}))
143166
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetHeaderFooter.xlsx")))
144167
}
168+
169+
func TestDefinedName(t *testing.T) {
170+
f := excelize.NewFile()
171+
assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
172+
Name: "Amount",
173+
RefersTo: "Sheet1!$A$2:$D$5",
174+
Comment: "defined name comment",
175+
Scope: "Sheet1",
176+
}))
177+
assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
178+
Name: "Amount",
179+
RefersTo: "Sheet1!$A$2:$D$5",
180+
Comment: "defined name comment",
181+
}))
182+
assert.EqualError(t, f.SetDefinedName(&excelize.DefinedName{
183+
Name: "Amount",
184+
RefersTo: "Sheet1!$A$2:$D$5",
185+
Comment: "defined name comment",
186+
}), "the same name already exists on scope")
187+
assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[1].RefersTo)
188+
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDefinedName.xlsx")))
189+
}

xmlWorkbook.go

+9
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,12 @@ type xlsxCustomWorkbookView struct {
288288
XWindow *int `xml:"xWindow,attr"`
289289
YWindow *int `xml:"yWindow,attr"`
290290
}
291+
292+
// DefinedName directly maps the name for a cell or cell range on a
293+
// worksheet.
294+
type DefinedName struct {
295+
Name string
296+
Comment string
297+
RefersTo string
298+
Scope string
299+
}

0 commit comments

Comments
 (0)