소스 검색

New functions: SetDefinedName and GetDefinedName added

xuri 6 년 전
부모
커밋
a335be7e4e
4개의 변경된 파일135개의 추가작업 그리고 20개의 파일을 삭제
  1. 5 16
      excelize_test.go
  2. 76 4
      sheet.go
  3. 45 0
      sheet_test.go
  4. 9 0
      xmlWorkbook.go

+ 5 - 16
excelize_test.go

@@ -182,6 +182,11 @@ func TestSaveAsWrongPath(t *testing.T) {
 	}
 }
 
+func TestOpenReader(t *testing.T) {
+	_, err := OpenReader(strings.NewReader(""))
+	assert.EqualError(t, err, "zip: not a valid zip file")
+}
+
 func TestBrokenFile(t *testing.T) {
 	// Test write file with broken file struct.
 	f := File{}
@@ -1033,22 +1038,6 @@ func TestHSL(t *testing.T) {
 	t.Log(RGBToHSL(250, 50, 100))
 }
 
-func TestSearchSheet(t *testing.T) {
-	f, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
-	if !assert.NoError(t, err) {
-		t.FailNow()
-	}
-
-	// Test search in a not exists worksheet.
-	t.Log(f.SearchSheet("Sheet4", ""))
-	// Test search a not exists value.
-	t.Log(f.SearchSheet("Sheet1", "X"))
-	t.Log(f.SearchSheet("Sheet1", "A"))
-	// Test search the coordinates where the numerical value in the range of
-	// "0-9" of Sheet1 is described by regular expression:
-	t.Log(f.SearchSheet("Sheet1", "[0-9]", true))
-}
-
 func TestProtectSheet(t *testing.T) {
 	f := NewFile()
 	f.ProtectSheet("Sheet1", nil)

+ 76 - 4
sheet.go

@@ -704,18 +704,14 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
 	var (
 		regSearch bool
 		result    []string
-		inElement string
-		r         xlsxRow
 	)
 	for _, r := range reg {
 		regSearch = r
 	}
-
 	xlsx, err := f.workSheetReader(sheet)
 	if err != nil {
 		return result, err
 	}
-
 	name, ok := f.sheetMap[trimSheetName(sheet)]
 	if !ok {
 		return result, nil
@@ -724,6 +720,17 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
 		output, _ := xml.Marshal(f.Sheet[name])
 		f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output))
 	}
