diff --git a/.gitignore b/.gitignore
index bafda042..a3fcff22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
~$*.xlsx
test/Test*.xlsx
*.out
-*.test
\ No newline at end of file
+*.test
+.idea
diff --git a/calcchain.go b/calcchain.go
index b4cadefe..413f470e 100644
--- a/calcchain.go
+++ b/calcchain.go
@@ -9,16 +9,26 @@
package excelize
-import "encoding/xml"
+import (
+ "bytes"
+ "encoding/xml"
+ "io"
+ "log"
+)
// calcChainReader provides a function to get the pointer to the structure
// after deserialization of xl/calcChain.xml.
func (f *File) calcChainReader() *xlsxCalcChain {
+ var err error
+
if f.CalcChain == nil {
- var c xlsxCalcChain
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/calcChain.xml")), &c)
- f.CalcChain = &c
+ f.CalcChain = new(xlsxCalcChain)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("xl/calcChain.xml")))).
+ Decode(f.CalcChain); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
}
+
return f.CalcChain
}
diff --git a/chart.go b/chart.go
index 7d40405a..aaa7cd68 100644
--- a/chart.go
+++ b/chart.go
@@ -10,9 +10,12 @@
package excelize
import (
+ "bytes"
"encoding/json"
"encoding/xml"
"errors"
+ "io"
+ "log"
"strconv"
"strings"
)
@@ -1735,14 +1738,21 @@ func (f *File) drawPlotAreaTxPr() *cTxPr {
// deserialization, two different structures: decodeWsDr and encodeWsDr are
// defined.
func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
+ var (
+ err error
+ ok bool
+ )
+
if f.Drawings[path] == nil {
content := xlsxWsDr{}
content.A = NameSpaceDrawingML
content.Xdr = NameSpaceDrawingMLSpreadSheet
- _, ok := f.XLSX[path]
- if ok { // Append Model
+ if _, ok = f.XLSX[path]; ok { // Append Model
decodeWsDr := decodeWsDr{}
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(path)), &decodeWsDr)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(path)))).
+ Decode(&decodeWsDr); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
content.R = decodeWsDr.R
for _, v := range decodeWsDr.OneCellAnchor {
content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
diff --git a/comment.go b/comment.go
index 7f3b10db..99630c93 100644
--- a/comment.go
+++ b/comment.go
@@ -10,9 +10,12 @@
package excelize
import (
+ "bytes"
"encoding/json"
"encoding/xml"
"fmt"
+ "io"
+ "log"
"strconv"
"strings"
)
@@ -303,12 +306,16 @@ func (f *File) countComments() int {
// 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 {
+ var err error
+
if f.DecodeVMLDrawing[path] == nil {
c, ok := f.XLSX[path]
if ok {
- d := decodeVmlDrawing{}
- _ = xml.Unmarshal(namespaceStrictToTransitional(c), &d)
- f.DecodeVMLDrawing[path] = &d
+ f.DecodeVMLDrawing[path] = new(decodeVmlDrawing)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(c))).
+ Decode(f.DecodeVMLDrawing[path]); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
}
}
return f.DecodeVMLDrawing[path]
@@ -328,12 +335,16 @@ func (f *File) vmlDrawingWriter() {
// 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 {
+ var err error
+
if f.Comments[path] == nil {
content, ok := f.XLSX[path]
if ok {
- c := xlsxComments{}
- _ = xml.Unmarshal(namespaceStrictToTransitional(content), &c)
- f.Comments[path] = &c
+ f.Comments[path] = new(xlsxComments)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(content))).
+ Decode(f.Comments[path]); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
}
}
return f.Comments[path]
diff --git a/docProps.go b/docProps.go
index 166512f7..884eb631 100644
--- a/docProps.go
+++ b/docProps.go
@@ -10,7 +10,10 @@
package excelize
import (
+ "bytes"
"encoding/xml"
+ "fmt"
+ "io"
"reflect"
)
@@ -65,13 +68,23 @@ import (
// Version: "1.0.0",
// })
//
-func (f *File) SetDocProps(docProperties *DocProperties) error {
- core := decodeCoreProperties{}
- err := xml.Unmarshal(namespaceStrictToTransitional(f.readXML("docProps/core.xml")), &core)
- if err != nil {
- return err
+func (f *File) SetDocProps(docProperties *DocProperties) (err error) {
+ var (
+ core *decodeCoreProperties
+ newProps *xlsxCoreProperties
+ fields []string
+ output []byte
+ immutable, mutable reflect.Value
+ field, val string
+ )
+
+ core = new(decodeCoreProperties)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("docProps/core.xml")))).
+ Decode(core); err != nil && err != io.EOF {
+ err = fmt.Errorf("xml decode error: %s", err)
+ return
}
- newProps := xlsxCoreProperties{
+ newProps, err = &xlsxCoreProperties{
Dc: NameSpaceDublinCore,
Dcterms: NameSpaceDublinCoreTerms,
Dcmitype: NameSpaceDublinCoreMetadataIntiative,
@@ -88,18 +101,16 @@ func (f *File) SetDocProps(docProperties *DocProperties) error {
ContentStatus: core.ContentStatus,
Category: core.Category,
Version: core.Version,
+ }, nil
+ newProps.Created.Text, newProps.Created.Type, newProps.Modified.Text, newProps.Modified.Type =
+ core.Created.Text, core.Created.Type, core.Modified.Text, core.Modified.Type
+ fields = []string{
+ "Category", "ContentStatus", "Creator", "Description", "Identifier", "Keywords",
+ "LastModifiedBy", "Revision", "Subject", "Title", "Language", "Version",
}
- newProps.Created.Text = core.Created.Text
- newProps.Created.Type = core.Created.Type
- newProps.Modified.Text = core.Modified.Text
- newProps.Modified.Type = core.Modified.Type
-
- fields := []string{"Category", "ContentStatus", "Creator", "Description", "Identifier", "Keywords", "LastModifiedBy", "Revision", "Subject", "Title", "Language", "Version"}
- immutable := reflect.ValueOf(*docProperties)
- mutable := reflect.ValueOf(&newProps).Elem()
- for _, field := range fields {
- val := immutable.FieldByName(field).String()
- if val != "" {
+ immutable, mutable = reflect.ValueOf(*docProperties), reflect.ValueOf(newProps).Elem()
+ for _, field = range fields {
+ if val = immutable.FieldByName(field).String(); val != "" {
mutable.FieldByName(field).SetString(val)
}
}
@@ -109,19 +120,22 @@ func (f *File) SetDocProps(docProperties *DocProperties) error {
if docProperties.Modified != "" {
newProps.Modified.Text = docProperties.Modified
}
- output, err := xml.Marshal(&newProps)
+ output, err = xml.Marshal(newProps)
f.saveFileList("docProps/core.xml", output)
- return err
+
+ return
}
// GetDocProps provides a function to get document core properties.
-func (f *File) GetDocProps() (*DocProperties, error) {
- core := decodeCoreProperties{}
- err := xml.Unmarshal(namespaceStrictToTransitional(f.readXML("docProps/core.xml")), &core)
- if err != nil {
- return nil, err
+func (f *File) GetDocProps() (ret *DocProperties, err error) {
+ var core = new(decodeCoreProperties)
+
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("docProps/core.xml")))).
+ Decode(core); err != nil && err != io.EOF {
+ err = fmt.Errorf("xml decode error: %s", err)
+ return
}
- return &DocProperties{
+ ret, err = &DocProperties{
Category: core.Category,
ContentStatus: core.ContentStatus,
Created: core.Created.Text,
@@ -137,4 +151,6 @@ func (f *File) GetDocProps() (*DocProperties, error) {
Language: core.Language,
Version: core.Version,
}, nil
+
+ return
}
diff --git a/docProps_test.go b/docProps_test.go
index 671d998c..df3122b1 100644
--- a/docProps_test.go
+++ b/docProps_test.go
@@ -39,7 +39,7 @@ func TestSetDocProps(t *testing.T) {
}))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetDocProps.xlsx")))
f.XLSX["docProps/core.xml"] = nil
- assert.EqualError(t, f.SetDocProps(&DocProperties{}), "EOF")
+ assert.NoError(t, f.SetDocProps(&DocProperties{}))
}
func TestGetDocProps(t *testing.T) {
@@ -52,5 +52,5 @@ func TestGetDocProps(t *testing.T) {
assert.Equal(t, props.Creator, "Microsoft Office User")
f.XLSX["docProps/core.xml"] = nil
_, err = f.GetDocProps()
- assert.EqualError(t, err, "EOF")
+ assert.NoError(t, err)
}
diff --git a/excelize.go b/excelize.go
index 4d46b94e..fe227b95 100644
--- a/excelize.go
+++ b/excelize.go
@@ -22,6 +22,8 @@ import (
"path"
"strconv"
"strings"
+
+ "golang.org/x/net/html/charset"
)
// File define a populated XLSX file struct.
@@ -43,8 +45,11 @@ type File struct {
WorkBook *xlsxWorkbook
Relationships map[string]*xlsxRelationships
XLSX map[string][]byte
+ CharsetReader charsetTranscoderFn
}
+type charsetTranscoderFn func(charset string, input io.Reader) (rdr io.Reader, err error)
+
// OpenFile take the name of an XLSX file and returns a populated XLSX file
// struct for it.
func OpenFile(filename string) (*File, error) {
@@ -61,6 +66,21 @@ func OpenFile(filename string) (*File, error) {
return f, nil
}
+// object builder
+func newFile() *File {
+ return &File{
+ checked: make(map[string]bool),
+ sheetMap: make(map[string]string),
+ Comments: make(map[string]*xlsxComments),
+ Drawings: make(map[string]*xlsxWsDr),
+ Sheet: make(map[string]*xlsxWorksheet),
+ DecodeVMLDrawing: make(map[string]*decodeVmlDrawing),
+ VMLDrawing: make(map[string]*vmlDrawing),
+ Relationships: make(map[string]*xlsxRelationships),
+ CharsetReader: charset.NewReaderLabel,
+ }
+}
+
// OpenReader take an io.Reader and return a populated XLSX file.
func OpenReader(r io.Reader) (*File, error) {
b, err := ioutil.ReadAll(r)
@@ -88,17 +108,8 @@ func OpenReader(r io.Reader) (*File, error) {
if err != nil {
return nil, err
}
- f := &File{
- checked: make(map[string]bool),
- Comments: make(map[string]*xlsxComments),
- Drawings: make(map[string]*xlsxWsDr),
- Sheet: make(map[string]*xlsxWorksheet),
- SheetCount: sheetCount,
- DecodeVMLDrawing: make(map[string]*decodeVmlDrawing),
- VMLDrawing: make(map[string]*vmlDrawing),
- Relationships: make(map[string]*xlsxRelationships),
- XLSX: file,
- }
+ f := newFile()
+ f.SheetCount, f.XLSX = sheetCount, file
f.CalcChain = f.calcChainReader()
f.sheetMap = f.getSheetMap()
f.Styles = f.stylesReader()
@@ -106,6 +117,16 @@ func OpenReader(r io.Reader) (*File, error) {
return f, nil
}
+// CharsetTranscoder Set user defined codepage transcoder function for open XLSX from non UTF-8 encoding
+func (f *File) CharsetTranscoder(fn charsetTranscoderFn) *File { f.CharsetReader = fn; return f }
+
+// Creates new XML decoder with charset reader
+func (f *File) xmlNewDecoder(rdr io.Reader) (ret *xml.Decoder) {
+ ret = xml.NewDecoder(rdr)
+ ret.CharsetReader = f.CharsetReader
+ return
+}
+
// setDefaultTimeStyle provides a function to set default numbers format for
// time.Time type cell value by given worksheet name, cell coordinates and
// number format code.
@@ -123,26 +144,38 @@ func (f *File) setDefaultTimeStyle(sheet, axis string, format int) error {
// workSheetReader provides a function to get the pointer to the structure
// after deserialization by given worksheet name.
-func (f *File) workSheetReader(sheet string) (*xlsxWorksheet, error) {
- name, ok := f.sheetMap[trimSheetName(sheet)]
- if !ok {
- return nil, fmt.Errorf("sheet %s is not exist", sheet)
+func (f *File) workSheetReader(sheet string) (xlsx *xlsxWorksheet, err error) {
+ var (
+ name string
+ ok bool
+ )
+
+ if name, ok = f.sheetMap[trimSheetName(sheet)]; !ok {
+ err = fmt.Errorf("sheet %s is not exist", sheet)
+ return
}
- if f.Sheet[name] == nil {
- var xlsx xlsxWorksheet
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(name)), &xlsx)
+ if xlsx = f.Sheet[name]; f.Sheet[name] == nil {
+ xlsx = new(xlsxWorksheet)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(name)))).
+ Decode(xlsx); err != nil && err != io.EOF {
+ err = fmt.Errorf("xml decode error: %s", err)
+ return
+ }
+ err = nil
if f.checked == nil {
f.checked = make(map[string]bool)
}
- ok := f.checked[name]
- if !ok {
- checkSheet(&xlsx)
- checkRow(&xlsx)
+ if ok = f.checked[name]; !ok {
+ checkSheet(xlsx)
+ if err = checkRow(xlsx); err != nil {
+ return
+ }
f.checked[name] = true
}
- f.Sheet[name] = &xlsx
+ f.Sheet[name] = xlsx
}
- return f.Sheet[name], nil
+
+ return
}
// checkSheet provides a function to fill each row element and make that is
diff --git a/file.go b/file.go
index 2e0d27be..d8f10fac 100644
--- a/file.go
+++ b/file.go
@@ -33,12 +33,8 @@ func NewFile() *File {
file["xl/styles.xml"] = []byte(XMLHeader + templateStyles)
file["xl/workbook.xml"] = []byte(XMLHeader + templateWorkbook)
file["[Content_Types].xml"] = []byte(XMLHeader + templateContentTypes)
- f := &File{
- sheetMap: make(map[string]string),
- Sheet: make(map[string]*xlsxWorksheet),
- SheetCount: 1,
- XLSX: file,
- }
+ f := newFile()
+ f.SheetCount, f.XLSX = 1, file
f.CalcChain = f.calcChainReader()
f.Comments = make(map[string]*xlsxComments)
f.ContentTypes = f.contentTypesReader()
diff --git a/go.mod b/go.mod
index 892f3066..420c64eb 100644
--- a/go.mod
+++ b/go.mod
@@ -7,4 +7,6 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/stretchr/testify v1.3.0
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a
+ golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
+ golang.org/x/text v0.3.2 // indirect
)
diff --git a/go.sum b/go.sum
index 2d29d33a..54492ac2 100644
--- a/go.sum
+++ b/go.sum
@@ -9,6 +9,14 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R5r1BuKtfYqRqF0h/Cbh0=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/picture.go b/picture.go
index ff408633..09c19559 100644
--- a/picture.go
+++ b/picture.go
@@ -14,7 +14,9 @@ import (
"encoding/json"
"encoding/xml"
"errors"
+ "fmt"
"image"
+ "io"
"io/ioutil"
"os"
"path"
@@ -471,39 +473,55 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
// getPicture provides a function to get picture base name and raw content
// embed in XLSX by given coordinates and drawing relationships.
-func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string) (string, []byte, error) {
- wsDr, _ := f.drawingParser(drawingXML)
- for _, anchor := range wsDr.TwoCellAnchor {
+func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string) (ret string, buf []byte, err error) {
+ var (
+ wsDr *xlsxWsDr
+ ok bool
+ anchor *xdrCellAnchor
+ deWsDr *decodeWsDr
+ xxRelationship *xlsxRelationship
+ deTwoCellAnchor *decodeTwoCellAnchor
+ )
+
+ wsDr, _ = f.drawingParser(drawingXML)
+ for _, anchor = range wsDr.TwoCellAnchor {
if anchor.From != nil && anchor.Pic != nil {
if anchor.From.Col == col && anchor.From.Row == row {
- xlsxRelationship := f.getDrawingRelationships(drawingRelationships,
+ xxRelationship = f.getDrawingRelationships(drawingRelationships,
anchor.Pic.BlipFill.Blip.Embed)
- _, ok := supportImageTypes[filepath.Ext(xlsxRelationship.Target)]
- if ok {
- return filepath.Base(xlsxRelationship.Target),
- []byte(f.XLSX[strings.Replace(xlsxRelationship.Target,
- "..", "xl", -1)]), nil
+ if _, ok = supportImageTypes[filepath.Ext(xxRelationship.Target)]; ok {
+ ret, buf = filepath.Base(xxRelationship.Target), []byte(f.XLSX[strings.Replace(xxRelationship.Target, "..", "xl", -1)])
+ return
+ }
+ }
+ }
+ }
+ 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)
+ return
+ }
+ err = nil
+ for _, anchor := range deWsDr.TwoCellAnchor {
+ deTwoCellAnchor = new(decodeTwoCellAnchor)
+ if err = f.xmlNewDecoder(bytes.NewReader([]byte("" + anchor.Content + ""))).
+ Decode(deTwoCellAnchor); err != nil && err != io.EOF {
+ err = fmt.Errorf("xml decode error: %s", err)
+ return
+ }
+ if err = nil; deTwoCellAnchor.From != nil && deTwoCellAnchor.Pic != nil {
+ if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {
+ xxRelationship = f.getDrawingRelationships(drawingRelationships, deTwoCellAnchor.Pic.BlipFill.Blip.Embed)
+ if _, ok = supportImageTypes[filepath.Ext(xxRelationship.Target)]; ok {
+ ret, buf = filepath.Base(xxRelationship.Target), []byte(f.XLSX[strings.Replace(xxRelationship.Target, "..", "xl", -1)])
+ return
}
}
}
}
- decodeWsDr := decodeWsDr{}
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr)
- for _, anchor := range decodeWsDr.TwoCellAnchor {
- decodeTwoCellAnchor := decodeTwoCellAnchor{}
- _ = xml.Unmarshal([]byte(""+anchor.Content+""), &decodeTwoCellAnchor)
- if decodeTwoCellAnchor.From != nil && decodeTwoCellAnchor.Pic != nil {
- if decodeTwoCellAnchor.From.Col == col && decodeTwoCellAnchor.From.Row == row {
- xlsxRelationship := f.getDrawingRelationships(drawingRelationships, decodeTwoCellAnchor.Pic.BlipFill.Blip.Embed)
- _, ok := supportImageTypes[filepath.Ext(xlsxRelationship.Target)]
- if ok {
- return filepath.Base(xlsxRelationship.Target), []byte(f.XLSX[strings.Replace(xlsxRelationship.Target, "..", "xl", -1)]), nil
- }
- }
- }
- }
- return "", nil, nil
+ return
}
// getDrawingRelationships provides a function to get drawing relationships
diff --git a/rows.go b/rows.go
index 37964411..e12e349a 100644
--- a/rows.go
+++ b/rows.go
@@ -10,9 +10,11 @@
package excelize
import (
- "encoding/xml"
+ "bytes"
"errors"
"fmt"
+ "io"
+ "log"
"math"
"strconv"
)
@@ -187,15 +189,21 @@ func (f *File) GetRowHeight(sheet string, row int) (float64, error) {
// sharedStringsReader provides a function to get the pointer to the structure
// after deserialization of xl/sharedStrings.xml.
func (f *File) sharedStringsReader() *xlsxSST {
+ var err error
+
if f.SharedStrings == nil {
var sharedStrings xlsxSST
ss := f.readXML("xl/sharedStrings.xml")
if len(ss) == 0 {
ss = f.readXML("xl/SharedStrings.xml")
}
- _ = xml.Unmarshal(namespaceStrictToTransitional(ss), &sharedStrings)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(ss))).
+ Decode(&sharedStrings); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
f.SharedStrings = &sharedStrings
}
+
return f.SharedStrings
}
diff --git a/sheet.go b/sheet.go
index 951baf92..42fd6b33 100644
--- a/sheet.go
+++ b/sheet.go
@@ -15,7 +15,9 @@ import (
"encoding/xml"
"errors"
"fmt"
+ "io"
"io/ioutil"
+ "log"
"os"
"path"
"reflect"
@@ -61,11 +63,16 @@ func (f *File) NewSheet(name string) int {
// contentTypesReader provides a function to get the pointer to the
// [Content_Types].xml structure after deserialization.
func (f *File) contentTypesReader() *xlsxTypes {
+ var err error
+
if f.ContentTypes == nil {
- var content xlsxTypes
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("[Content_Types].xml")), &content)
- f.ContentTypes = &content
+ f.ContentTypes = new(xlsxTypes)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("[Content_Types].xml")))).
+ Decode(f.ContentTypes); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
}
+
return f.ContentTypes
}
@@ -81,11 +88,16 @@ func (f *File) contentTypesWriter() {
// workbookReader provides a function to get the pointer to the xl/workbook.xml
// structure after deserialization.
func (f *File) workbookReader() *xlsxWorkbook {
+ var err error
+
if f.WorkBook == nil {
- var content xlsxWorkbook
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/workbook.xml")), &content)
- f.WorkBook = &content
+ f.WorkBook = new(xlsxWorkbook)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("xl/workbook.xml")))).
+ Decode(f.WorkBook); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
}
+
return f.WorkBook
}
@@ -679,42 +691,51 @@ func (f *File) GetSheetVisible(name string) bool {
//
// result, err := f.SearchSheet("Sheet1", "[0-9]", true)
//
-func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
+func (f *File) SearchSheet(sheet, value string, reg ...bool) (result []string, err error) {
var (
- regSearch bool
- result []string
+ xlsx *xlsxWorksheet
+ regSearch, r, ok bool
+ name string
+ output []byte
)
- for _, r := range reg {
+
+ for _, r = range reg {
regSearch = r
}
- xlsx, err := f.workSheetReader(sheet)
- if err != nil {
- return result, err
+ if xlsx, err = f.workSheetReader(sheet); err != nil {
+ return
}
- name, ok := f.sheetMap[trimSheetName(sheet)]
- if !ok {
- return result, nil
+ if name, ok = f.sheetMap[trimSheetName(sheet)]; !ok {
+ return
}
if xlsx != nil {
- output, _ := xml.Marshal(f.Sheet[name])
+ if output, err = xml.Marshal(f.Sheet[name]); err != nil {
+ return
+ }
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output))
}
+
return f.searchSheet(name, value, regSearch)
}
// searchSheet provides a function to get coordinates by given worksheet name,
// cell value, and regular expression.
-func (f *File) searchSheet(name, value string, regSearch bool) ([]string, error) {
+func (f *File) searchSheet(name, value string, regSearch bool) (result []string, err error) {
var (
+ d *xlsxSST
+ decoder *xml.Decoder
inElement string
- result []string
r xlsxRow
+ token xml.Token
)
- d := f.sharedStringsReader()
- decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name)))
+
+ d = f.sharedStringsReader()
+ decoder = f.xmlNewDecoder(bytes.NewReader(f.readXML(name)))
for {
- token, _ := decoder.Token()
- if token == nil {
+ if token, err = decoder.Token(); err != nil || token == nil {
+ if err == io.EOF {
+ err = nil
+ }
break
}
switch startElement := token.(type) {
@@ -750,7 +771,8 @@ func (f *File) searchSheet(name, value string, regSearch bool) ([]string, error)
default:
}
}
- return result, nil
+
+ return
}
// SetHeaderFooter provides a function to set headers and footers by given
@@ -1360,14 +1382,20 @@ func (f *File) UngroupSheets() error {
// relsReader provides a function to get the pointer to the structure
// after deserialization of xl/worksheets/_rels/sheet%d.xml.rels.
func (f *File) relsReader(path string) *xlsxRelationships {
+ var err error
+
if f.Relationships[path] == nil {
_, ok := f.XLSX[path]
if ok {
c := xlsxRelationships{}
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(path)), &c)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(path)))).
+ Decode(&c); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
f.Relationships[path] = &c
}
}
+
return f.Relationships[path]
}
diff --git a/sparkline.go b/sparkline.go
index b09dbf40..9ad50877 100644
--- a/sparkline.go
+++ b/sparkline.go
@@ -10,8 +10,10 @@
package excelize
import (
+ "bytes"
"encoding/xml"
"errors"
+ "io"
"strings"
)
@@ -386,23 +388,40 @@ func (f *File) addSparklineGroupByStyle(ID int) *xlsxX14SparklineGroup {
// ColorAxis | An RGB Color is specified as RRGGBB
// Axis | Show sparkline axis
//
-func (f *File) AddSparkline(sheet string, opt *SparklineOption) error {
+func (f *File) AddSparkline(sheet string, opt *SparklineOption) (err error) {
+ var (
+ ws *xlsxWorksheet
+ sparkType string
+ sparkTypes map[string]string
+ specifiedSparkTypes string
+ ok bool
+ group *xlsxX14SparklineGroup
+ groups *xlsxX14SparklineGroups
+ decodeExtLst *decodeWorksheetExt
+ idx int
+ ext *xlsxWorksheetExt
+ decodeSparklineGroups *decodeX14SparklineGroups
+ sparklineGroupBytes []byte
+ sparklineGroupsBytes []byte
+ extLst string
+ extLstBytes, extBytes []byte
+ )
+
// parameter validation
- ws, err := f.parseFormatAddSparklineSet(sheet, opt)
- if err != nil {
- return err
+ if ws, err = f.parseFormatAddSparklineSet(sheet, opt); err != nil {
+ return
}
// Handle the sparkline type
- sparkType := "line"
- sparkTypes := map[string]string{"line": "line", "column": "column", "win_loss": "stacked"}
+ sparkType = "line"
+ sparkTypes = map[string]string{"line": "line", "column": "column", "win_loss": "stacked"}
if opt.Type != "" {
- specifiedSparkTypes, ok := sparkTypes[opt.Type]
- if !ok {
- return errors.New("parameter 'Type' must be 'line', 'column' or 'win_loss'")
+ if specifiedSparkTypes, ok = sparkTypes[opt.Type]; !ok {
+ err = errors.New("parameter 'Type' must be 'line', 'column' or 'win_loss'")
+ return
}
sparkType = specifiedSparkTypes
}
- group := f.addSparklineGroupByStyle(opt.Style)
+ group = f.addSparklineGroupByStyle(opt.Style)
group.Type = sparkType
group.ColorAxis = &xlsxColor{RGB: "FF000000"}
group.DisplayEmptyCellsAs = "gap"
@@ -423,43 +442,57 @@ func (f *File) AddSparkline(sheet string, opt *SparklineOption) error {
}
f.addSparkline(opt, group)
if ws.ExtLst.Ext != "" { // append mode ext
- decodeExtLst := decodeWorksheetExt{}
- err = xml.Unmarshal([]byte(""+ws.ExtLst.Ext+""), &decodeExtLst)
- if err != nil {
- return err
+ decodeExtLst = new(decodeWorksheetExt)
+ if err = f.xmlNewDecoder(bytes.NewReader([]byte("" + ws.ExtLst.Ext + ""))).
+ Decode(decodeExtLst); err != nil && err != io.EOF {
+ return
}
- for idx, ext := range decodeExtLst.Ext {
+ for idx, ext = range decodeExtLst.Ext {
if ext.URI == ExtURISparklineGroups {
- decodeSparklineGroups := decodeX14SparklineGroups{}
- _ = xml.Unmarshal([]byte(ext.Content), &decodeSparklineGroups)
- sparklineGroupBytes, _ := xml.Marshal(group)
- groups := xlsxX14SparklineGroups{
+ decodeSparklineGroups = new(decodeX14SparklineGroups)
+ if err = f.xmlNewDecoder(bytes.NewReader([]byte(ext.Content))).
+ Decode(decodeSparklineGroups); err != nil && err != io.EOF {
+ return
+ }
+ if sparklineGroupBytes, err = xml.Marshal(group); err != nil {
+ return
+ }
+ groups = &xlsxX14SparklineGroups{
XMLNSXM: NameSpaceSpreadSheetExcel2006Main,
Content: decodeSparklineGroups.Content + string(sparklineGroupBytes),
}
- sparklineGroupsBytes, _ := xml.Marshal(groups)
+ if sparklineGroupsBytes, err = xml.Marshal(groups); err != nil {
+ return
+ }
decodeExtLst.Ext[idx].Content = string(sparklineGroupsBytes)
}
}
- extLstBytes, _ := xml.Marshal(decodeExtLst)
- extLst := string(extLstBytes)
+ if extLstBytes, err = xml.Marshal(decodeExtLst); err != nil {
+ return
+ }
+ extLst = string(extLstBytes)
ws.ExtLst = &xlsxExtLst{
Ext: strings.TrimSuffix(strings.TrimPrefix(extLst, ""), ""),
}
} else {
- groups := xlsxX14SparklineGroups{
+ groups = &xlsxX14SparklineGroups{
XMLNSXM: NameSpaceSpreadSheetExcel2006Main,
SparklineGroups: []*xlsxX14SparklineGroup{group},
}
- sparklineGroupsBytes, _ := xml.Marshal(groups)
- extLst := xlsxWorksheetExt{
+ if sparklineGroupsBytes, err = xml.Marshal(groups); err != nil {
+ return
+ }
+ ext = &xlsxWorksheetExt{
URI: ExtURISparklineGroups,
Content: string(sparklineGroupsBytes),
}
- extBytes, _ := xml.Marshal(extLst)
+ if extBytes, err = xml.Marshal(ext); err != nil {
+ return
+ }
ws.ExtLst.Ext = string(extBytes)
}
- return nil
+
+ return
}
// parseFormatAddSparklineSet provides a function to validate sparkline
diff --git a/styles.go b/styles.go
index 3244be24..fa0507eb 100644
--- a/styles.go
+++ b/styles.go
@@ -10,9 +10,12 @@
package excelize
import (
+ "bytes"
"encoding/json"
"encoding/xml"
"fmt"
+ "io"
+ "log"
"math"
"strconv"
"strings"
@@ -997,11 +1000,16 @@ func is12HourTime(format string) bool {
// stylesReader provides a function to get the pointer to the structure after
// deserialization of xl/styles.xml.
func (f *File) stylesReader() *xlsxStyleSheet {
+ var err error
+
if f.Styles == nil {
- var styleSheet xlsxStyleSheet
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/styles.xml")), &styleSheet)
- f.Styles = &styleSheet
+ f.Styles = new(xlsxStyleSheet)
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("xl/styles.xml")))).
+ Decode(f.Styles); err != nil && err != io.EOF {
+ log.Printf("xml decode error: %s", err)
+ }
}
+
return f.Styles
}
@@ -2803,8 +2811,16 @@ func getPaletteColor(color string) string {
// themeReader provides a function to get the pointer to the xl/theme/theme1.xml
// structure after deserialization.
func (f *File) themeReader() *xlsxTheme {
- var theme xlsxTheme
- _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/theme/theme1.xml")), &theme)
+ var (
+ err error
+ theme xlsxTheme
+ )
+
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("xl/theme/theme1.xml")))).
+ Decode(&theme); err != nil && err != io.EOF {
+ log.Printf("xml decoder error: %s", err)
+ }
+
return &theme
}