diff --git a/README.md b/README.md index 1cfe4e5..431aea6 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,15 @@ import ( ) func main() { - xlsx := excelize.CreateFile() + xlsx, err := excelize.CreateFile() + if err != nil { + fmt.Println(err) + } xlsx.NewSheet(2, "Sheet2") xlsx.NewSheet(3, "Sheet3") xlsx.SetCellInt("Sheet2", "A23", 10) xlsx.SetCellStr("Sheet3", "B20", "Hello") - err := xlsx.WriteTo("/home/Workbook.xlsx") + err = xlsx.WriteTo("/home/Workbook.xlsx") if err != nil { fmt.Println(err) } @@ -59,14 +62,17 @@ import ( ) func main() { - xlsx := excelize.OpenFile("/home/Workbook.xlsx") + xlsx, err := excelize.OpenFile("/home/Workbook.xlsx") + if err != nil { + fmt.Println(err) + } xlsx.SetCellInt("Sheet2", "B2", 100) xlsx.SetCellStr("Sheet2", "C11", "Hello") xlsx.NewSheet(3, "TestSheet") xlsx.SetCellInt("Sheet3", "A23", 10) xlsx.SetCellStr("Sheet3", "b230", "World") xlsx.SetActiveSheet(2) - err := xlsx.Save() + err = xlsx.Save() if err != nil { fmt.Println(err) } @@ -84,7 +90,10 @@ import ( ) func main() { - xlsx := excelize.OpenFile("/home/Workbook.xlsx") + xlsx, err := excelize.OpenFile("/home/Workbook.xlsx") + if err != nil { + fmt.Println(err) + } cell := xlsx.GetCellValue("Sheet2", "D11") fmt.Println(cell) } diff --git a/excelize.go b/excelize.go index d37860f..15710db 100644 --- a/excelize.go +++ b/excelize.go @@ -11,21 +11,28 @@ import ( // File define a populated xlsx.File struct. type File struct { - XLSX map[string]string - Path string + XLSX map[string]string + Path string + SheetCount int } // OpenFile take the name of an XLSX file and returns a populated // xlsx.File struct for it. -func OpenFile(filename string) *File { +func OpenFile(filename string) (*File, error) { var f *zip.ReadCloser + var err error file := make(map[string]string) - f, _ = zip.OpenReader(filename) - file, _ = ReadZip(f) - return &File{ - XLSX: file, - Path: filename, + sheetCount := 0 + f, err = zip.OpenReader(filename) + if err != nil { + return &File{}, err } + file, sheetCount, err = ReadZip(f) + return &File{ + XLSX: file, + Path: filename, + SheetCount: sheetCount, + }, nil } // SetCellInt provide function to set int type value of a cell @@ -176,6 +183,7 @@ func replaceWorkSheetsRelationshipsNameSpace(workbookMarshal string) string { // // // +// Noteice: this method could be very slow for large spreadsheets (more than 3000 rows one sheet). func checkRow(xlsx xlsxWorksheet) xlsxWorksheet { buffer := bytes.Buffer{} for k, v := range xlsx.SheetData.Row { @@ -207,3 +215,44 @@ func checkRow(xlsx xlsxWorksheet) xlsxWorksheet { } return xlsx } + +// UpdateLinkedValue fix linked values within a spreadsheet are not updating. +// This function will be remove value tag when met a cell have a linked value. +// Reference https://social.technet.microsoft.com/Forums/office/en-US/e16bae1f-6a2c-4325-8013-e989a3479066/excel-2010-linked-cells-not-updating?forum=excel +// +// Notice: after open XLSX file Excel will be update linked value and generate +// new value and will prompt save file or not. +// +// For example: +// +// +// +// SUM(Sheet2!D2,Sheet2!D11) +// 100 +// +// +// +// to +// +// +// +// SUM(Sheet2!D2,Sheet2!D11) +// +// +func (f *File) UpdateLinkedValue() { + for i := 1; i <= f.SheetCount; i++ { + var xlsx xlsxWorksheet + name := `xl/worksheets/sheet` + strconv.Itoa(i) + `.xml` + xml.Unmarshal([]byte(f.readXML(name)), &xlsx) + for indexR, row := range xlsx.SheetData.Row { + for indexC, col := range row.C { + if col.F != nil && col.V != `` { + xlsx.SheetData.Row[indexR].C[indexC].V = `` + xlsx.SheetData.Row[indexR].C[indexC].T = `` + } + } + } + output, _ := xml.Marshal(xlsx) + f.saveFileList(name, replaceRelationshipsID(replaceWorkSheetsRelationshipsNameSpace(string(output)))) + } +} diff --git a/excelize_test.go b/excelize_test.go index d206e2d..7af1991 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -7,7 +7,11 @@ import ( func TestExcelize(t *testing.T) { // Test update a XLSX file - file := OpenFile("./test/Workbook1.xlsx") + file, err := OpenFile("./test/Workbook1.xlsx") + if err != nil { + t.Log(err) + } + file.UpdateLinkedValue() file.SetCellInt("SHEET2", "B2", 100) file.SetCellStr("SHEET2", "C11", "Knowns") file.NewSheet(3, "TestSheet") @@ -15,10 +19,20 @@ func TestExcelize(t *testing.T) { file.SetCellStr("SHEET3", "b230", "10") file.SetCellStr("SHEET10", "b230", "10") file.SetActiveSheet(2) + // Test read cell value with given illegal rows number + file.GetCellValue("Sheet2", "a-1") + // Test read cell value with given lowercase column number + file.GetCellValue("Sheet2", "a5") + file.GetCellValue("Sheet2", "C11") + file.GetCellValue("Sheet2", "D11") + file.GetCellValue("Sheet2", "D12") + // Test read cell value with given axis large than exists row + file.GetCellValue("Sheet2", "E13") + for i := 1; i <= 300; i++ { file.SetCellStr("SHEET3", "c"+strconv.Itoa(i), strconv.Itoa(i)) } - err := file.Save() + err = file.Save() if err != nil { t.Log(err) } @@ -45,13 +59,9 @@ func TestExcelize(t *testing.T) { t.Log(err) } - // Test read cell value with given illegal rows number - file.GetCellValue("Sheet2", "a-1") - // Test read cell value with given lowercase column number - file.GetCellValue("Sheet2", "a5") - file.GetCellValue("Sheet2", "C11") - file.GetCellValue("Sheet2", "D11") - file.GetCellValue("Sheet2", "D12") - // Test read cell value with given axis large than exists row - file.GetCellValue("Sheet2", "E13") + // Test open a XLSX file with given illegal path + _, err = OpenFile("./test/Workbook.xlsx") + if err != nil { + t.Log(err) + } } diff --git a/lib.go b/lib.go index 915bca1..0fe6870 100644 --- a/lib.go +++ b/lib.go @@ -14,19 +14,25 @@ import ( // ReadZip takes a pointer to a zip.ReadCloser and returns a // xlsx.File struct populated with its contents. In most cases // ReadZip is not used directly, but is called internally by OpenFile. -func ReadZip(f *zip.ReadCloser) (map[string]string, error) { +func ReadZip(f *zip.ReadCloser) (map[string]string, int, error) { defer f.Close() return ReadZipReader(&f.Reader) } // ReadZipReader can be used to read an XLSX in memory without // touching the filesystem. -func ReadZipReader(r *zip.Reader) (map[string]string, error) { +func ReadZipReader(r *zip.Reader) (map[string]string, int, error) { fileList := make(map[string]string) + worksheets := 0 for _, v := range r.File { fileList[v.Name] = readFile(v) + if len(v.Name) > 18 { + if v.Name[0:19] == "xl/worksheets/sheet" { + worksheets++ + } + } } - return fileList, nil + return fileList, worksheets, nil } // Read XML content as string and replace drawing property in XML namespace of sheet diff --git a/test/Workbook1.xlsx b/test/Workbook1.xlsx index 05b51c2..81565d6 100644 Binary files a/test/Workbook1.xlsx and b/test/Workbook1.xlsx differ