+	return f.searchSheet(name, value, regSearch)
+}
+
+// searchSheet provides a function to get coordinates by given worksheet name,
+// cell value, and regular expression.
+func (f *File) searchSheet(name, value string, regSearch bool) ([]string, error) {
+	var (
+		inElement string
+		result    []string
+		r         xlsxRow
+	)
 	xml.NewDecoder(bytes.NewReader(f.readXML(name)))
 	d := f.sharedStringsReader()
 
@@ -1213,6 +1220,71 @@ func (f *File) GetPageLayout(sheet string, opts ...PageLayoutOptionPtr) error {
 	return err
 }
 
+// SetDefinedName provides a function to set the defined names of the workbook
+// or worksheet. If not specified scopr, the default scope is workbook.
+// For example:
+//
+//    f.SetDefinedName(&excelize.DefinedName{
+//        Name:     "Amount",
+//        RefersTo: "Sheet1!$A$2:$D$5",
+//        Comment:  "defined name comment",
+//        Scope:    "Sheet2",
+//    })
+//
+func (f *File) SetDefinedName(definedName *DefinedName) error {
+	wb := f.workbookReader()
+	d := xlsxDefinedName{
+		Name:    definedName.Name,
+		Comment: definedName.Comment,
+		Data:    definedName.RefersTo,
+	}
+	if definedName.Scope != "" {
+		if sheetID := f.GetSheetIndex(definedName.Scope); sheetID != 0 {
+			sheetID--
+			d.LocalSheetID = &sheetID
+		}
+	}
+	if wb.DefinedNames != nil {
+		for _, dn := range wb.DefinedNames.DefinedName {
+			var scope string
+			if dn.LocalSheetID != nil {
+				scope = f.GetSheetName(*dn.LocalSheetID + 1)
+			}
+			if scope == definedName.Scope && dn.Name == definedName.Name {
+				return errors.New("the same name already exists on scope")
+			}
+		}
+		wb.DefinedNames.DefinedName = append(wb.DefinedNames.DefinedName, d)
+		return nil
+	}
+	wb.DefinedNames = &xlsxDefinedNames{
+		DefinedName: []xlsxDefinedName{d},
+	}
+	return nil
+}
+
+// GetDefinedName provides a function to get the defined names of the workbook
+// or worksheet.
+func (f *File) GetDefinedName() []DefinedName {
+	var definedNames []DefinedName
+	wb := f.workbookReader()
+	if wb.DefinedNames != nil {
+		for _, dn := range wb.DefinedNames.DefinedName {
+			definedName := DefinedName{
+				Name:     dn.Name,
+				Comment:  dn.Comment,
+				RefersTo: dn.Data,
+				Scope:    "Workbook",
+			}
+			if dn.LocalSheetID != nil {
+				definedName.Scope = f.GetSheetName(*dn.LocalSheetID + 1)
+			}
+			definedNames = append(definedNames, definedName)
+		}
+	}
+	return definedNames
+}
+
 // workSheetRelsReader provides a function to get the pointer to the structure
 // after deserialization of xl/worksheets/_rels/sheet%d.xml.rels.
 func (f *File) workSheetRelsReader(path string) *xlsxWorkbookRels {

+ 45 - 0
sheet_test.go

@@ -108,6 +108,29 @@ func TestPageLayoutOption(t *testing.T) {
 	}
 }
 
+func TestSearchSheet(t *testing.T) {
+	f, err := excelize.OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
+	if !assert.NoError(t, err) {
+		t.FailNow()
+	}
+	// Test search in a not exists worksheet.
+	_, err = f.SearchSheet("Sheet4", "")
+	assert.EqualError(t, err, "sheet Sheet4 is not exist")
+	var expected []string
+	// Test search a not exists value.
+	result, err := f.SearchSheet("Sheet1", "X")
+	assert.NoError(t, err)
+	assert.EqualValues(t, expected, result)
+	result, err = f.SearchSheet("Sheet1", "A")
+	assert.NoError(t, err)
+	assert.EqualValues(t, []string{"A1"}, result)
+	// Test search the coordinates where the numerical value in the range of
+	// "0-9" of Sheet1 is described by regular expression:
+	result, err = f.SearchSheet("Sheet1", "[0-9]", true)
+	assert.NoError(t, err)
+	assert.EqualValues(t, expected, result)
+}
+
 func TestSetPageLayout(t *testing.T) {
 	f := excelize.NewFile()
 	// Test set page layout on not exists worksheet.
@@ -142,3 +165,25 @@ func TestSetHeaderFooter(t *testing.T) {
 	}))
 	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetHeaderFooter.xlsx")))
 }
+
+func TestDefinedName(t *testing.T) {
+	f := excelize.NewFile()
+	assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
+		Name:     "Amount",
+		RefersTo: "Sheet1!$A$2:$D$5",
+		Comment:  "defined name comment",
+		Scope:    "Sheet1",
+	}))
+	assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
+		Name:     "Amount",
+		RefersTo: "Sheet1!$A$2:$D$5",
+		Comment:  "defined name comment",
+	}))
+	assert.EqualError(t, f.SetDefinedName(&excelize.DefinedName{
+		Name:     "Amount",
+		RefersTo: "Sheet1!$A$2:$D$5",
+		Comment:  "defined name comment",
+	}), "the same name already exists on scope")
+	assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[1].RefersTo)
+	assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDefinedName.xlsx")))
+}

+ 9 - 0
xmlWorkbook.go

@@ -288,3 +288,12 @@ type xlsxCustomWorkbookView struct {
 	XWindow              *int    `xml:"xWindow,attr"`
 	YWindow              *int    `xml:"yWindow,attr"`
 }
+
+// DefinedName directly maps the name for a cell or cell range on a
+// worksheet.
+type DefinedName struct {
+	Name     string
+	Comment  string
+	RefersTo string
+	Scope    string
+}