summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2019-02-22 22:17:38 +0800
committerxuri <xuri.me@gmail.com>2019-02-22 22:17:38 +0800
commit0072bb731043f89ce978778b9d7fdc6160e29de0 (patch)
treec44726082c606dbbcf6fa5c1dfba31cd81993c84
parente780e41e0222517caa9c69030b5955ab2b458a49 (diff)
resolve the issue corrupted xlsx after deleting formula of cell, reference #346
-rw-r--r--calcchain.go55
-rw-r--r--cell.go5
-rw-r--r--col.go4
-rw-r--r--excelize.go4
-rw-r--r--excelize_test.go12
-rw-r--r--file.go1
-rw-r--r--rows.go14
-rw-r--r--sheet.go2
-rwxr-xr-xtest/CalcChain.xlsxbin0 -> 5959 bytes
-rw-r--r--xmlCalcChain.go28
10 files changed, 121 insertions, 4 deletions
diff --git a/calcchain.go b/calcchain.go
new file mode 100644
index 0000000..285a3e9
--- /dev/null
+++ b/calcchain.go
@@ -0,0 +1,55 @@
+// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// this source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+//
+// Package excelize providing a set of functions that allow you to write to
+// and read from XLSX files. Support reads and writes XLSX file generated by
+// Microsoft Excelâ„¢ 2007 and later. Support save file without losing original
+// charts of XLSX. This library needs Go version 1.8 or later.
+
+package excelize
+
+import "encoding/xml"
+
+// calcChainReader provides a function to get the pointer to the structure
+// after deserialization of xl/calcChain.xml.
+func (f *File) calcChainReader() *xlsxCalcChain {
+ if f.CalcChain == nil {
+ var c xlsxCalcChain
+ _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/calcChain.xml")), &c)
+ f.CalcChain = &c
+ }
+ return f.CalcChain
+}
+
+// calcChainWriter provides a function to save xl/calcChain.xml after
+// serialize structure.
+func (f *File) calcChainWriter() {
+ if f.CalcChain != nil {
+ output, _ := xml.Marshal(f.CalcChain)
+ f.saveFileList("xl/calcChain.xml", output)
+ }
+}
+
+// deleteCalcChain provides a function to remove cell reference on the
+// calculation chain.
+func (f *File) deleteCalcChain(axis string) {
+ calc := f.calcChainReader()
+ if calc != nil {
+ for i, c := range calc.C {
+ if c.R == axis {
+ calc.C = append(calc.C[:i], calc.C[i+1:]...)
+ }
+ }
+ }
+ if len(calc.C) == 0 {
+ f.CalcChain = nil
+ delete(f.XLSX, "xl/calcChain.xml")
+ content := f.contentTypesReader()
+ for k, v := range content.Overrides {
+ if v.PartName == "/xl/calcChain.xml" {
+ content.Overrides = append(content.Overrides[:k], content.Overrides[k+1:]...)
+ }
+ }
+ }
+}
diff --git a/cell.go b/cell.go
index afe8635..3cf880a 100644
--- a/cell.go
+++ b/cell.go
@@ -305,6 +305,11 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)
+ if formula == "" {
+ xlsx.SheetData.Row[xAxis].C[yAxis].F = nil
+ f.deleteCalcChain(axis)
+ return
+ }
if xlsx.SheetData.Row[xAxis].C[yAxis].F != nil {
xlsx.SheetData.Row[xAxis].C[yAxis].F.Content = formula
} else {
diff --git a/col.go b/col.go
index af2c321..1130c3a 100644
--- a/col.go
+++ b/col.go
@@ -322,6 +322,10 @@ func (f *File) InsertCol(sheet, column string) {
//
// xlsx.RemoveCol("Sheet1", "C")
//
+// Use this method with caution, which will affect changes in references such
+// as formulas, charts, and so on. If there is any referenced value of the
+// worksheet, it will cause a file error when you open it. The excelize only
+// partially updates these references currently.
func (f *File) RemoveCol(sheet, column string) {
xlsx := f.workSheetReader(sheet)
for r := range xlsx.SheetData.Row {
diff --git a/excelize.go b/excelize.go
index 32f0451..32aa431 100644
--- a/excelize.go
+++ b/excelize.go
@@ -25,6 +25,7 @@ import (
type File struct {
checked map[string]bool
sheetMap map[string]string
+ CalcChain *xlsxCalcChain
ContentTypes *xlsxTypes
Path string
SharedStrings *xlsxSST
@@ -201,7 +202,8 @@ func (f *File) UpdateLinkedValue() {
// row: Index number of the row we're inserting/deleting before
// offset: Number of rows/column to insert/delete negative values indicate deletion
//
-// TODO: adjustPageBreaks, adjustComments, adjustDataValidations, adjustProtectedCells
+// TODO: adjustCalcChain, adjustPageBreaks, adjustComments,
+// adjustDataValidations, adjustProtectedCells
//
func (f *File) adjustHelper(sheet string, column, row, offset int) {
xlsx := f.workSheetReader(sheet)
diff --git a/excelize_test.go b/excelize_test.go
index ebbfcf7..d621b87 100644
--- a/excelize_test.go
+++ b/excelize_test.go
@@ -342,8 +342,18 @@ func TestSetCellFormula(t *testing.T) {
xlsx.SetCellFormula("Sheet1", "C19", "SUM(Sheet2!D2,Sheet2!D9)")
// Test set cell formula with illegal rows number.
xlsx.SetCellFormula("Sheet1", "C", "SUM(Sheet2!D2,Sheet2!D9)")
+ assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellFormula1.xlsx")))
- assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellFormula.xlsx")))
+ xlsx, err = OpenFile(filepath.Join("test", "CalcChain.xlsx"))
+ if !assert.NoError(t, err) {
+ t.FailNow()
+ }
+ // Test remove cell formula.
+ xlsx.SetCellFormula("Sheet1", "A1", "")
+ assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellFormula2.xlsx")))
+ // Test remove all cell formula.
+ xlsx.SetCellFormula("Sheet1", "B1", "")
+ assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellFormula3.xlsx")))
}
func TestSetSheetBackground(t *testing.T) {
diff --git a/file.go b/file.go
index 3e49803..66b46c5 100644
--- a/file.go
+++ b/file.go
@@ -92,6 +92,7 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
f.workbookRelsWriter()
f.worksheetWriter()
f.styleSheetWriter()
+ f.calcChainWriter()
for path, content := range f.XLSX {
fi, err := zw.Create(path)
if err != nil {
diff --git a/rows.go b/rows.go
index 3984216..aebc979 100644
--- a/rows.go
+++ b/rows.go
@@ -343,6 +343,10 @@ func (f *File) GetRowOutlineLevel(sheet string, rowIndex int) uint8 {
//
// xlsx.RemoveRow("Sheet1", 2)
//
+// Use this method with caution, which will affect changes in references such
+// as formulas, charts, and so on. If there is any referenced value of the
+// worksheet, it will cause a file error when you open it. The excelize only
+// partially updates these references currently.
func (f *File) RemoveRow(sheet string, row int) {
if row < 0 {
return
@@ -375,15 +379,23 @@ func (f *File) InsertRow(sheet string, row int) {
//
// xlsx.DuplicateRow("Sheet1", 2)
//
+// Use this method with caution, which will affect changes in references such
+// as formulas, charts, and so on. If there is any referenced value of the
+// worksheet, it will cause a file error when you open it. The excelize only
+// partially updates these references currently.
func (f *File) DuplicateRow(sheet string, row int) {
f.DuplicateRowTo(sheet, row, row+1)
}
// DuplicateRowTo inserts a copy of specified row at specified row position
-// movig down exists rows aftet target position
+// moving down exists rows after target position
//
// xlsx.DuplicateRowTo("Sheet1", 2, 7)
//
+// Use this method with caution, which will affect changes in references such
+// as formulas, charts, and so on. If there is any referenced value of the
+// worksheet, it will cause a file error when you open it. The excelize only
+// partially updates these references currently.
func (f *File) DuplicateRowTo(sheet string, row, row2 int) {
if row <= 0 || row2 <= 0 || row == row2 {
return
diff --git a/sheet.go b/sheet.go
index cb1c08e..efbd466 100644
--- a/sheet.go
+++ b/sheet.go
@@ -900,7 +900,7 @@ func (p *PageLayoutPaperSize) getPageLayout(ps *xlsxPageSetUp) {
// 40 | German standard fanfold (8.5 in. by 12 in.)
// 41 | German legal fanfold (8.5 in. by 13 in.)
// 42 | ISO B4 (250 mm by 353 mm)
-// 43 | Japanese double postcard (200 mm by 148 mm)
+// 43 | Japanese postcard (100 mm by 148 mm)
// 44 | Standard paper (9 in. by 11 in.)
// 45 | Standard paper (10 in. by 11 in.)
// 46 | Standard paper (15 in. by 11 in.)
diff --git a/test/CalcChain.xlsx b/test/CalcChain.xlsx
new file mode 100755
index 0000000..8558f82
--- /dev/null
+++ b/test/CalcChain.xlsx
Binary files differ
diff --git a/xmlCalcChain.go b/xmlCalcChain.go
new file mode 100644
index 0000000..9c916bf
--- /dev/null
+++ b/xmlCalcChain.go
@@ -0,0 +1,28 @@
+// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of
+// this source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+//
+// Package excelize providing a set of functions that allow you to write to
+// and read from XLSX files. Support reads and writes XLSX file generated by
+// Microsoft Excelâ„¢ 2007 and later. Support save file without losing original
+// charts of XLSX. This library needs Go version 1.8 or later.
+
+package excelize
+
+import "encoding/xml"
+
+// xlsxCalcChain directly maps the calcChain element. This element represents the root of the calculation chain.
+type xlsxCalcChain struct {
+ XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main calcChain"`
+ C []xlsxCalcChainC `xml:"c"`
+}
+
+// xlsxCalcChainC directly maps the c element.
+type xlsxCalcChainC struct {
+ R string `xml:"r,attr"`
+ I int `xml:"i,attr"`
+ L bool `xml:"l,attr,omitempty"`
+ S bool `xml:"s,attr,omitempty"`
+ T bool `xml:"t,attr,omitempty"`
+ A bool `xml:"a,attr,omitempty"`
+}