Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix-save-to-file-as-stream #489

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions calcchain.go
Expand Up @@ -10,8 +10,8 @@
package excelize

import (
"archive/zip"
"bytes"
"encoding/xml"
"io"
"log"
)
Expand All @@ -34,11 +34,11 @@ func (f *File) calcChainReader() *xlsxCalcChain {

// calcChainWriter provides a function to save xl/calcChain.xml after
// serialize structure.
func (f *File) calcChainWriter() {
func (f File) calcChainWriter(zw *zip.Writer) error {
if f.CalcChain != nil && f.CalcChain.C != nil {
output, _ := xml.Marshal(f.CalcChain)
f.saveFileList("xl/calcChain.xml", output)
return writeXMLToZipWriter(zw, "xl/calcChain.xml", f.CalcChain)
}
return nil
}

// deleteCalcChain provides a function to remove cell reference on the
Expand Down
4 changes: 2 additions & 2 deletions cell.go
Expand Up @@ -385,7 +385,7 @@ func (f *File) GetCellHyperLink(sheet, axis string) (bool, string, error) {
if xlsx.Hyperlinks != nil {
for _, link := range xlsx.Hyperlinks.Hyperlink {
if link.Ref == axis {
if link.RID != "" {
if len(link.RID) != 0 {
return true, f.getSheetRelationshipsTargetByID(sheet, link.RID), err
}
return true, link.Location, err
Expand Down Expand Up @@ -443,7 +443,7 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) error {
sheetPath := f.sheetMap[trimSheetName(sheet)]
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
rID := f.addRels(sheetRels, SourceRelationshipHyperLink, link, linkType)
linkData.RID = "rId" + strconv.Itoa(rID)
linkData.RID = relationship("rId" + strconv.Itoa(rID))
case "Location":
linkData = xlsxHyperlink{
Ref: axis,
Expand Down
23 changes: 15 additions & 8 deletions comment.go
Expand Up @@ -10,6 +10,7 @@
package excelize

import (
"archive/zip"
"bytes"
"encoding/json"
"encoding/xml"
Expand Down Expand Up @@ -322,13 +323,16 @@ func (f *File) decodeVMLDrawingReader(path string) *decodeVmlDrawing {

// vmlDrawingWriter provides a function to save xl/drawings/vmlDrawing%d.xml
// after serialize structure.
func (f *File) vmlDrawingWriter() {
func (f *File) vmlDrawingWriter(zw *zip.Writer) error {
for path, vml := range f.VMLDrawing {
if vml != nil {
v, _ := xml.Marshal(vml)
f.XLSX[path] = v
if vml == nil {
continue
}
if err := writeXMLToZipWriter(zw, path, vml); err != nil {
return err
}
}
return nil
}

// commentsReader provides a function to get the pointer to the structure
Expand All @@ -351,11 +355,14 @@ func (f *File) commentsReader(path string) *xlsxComments {

// commentsWriter provides a function to save xl/comments%d.xml after
// serialize structure.
func (f *File) commentsWriter() {
func (f *File) commentsWriter(zw *zip.Writer) error {
for path, c := range f.Comments {
if c != nil {
v, _ := xml.Marshal(c)
f.saveFileList(path, v)
if c == nil {
continue
}
if err := writeXMLToZipWriter(zw, path, c); err != nil {
return err
}
}
return nil
}
4 changes: 2 additions & 2 deletions excelize.go
Expand Up @@ -232,7 +232,7 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int {
// Office Excel 2007.
func replaceWorkSheetsRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte {
var oldXmlns = []byte(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
var newXmlns = []byte(`<worksheet` + templateNamespaceIDMap)
var newXmlns = []byte(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ` + templateNamespaceIDMap+">")
workbookMarshal = bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1)
return workbookMarshal
}
Expand All @@ -242,7 +242,7 @@ func replaceWorkSheetsRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte
// Excel 2007.
func replaceStyleRelationshipsNameSpaceBytes(contentMarshal []byte) []byte {
var oldXmlns = []byte(`<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
var newXmlns = []byte(`<styleSheet` + templateNamespaceIDMap)
var newXmlns = []byte(`<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ` + templateNamespaceIDMap+">")
contentMarshal = bytes.Replace(contentMarshal, oldXmlns, newXmlns, -1)
return contentMarshal
}
Expand Down
3 changes: 2 additions & 1 deletion excelize_test.go
Expand Up @@ -5,6 +5,7 @@ import (
"compress/gzip"
"encoding/xml"
"fmt"
"github.com/stretchr/testify/require"
"image/color"
_ "image/gif"
_ "image/jpeg"
Expand Down Expand Up @@ -925,7 +926,7 @@ func TestGetActiveSheetIndex(t *testing.T) {
func TestRelsWriter(t *testing.T) {
f := NewFile()
f.Relationships["xl/worksheets/sheet/rels/sheet1.xml.rel"] = &xlsxRelationships{}
f.relsWriter()
require.NoError(t, f.SaveAs("test/RelsWriter.xlsx"))
}

func TestGetSheetView(t *testing.T) {
Expand Down
85 changes: 52 additions & 33 deletions file.go
Expand Up @@ -72,44 +72,63 @@ func (f *File) SaveAs(name string) error {

// Write provides a function to write to an io.Writer.
func (f *File) Write(w io.Writer) error {
_, err := f.WriteTo(w)
return err
}

// WriteTo implements io.WriterTo to write the file.
func (f *File) WriteTo(w io.Writer) (int64, error) {
ducquangkstn marked this conversation as resolved.
Show resolved Hide resolved
buf, err := f.WriteToBuffer()
if err != nil {
return 0, err
}
return buf.WriteTo(w)
}

// WriteToBuffer provides a function to get bytes.Buffer from the saved file.
func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
buf := new(bytes.Buffer)
zw := zip.NewWriter(buf)
f.calcChainWriter()
f.commentsWriter()
f.contentTypesWriter()
f.drawingsWriter()
f.vmlDrawingWriter()
f.workBookWriter()
f.workSheetWriter()
f.relsWriter()
f.styleSheetWriter()
var err error
zw := zip.NewWriter(w)
isZipWriterClosed := false
defer func() {
if !isZipWriterClosed {
zw.Close()
}
}()

for path, content := range f.XLSX {
if path == "xl/styles.xml" || path == "xl/workbook.xml" || path == "[Content_Types].xml" {
continue
}
fi, err := zw.Create(path)
if err != nil {
zw.Close()
return buf, err
return err
}
_, err = fi.Write(content)
if err != nil {
zw.Close()
return buf, err
if _, err = fi.Write(content); err != nil {
return err
}
}
return buf, zw.Close()
if err = f.calcChainWriter(zw); err != nil {
return err
}
if err = f.commentsWriter(zw); err != nil {
return err
}
if err = f.contentTypesWriter(zw); err != nil {
return err
}
if err = f.drawingsWriter(zw); err != nil {
return err
}
if err = f.vmlDrawingWriter(zw); err != nil {
return err
}
if err = f.workBookWriter(zw); err != nil {
return err
}
if err = f.workSheetWriter(zw); err != nil {
return err
}
if err = f.relsWriter(zw); err != nil {
return err
}
if err = f.styleSheetWriter(zw); err != nil {
return err
}
isZipWriterClosed = true
return zw.Close()
}

// WriteTo implements io.WriterTo to write the file.
func (f *File) WriteTo(w io.Writer) (int64, error) {
buf := new(bytes.Buffer)
if err := f.Write(buf); err != nil {
return 0, err
}
return buf.WriteTo(w)
}
25 changes: 25 additions & 0 deletions lib.go
Expand Up @@ -12,6 +12,7 @@ package excelize
import (
"archive/zip"
"bytes"
"encoding/xml"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -50,6 +51,30 @@ func (f *File) saveFileList(name string, content []byte) {
f.XLSX[name] = newContent
}

// writeXMLToZipWriter writes data obj in form of XML to zip,Writer
func writeXMLToZipWriter(zw *zip.Writer, name string, data interface{}) error {
w, err := zw.Create(name)
if err != nil {
return err
}
_, err = w.Write([]byte(XMLHeader))
if err != nil {
return err
}
encoder := xml.NewEncoder(w)
return encoder.Encode(data)
}

// writeStringToZipWriter writes string to zip.Writer
func writeStringToZipWriter(zw *zip.Writer, name string, data string) error {
w, err := zw.Create(name)
if err != nil {
return err
}
_, err = w.Write([]byte(XMLHeader + data))
return err
}

// Read file content as string in a archive file.
func readFile(file *zip.File) []byte {
rc, err := file.Open()
Expand Down
27 changes: 15 additions & 12 deletions picture.go
Expand Up @@ -10,9 +10,9 @@
package excelize

import (
"archive/zip"
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"image"
Expand Down Expand Up @@ -170,7 +170,7 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
// deleteSheetRelationships provides a function to delete relationships in
// xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name and
// relationship index.
func (f *File) deleteSheetRelationships(sheet, rID string) {
func (f *File) deleteSheetRelationships(sheet string, rID relationship) {
name, ok := f.sheetMap[trimSheetName(sheet)]
if !ok {
name = strings.ToLower(sheet) + ".xml"
Expand All @@ -181,7 +181,7 @@ func (f *File) deleteSheetRelationships(sheet, rID string) {
sheetRels = &xlsxRelationships{}
}
for k, v := range sheetRels.Relationships {
if v.ID == rID {
if v.ID == string(rID) {
sheetRels.Relationships = append(sheetRels.Relationships[:k], sheetRels.Relationships[k+1:]...)
}
}
Expand All @@ -193,7 +193,7 @@ func (f *File) deleteSheetRelationships(sheet, rID string) {
func (f *File) addSheetLegacyDrawing(sheet string, rID int) {
xlsx, _ := f.workSheetReader(sheet)
xlsx.LegacyDrawing = &xlsxLegacyDrawing{
RID: "rId" + strconv.Itoa(rID),
RID: relationship("rId" + strconv.Itoa(rID)),
}
}

Expand All @@ -202,7 +202,7 @@ func (f *File) addSheetLegacyDrawing(sheet string, rID int) {
func (f *File) addSheetDrawing(sheet string, rID int) {
xlsx, _ := f.workSheetReader(sheet)
xlsx.Drawing = &xlsxDrawing{
RID: "rId" + strconv.Itoa(rID),
RID: relationship("rId" + strconv.Itoa(rID)),
}
}

Expand All @@ -211,7 +211,7 @@ func (f *File) addSheetDrawing(sheet string, rID int) {
func (f *File) addSheetPicture(sheet string, rID int) {
xlsx, _ := f.workSheetReader(sheet)
xlsx.Picture = &xlsxPicture{
RID: "rId" + strconv.Itoa(rID),
RID: relationship("rId" + strconv.Itoa(rID)),
}
}

Expand Down Expand Up @@ -400,7 +400,7 @@ func (f *File) addContentTypePart(index int, contentType string) {
// getSheetRelationshipsTargetByID provides a function to get Target attribute
// value in xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name and
// relationship index.
func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
func (f *File) getSheetRelationshipsTargetByID(sheet string, rID relationship) string {
name, ok := f.sheetMap[trimSheetName(sheet)]
if !ok {
name = strings.ToLower(sheet) + ".xml"
Expand All @@ -411,7 +411,7 @@ func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
sheetRels = &xlsxRelationships{}
}
for _, v := range sheetRels.Relationships {
if v.ID == rID {
if v.ID == string(rID) {
return v.Target
}
}
Expand Down Expand Up @@ -544,11 +544,14 @@ func (f *File) getDrawingRelationships(rels, rID string) *xlsxRelationship {

// drawingsWriter provides a function to save xl/drawings/drawing%d.xml after
// serialize structure.
func (f *File) drawingsWriter() {
func (f *File) drawingsWriter(zw *zip.Writer) error {
for path, d := range f.Drawings {
if d != nil {
v, _ := xml.Marshal(d)
f.saveFileList(path, v)
if d == nil {
continue
}
if err := writeXMLToZipWriter(zw, path, d); err != nil {
return err
}
}
return nil
}
2 changes: 1 addition & 1 deletion pivotTable.go
Expand Up @@ -445,7 +445,7 @@ func (f *File) addWorkbookPivotCache(RID int) int {
cacheID++
wb.PivotCaches.PivotCache = append(wb.PivotCaches.PivotCache, xlsxPivotCache{
CacheID: cacheID,
RID: fmt.Sprintf("rId%d", RID),
RID: relationship(fmt.Sprintf("rId%d", RID)),
})
return cacheID
}