From e6765f081fd8b826639ab54bc65d0ec985af0207 Mon Sep 17 00:00:00 2001
From: NaturalGao <43291304+NaturalGao@users.noreply.github.com>
Date: Fri, 19 Aug 2022 23:24:13 +0800
Subject: [PATCH] This closes #849, add new function `DeleteComment` for delete
comment (#1317)
- Update unit tests for the delete comment
- Add 3 errors function for error messages
---
comment.go | 33 +++++++++++++++++++++++++++++++++
comment_test.go | 26 ++++++++++++++++++++++++++
docProps.go | 9 ++++-----
drawing.go | 3 +--
errors.go | 17 +++++++++++++++++
excelize.go | 8 ++++----
picture.go | 5 ++---
stream.go | 2 +-
8 files changed, 88 insertions(+), 15 deletions(-)
diff --git a/comment.go b/comment.go
index 82d1f88cf0f..ac22ec7476a 100644
--- a/comment.go
+++ b/comment.go
@@ -140,6 +140,39 @@ func (f *File) AddComment(sheet, cell, format string) error {
return err
}
+// DeleteComment provides the method to delete comment in a sheet by given
+// worksheet. For example, delete the comment in Sheet1!$A$30:
+//
+// err := f.DeleteComment("Sheet1", "A30")
+func (f *File) DeleteComment(sheet, cell string) (err error) {
+ sheetXMLPath, ok := f.getSheetXMLPath(sheet)
+ if !ok {
+ err = newNoExistSheetError(sheet)
+ return
+ }
+ commentsXML := f.getSheetComments(filepath.Base(sheetXMLPath))
+ if !strings.HasPrefix(commentsXML, "/") {
+ commentsXML = "xl" + strings.TrimPrefix(commentsXML, "..")
+ }
+ commentsXML = strings.TrimPrefix(commentsXML, "/")
+ if comments := f.commentsReader(commentsXML); comments != nil {
+ for i, cmt := range comments.CommentList.Comment {
+ if cmt.Ref == cell {
+ if len(comments.CommentList.Comment) > 1 {
+ comments.CommentList.Comment = append(
+ comments.CommentList.Comment[:i],
+ comments.CommentList.Comment[i+1:]...,
+ )
+ continue
+ }
+ comments.CommentList.Comment = nil
+ }
+ }
+ f.Comments[commentsXML] = comments
+ }
+ return
+}
+
// addDrawingVML provides a function to create comment as
// xl/drawings/vmlDrawing%d.vml by given commit ID and cell.
func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, colCount int) error {
diff --git a/comment_test.go b/comment_test.go
index 01f1e42e3e3..c2d9fe2edaa 100644
--- a/comment_test.go
+++ b/comment_test.go
@@ -46,6 +46,32 @@ func TestAddComments(t *testing.T) {
assert.EqualValues(t, len(NewFile().GetComments()), 0)
}
+func TestDeleteComment(t *testing.T) {
+ f, err := prepareTestBook1()
+ if !assert.NoError(t, err) {
+ t.FailNow()
+ }
+
+ assert.NoError(t, f.AddComment("Sheet2", "A40", `{"author":"Excelize: ","text":"This is a comment1."}`))
+ assert.NoError(t, f.AddComment("Sheet2", "A41", `{"author":"Excelize: ","text":"This is a comment2."}`))
+ assert.NoError(t, f.AddComment("Sheet2", "C41", `{"author":"Excelize: ","text":"This is a comment3."}`))
+
+ assert.NoError(t, f.DeleteComment("Sheet2", "A40"))
+
+ assert.EqualValues(t, 2, len(f.GetComments()["Sheet2"]))
+ assert.EqualValues(t, len(NewFile().GetComments()), 0)
+
+ // Test delete all comments in a worksheet
+ assert.NoError(t, f.DeleteComment("Sheet2", "A41"))
+ assert.NoError(t, f.DeleteComment("Sheet2", "C41"))
+ assert.EqualValues(t, 0, len(f.GetComments()["Sheet2"]))
+ // Test delete comment on not exists worksheet
+ assert.EqualError(t, f.DeleteComment("SheetN", "A1"), "sheet SheetN is not exist")
+ // Test delete comment with worksheet part
+ f.Pkg.Delete("xl/worksheets/sheet1.xml")
+ assert.NoError(t, f.DeleteComment("Sheet1", "A22"))
+}
+
func TestDecodeVMLDrawingReader(t *testing.T) {
f := NewFile()
path := "xl/drawings/vmlDrawing1.xml"
diff --git a/docProps.go b/docProps.go
index df15b57dc8f..00ff808bbdf 100644
--- a/docProps.go
+++ b/docProps.go
@@ -14,7 +14,6 @@ package excelize
import (
"bytes"
"encoding/xml"
- "fmt"
"io"
"reflect"
)
@@ -76,7 +75,7 @@ func (f *File) SetAppProps(appProperties *AppProperties) (err error) {
app = new(xlsxProperties)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathDocPropsApp)))).
Decode(app); err != nil && err != io.EOF {
- err = fmt.Errorf("xml decode error: %s", err)
+ err = newDecodeXMLError(err)
return
}
fields = []string{"Application", "ScaleCrop", "DocSecurity", "Company", "LinksUpToDate", "HyperlinksChanged", "AppVersion"}
@@ -103,7 +102,7 @@ func (f *File) GetAppProps() (ret *AppProperties, err error) {
app := new(xlsxProperties)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathDocPropsApp)))).
Decode(app); err != nil && err != io.EOF {
- err = fmt.Errorf("xml decode error: %s", err)
+ err = newDecodeXMLError(err)
return
}
ret, err = &AppProperties{
@@ -181,7 +180,7 @@ func (f *File) SetDocProps(docProperties *DocProperties) (err error) {
core = new(decodeCoreProperties)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathDocPropsCore)))).
Decode(core); err != nil && err != io.EOF {
- err = fmt.Errorf("xml decode error: %s", err)
+ err = newDecodeXMLError(err)
return
}
newProps, err = &xlsxCoreProperties{
@@ -236,7 +235,7 @@ func (f *File) GetDocProps() (ret *DocProperties, err error) {
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathDocPropsCore)))).
Decode(core); err != nil && err != io.EOF {
- err = fmt.Errorf("xml decode error: %s", err)
+ err = newDecodeXMLError(err)
return
}
ret, err = &DocProperties{
diff --git a/drawing.go b/drawing.go
index 10f4cd0f2c5..5015d265bf5 100644
--- a/drawing.go
+++ b/drawing.go
@@ -14,7 +14,6 @@ package excelize
import (
"bytes"
"encoding/xml"
- "fmt"
"io"
"log"
"reflect"
@@ -1322,7 +1321,7 @@ func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (err
deTwoCellAnchor = new(decodeTwoCellAnchor)
if err = f.xmlNewDecoder(strings.NewReader("" + wsDr.TwoCellAnchor[idx].GraphicFrame + "")).
Decode(deTwoCellAnchor); err != nil && err != io.EOF {
- err = fmt.Errorf("xml decode error: %s", err)
+ err = newDecodeXMLError(err)
return
}
if err = nil; deTwoCellAnchor.From != nil && decodeTwoCellAnchorFuncs[drawingType](deTwoCellAnchor) {
diff --git a/errors.go b/errors.go
index f5ea06e6589..fbcef043a65 100644
--- a/errors.go
+++ b/errors.go
@@ -70,6 +70,23 @@ func newCellNameToCoordinatesError(cell string, err error) error {
return fmt.Errorf("cannot convert cell %q to coordinates: %v", cell, err)
}
+// newNoExistSheetError defined the error message on receiving the not exist
+// sheet name.
+func newNoExistSheetError(name string) error {
+ return fmt.Errorf("sheet %s is not exist", name)
+}
+
+// newNotWorksheetError defined the error message on receiving a sheet which
+// not a worksheet.
+func newNotWorksheetError(name string) error {
+ return fmt.Errorf("sheet %s is not a worksheet", name)
+}
+
+// newDecodeXMLError defined the error message on decode XML error.
+func newDecodeXMLError(err error) error {
+ return fmt.Errorf("xml decode error: %s", err)
+}
+
var (
// ErrStreamSetColWidth defined the error message on set column width in
// stream writing mode.
diff --git a/excelize.go b/excelize.go
index ef438dd8dd2..f3b4381da2f 100644
--- a/excelize.go
+++ b/excelize.go
@@ -231,7 +231,7 @@ func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
ok bool
)
if name, ok = f.getSheetXMLPath(sheet); !ok {
- err = fmt.Errorf("sheet %s is not exist", sheet)
+ err = newNoExistSheetError(sheet)
return
}
if worksheet, ok := f.Sheet.Load(name); ok && worksheet != nil {
@@ -240,7 +240,7 @@ func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
}
for _, sheetType := range []string{"xl/chartsheets", "xl/dialogsheet", "xl/macrosheet"} {
if strings.HasPrefix(name, sheetType) {
- err = fmt.Errorf("sheet %s is not a worksheet", sheet)
+ err = newNotWorksheetError(sheet)
return
}
}
@@ -251,7 +251,7 @@ func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
}
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readBytes(name)))).
Decode(ws); err != nil && err != io.EOF {
- err = fmt.Errorf("xml decode error: %s", err)
+ err = newDecodeXMLError(err)
return
}
err = nil
@@ -424,7 +424,7 @@ func (f *File) UpdateLinkedValue() error {
for _, name := range f.GetSheetList() {
ws, err := f.workSheetReader(name)
if err != nil {
- if err.Error() == fmt.Sprintf("sheet %s is not a worksheet", trimSheetName(name)) {
+ if err.Error() == newNotWorksheetError(name).Error() {
continue
}
return err
diff --git a/picture.go b/picture.go
index c78df93cf3a..84c77316817 100644
--- a/picture.go
+++ b/picture.go
@@ -15,7 +15,6 @@ import (
"bytes"
"encoding/json"
"encoding/xml"
- "fmt"
"image"
"io"
"io/ioutil"
@@ -554,7 +553,7 @@ func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string)
deWsDr = new(decodeWsDr)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(drawingXML)))).
Decode(deWsDr); err != nil && err != io.EOF {
- err = fmt.Errorf("xml decode error: %s", err)
+ err = newDecodeXMLError(err)
return
}
err = nil
@@ -562,7 +561,7 @@ func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string)
deTwoCellAnchor = new(decodeTwoCellAnchor)
if err = f.xmlNewDecoder(strings.NewReader("" + anchor.Content + "")).
Decode(deTwoCellAnchor); err != nil && err != io.EOF {
- err = fmt.Errorf("xml decode error: %s", err)
+ err = newDecodeXMLError(err)
return
}
if err = nil; deTwoCellAnchor.From != nil && deTwoCellAnchor.Pic != nil {
diff --git a/stream.go b/stream.go
index be8ad2e3155..46df2486a97 100644
--- a/stream.go
+++ b/stream.go
@@ -92,7 +92,7 @@ type StreamWriter struct {
func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
sheetID := f.getSheetID(sheet)
if sheetID == -1 {
- return nil, fmt.Errorf("sheet %s is not exist", sheet)
+ return nil, newNoExistSheetError(sheet)
}
sw := &StreamWriter{
File: f,