diff --git a/comment.go b/comment.go index 42e7d451..5db6312f 100644 --- a/comment.go +++ b/comment.go @@ -122,31 +122,34 @@ func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, row, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell)) xAxis := row - 1 yAxis := TitleToNumber(col) - vml := vmlDrawing{ - XMLNSv: "urn:schemas-microsoft-com:vml", - XMLNSo: "urn:schemas-microsoft-com:office:office", - XMLNSx: "urn:schemas-microsoft-com:office:excel", - XMLNSmv: "http://macVmlSchemaUri", - Shapelayout: &xlsxShapelayout{ - Ext: "edit", - IDmap: &xlsxIDmap{ - Ext: "edit", - Data: commentID, + vml := f.VMLDrawing[drawingVML] + if vml == nil { + vml = &vmlDrawing{ + XMLNSv: "urn:schemas-microsoft-com:vml", + XMLNSo: "urn:schemas-microsoft-com:office:office", + XMLNSx: "urn:schemas-microsoft-com:office:excel", + XMLNSmv: "http://macVmlSchemaUri", + Shapelayout: &xlsxShapelayout{ + Ext: "edit", + IDmap: &xlsxIDmap{ + Ext: "edit", + Data: commentID, + }, }, - }, - Shapetype: &xlsxShapetype{ - ID: "_x0000_t202", - Coordsize: "21600,21600", - Spt: 202, - Path: "m0,0l0,21600,21600,21600,21600,0xe", - Stroke: &xlsxStroke{ - Joinstyle: "miter", + Shapetype: &xlsxShapetype{ + ID: "_x0000_t202", + Coordsize: "21600,21600", + Spt: 202, + Path: "m0,0l0,21600,21600,21600,21600,0xe", + Stroke: &xlsxStroke{ + Joinstyle: "miter", + }, + VPath: &vPath{ + Gradientshapeok: "t", + Connecttype: "miter", + }, }, - VPath: &vPath{ - Gradientshapeok: "t", - Connecttype: "miter", - }, - }, + } } sp := encodeShape{ Fill: &vFill{ @@ -191,10 +194,8 @@ func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, Strokecolor: "#edeaa1", Val: string(s[13 : len(s)-14]), } - c, ok := f.XLSX[drawingVML] - if ok { - d := decodeVmlDrawing{} - _ = xml.Unmarshal(namespaceStrictToTransitional(c), &d) + d := f.decodeVMLDrawingReader(drawingVML) + if d != nil { for _, v := range d.Shape { s := xlsxShape{ ID: "_x0000_s1025", @@ -208,8 +209,7 @@ func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, } } vml.Shape = append(vml.Shape, shape) - v, _ := xml.Marshal(vml) - f.XLSX[drawingVML] = v + f.VMLDrawing[drawingVML] = vml } // addComment provides a function to create chart as xl/comments%d.xml by @@ -223,12 +223,15 @@ func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) { if len(t) > 32512 { t = t[0:32512] } - comments := xlsxComments{ - Authors: []xlsxAuthor{ - { - Author: formatSet.Author, + comments := f.commentsReader(commentsXML) + if comments == nil { + comments = &xlsxComments{ + Authors: []xlsxAuthor{ + { + Author: formatSet.Author, + }, }, - }, + } } cmt := xlsxComment{ Ref: cell, @@ -261,15 +264,8 @@ func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) { }, }, } - c, ok := f.XLSX[commentsXML] - if ok { - d := xlsxComments{} - _ = xml.Unmarshal(namespaceStrictToTransitional(c), &d) - comments.CommentList.Comment = append(comments.CommentList.Comment, d.CommentList.Comment...) - } comments.CommentList.Comment = append(comments.CommentList.Comment, cmt) - v, _ := xml.Marshal(comments) - f.saveFileList(commentsXML, v) + f.Comments[commentsXML] = comments } // countComments provides a function to get comments files count storage in @@ -283,3 +279,53 @@ func (f *File) countComments() int { } return count } + +// decodeVMLDrawingReader provides a function to get the pointer to the +// structure after deserialization of xl/drawings/vmlDrawing%d.xml. +func (f *File) decodeVMLDrawingReader(path string) *decodeVmlDrawing { + if f.DecodeVMLDrawing[path] == nil { + c, ok := f.XLSX[path] + if ok { + d := decodeVmlDrawing{} + _ = xml.Unmarshal(namespaceStrictToTransitional(c), &d) + f.DecodeVMLDrawing[path] = &d + } + } + return f.DecodeVMLDrawing[path] +} + +// vmlDrawingWriter provides a function to save xl/drawings/vmlDrawing%d.xml. +// after serialize structure. +func (f *File) vmlDrawingWriter() { + for path, vml := range f.VMLDrawing { + if vml != nil { + v, _ := xml.Marshal(vml) + f.XLSX[path] = v + } + } +} + +// commentsReader provides a function to get the pointer to the structure +// after deserialization of xl/comments%d.xml. +func (f *File) commentsReader(path string) *xlsxComments { + if f.Comments[path] == nil { + content, ok := f.XLSX[path] + if ok { + c := xlsxComments{} + _ = xml.Unmarshal(namespaceStrictToTransitional(content), &c) + f.Comments[path] = &c + } + } + return f.Comments[path] +} + +// commentsWriter provides a function to save xl/comments%d.xml after +// serialize structure. +func (f *File) commentsWriter() { + for path, c := range f.Comments { + if c != nil { + v, _ := xml.Marshal(c) + f.saveFileList(path, v) + } + } +} diff --git a/excelize.go b/excelize.go index 32aa431e..df3cd05b 100644 --- a/excelize.go +++ b/excelize.go @@ -23,19 +23,22 @@ import ( // File define a populated XLSX file struct. type File struct { - checked map[string]bool - sheetMap map[string]string - CalcChain *xlsxCalcChain - ContentTypes *xlsxTypes - Path string - SharedStrings *xlsxSST - Sheet map[string]*xlsxWorksheet - SheetCount int - Styles *xlsxStyleSheet - Theme *xlsxTheme - WorkBook *xlsxWorkbook - WorkBookRels *xlsxWorkbookRels - XLSX map[string][]byte + checked map[string]bool + sheetMap map[string]string + CalcChain *xlsxCalcChain + Comments map[string]*xlsxComments + ContentTypes *xlsxTypes + Path string + SharedStrings *xlsxSST + Sheet map[string]*xlsxWorksheet + SheetCount int + Styles *xlsxStyleSheet + Theme *xlsxTheme + DecodeVMLDrawing map[string]*decodeVmlDrawing + VMLDrawing map[string]*vmlDrawing + WorkBook *xlsxWorkbook + WorkBookRels *xlsxWorkbookRels + XLSX map[string][]byte } // OpenFile take the name of an XLSX file and returns a populated XLSX file @@ -71,11 +74,15 @@ func OpenReader(r io.Reader) (*File, error) { return nil, err } f := &File{ - checked: make(map[string]bool), - Sheet: make(map[string]*xlsxWorksheet), - SheetCount: sheetCount, - XLSX: file, + checked: make(map[string]bool), + Comments: make(map[string]*xlsxComments), + Sheet: make(map[string]*xlsxWorksheet), + SheetCount: sheetCount, + DecodeVMLDrawing: make(map[string]*decodeVmlDrawing), + VMLDrawing: make(map[string]*vmlDrawing), + XLSX: file, } + f.CalcChain = f.calcChainReader() f.sheetMap = f.getSheetMap() f.Styles = f.stylesReader() f.Theme = f.themeReader() diff --git a/file.go b/file.go index 66b46c59..b6bf57d0 100644 --- a/file.go +++ b/file.go @@ -39,8 +39,12 @@ func NewFile() *File { SheetCount: 1, XLSX: file, } + f.CalcChain = f.calcChainReader() + f.Comments = make(map[string]*xlsxComments) f.ContentTypes = f.contentTypesReader() f.Styles = f.stylesReader() + f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing) + f.VMLDrawing = make(map[string]*vmlDrawing) f.WorkBook = f.workbookReader() f.WorkBookRels = f.workbookRelsReader() f.Sheet["xl/worksheets/sheet1.xml"] = f.workSheetReader("Sheet1") @@ -87,12 +91,15 @@ func (f *File) WriteTo(w io.Writer) (int64, error) { func (f *File) WriteToBuffer() (*bytes.Buffer, error) { buf := new(bytes.Buffer) zw := zip.NewWriter(buf) + f.calcChainWriter() + f.commentsWriter() f.contentTypesWriter() + f.vmlDrawingWriter() f.workbookWriter() f.workbookRelsWriter() f.worksheetWriter() f.styleSheetWriter() - f.calcChainWriter() + for path, content := range f.XLSX { fi, err := zw.Create(path) if err != nil {