Remove internal error log print, throw XML deserialize error
This commit is contained in:
parent
bd5dd17673
commit
ac564afa56
|
@ -54,7 +54,10 @@ func (f *File) deleteCalcChain(index int, cell string) error {
|
|||
if len(calc.C) == 0 {
|
||||
f.CalcChain = nil
|
||||
f.Pkg.Delete(defaultXMLPathCalcChain)
|
||||
content := f.contentTypesReader()
|
||||
content, err := f.contentTypesReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content.Lock()
|
||||
defer content.Unlock()
|
||||
for k, v := range content.Overrides {
|
||||
|
|
|
@ -33,7 +33,14 @@ func TestDeleteCalcChain(t *testing.T) {
|
|||
|
||||
formulaType, ref := STCellFormulaTypeShared, "C1:C5"
|
||||
assert.NoError(t, f.SetCellFormula("Sheet1", "C1", "=A1+B1", FormulaOpts{Ref: &ref, Type: &formulaType}))
|
||||
|
||||
// Test delete calculation chain with unsupported charset calculation chain.
|
||||
f.CalcChain = nil
|
||||
f.Pkg.Store(defaultXMLPathCalcChain, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.SetCellValue("Sheet1", "C1", true), "XML syntax error on line 1: invalid UTF-8")
|
||||
|
||||
// Test delete calculation chain with unsupported charset content types.
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.deleteCalcChain(1, "A1"), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
|
13
cell.go
13
cell.go
|
@ -241,11 +241,14 @@ func (f *File) setCellTimeFunc(sheet, cell string, value time.Time) error {
|
|||
ws.Lock()
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
ws.Unlock()
|
||||
date1904, wb := false, f.workbookReader()
|
||||
var date1904, isNum bool
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wb != nil && wb.WorkbookPr != nil {
|
||||
date1904 = wb.WorkbookPr.Date1904
|
||||
}
|
||||
var isNum bool
|
||||
if isNum, err = c.setCellTime(value, date1904); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1320,7 +1323,11 @@ func (f *File) formattedValue(s int, v string, raw bool) (string, error) {
|
|||
if styleSheet.CellXfs.Xf[s].NumFmtID != nil {
|
||||
numFmtID = *styleSheet.CellXfs.Xf[s].NumFmtID
|
||||
}
|
||||
date1904, wb := false, f.workbookReader()
|
||||
date1904 := false
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return v, err
|
||||
}
|
||||
if wb != nil && wb.WorkbookPr != nil {
|
||||
date1904 = wb.WorkbookPr.Date1904
|
||||
}
|
||||
|
|
16
cell_test.go
16
cell_test.go
|
@ -173,7 +173,7 @@ func TestSetCellValue(t *testing.T) {
|
|||
f := NewFile()
|
||||
assert.EqualError(t, f.SetCellValue("Sheet1", "A", time.Now().UTC()), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
assert.EqualError(t, f.SetCellValue("Sheet1", "A", time.Duration(1e13)), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
// Test set cell value with column and row style inherit
|
||||
// Test set cell value with column and row style inherit.
|
||||
style1, err := f.NewStyle(&Style{NumFmt: 2})
|
||||
assert.NoError(t, err)
|
||||
style2, err := f.NewStyle(&Style{NumFmt: 9})
|
||||
|
@ -189,10 +189,14 @@ func TestSetCellValue(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, "0.50", B2)
|
||||
|
||||
// Test set cell value with unsupported charset shared strings table
|
||||
// Test set cell value with unsupported charset shared strings table.
|
||||
f.SharedStrings = nil
|
||||
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.SetCellValue("Sheet1", "A1", "A1"), "XML syntax error on line 1: invalid UTF-8")
|
||||
// Test set cell value with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.SetCellValue("Sheet1", "A1", time.Now().UTC()), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestSetCellValues(t *testing.T) {
|
||||
|
@ -204,7 +208,7 @@ func TestSetCellValues(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
assert.Equal(t, v, "12/31/10 00:00")
|
||||
|
||||
// Test date value lower than min date supported by Excel
|
||||
// Test date value lower than min date supported by Excel.
|
||||
err = f.SetCellValue("Sheet1", "A1", time.Date(1600, time.December, 31, 0, 0, 0, 0, time.UTC))
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
@ -782,6 +786,12 @@ func TestFormattedValue(t *testing.T) {
|
|||
assert.Equal(t, "0_0", fn("0_0", "", false))
|
||||
}
|
||||
|
||||
// Test format value with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
_, err = f.formattedValue(1, "43528", false)
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
|
||||
// Test format value with unsupported charset style sheet.
|
||||
f.Styles = nil
|
||||
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
||||
|
|
20
chart.go
20
chart.go
|
@ -927,8 +927,10 @@ func (f *File) AddChart(sheet, cell, opts string, combo ...string) error {
|
|||
return err
|
||||
}
|
||||
f.addChart(options, comboCharts)
|
||||
f.addContentTypePart(chartID, "chart")
|
||||
f.addContentTypePart(drawingID, "drawings")
|
||||
if err = f.addContentTypePart(chartID, "chart"); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = f.addContentTypePart(drawingID, "drawings")
|
||||
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||
return err
|
||||
}
|
||||
|
@ -952,7 +954,7 @@ func (f *File) AddChartSheet(sheet, opts string, combo ...string) error {
|
|||
},
|
||||
}
|
||||
f.SheetCount++
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
sheetID := 0
|
||||
for _, v := range wb.Sheets.Sheet {
|
||||
if v.SheetID > sheetID {
|
||||
|
@ -969,11 +971,15 @@ func (f *File) AddChartSheet(sheet, opts string, combo ...string) error {
|
|||
f.prepareChartSheetDrawing(&cs, drawingID, sheet)
|
||||
drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
|
||||
drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
|
||||
f.addSheetDrawingChart(drawingXML, drawingRID, &options.Format)
|
||||
if err = f.addSheetDrawingChart(drawingXML, drawingRID, &options.Format); err != nil {
|
||||
return err
|
||||
}
|
||||
f.addChart(options, comboCharts)
|
||||
f.addContentTypePart(chartID, "chart")
|
||||
f.addContentTypePart(sheetID, "chartsheet")
|
||||
f.addContentTypePart(drawingID, "drawings")
|
||||
if err = f.addContentTypePart(chartID, "chart"); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = f.addContentTypePart(sheetID, "chartsheet")
|
||||
_ = f.addContentTypePart(drawingID, "drawings")
|
||||
// Update workbook.xml.rels
|
||||
rID := f.addRels(f.getWorkbookRelsPath(), SourceRelationshipChartsheet, fmt.Sprintf("/xl/chartsheets/sheet%d.xml", sheetID), "")
|
||||
// Update workbook.xml
|
||||
|
|
|
@ -226,6 +226,11 @@ func TestAddChart(t *testing.T) {
|
|||
// Test add combo chart with unsupported chart type
|
||||
assert.EqualError(t, f.AddChart("Sheet2", "BD64", `{"type":"barOfPie","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$A$30:$D$37","values":"Sheet1!$B$30:$B$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Bar of Pie Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"major_grid_lines":true},"y_axis":{"major_grid_lines":true}}`, `{"type":"unknown","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$A$30:$D$37","values":"Sheet1!$B$30:$B$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Bar of Pie Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"major_grid_lines":true},"y_axis":{"major_grid_lines":true}}`), "unsupported chart type unknown")
|
||||
assert.NoError(t, f.Close())
|
||||
|
||||
// Test add chart with unsupported charset content types.
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AddChart("Sheet1", "P1", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"}],"title":{"name":"2D Column Chart"}}`), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestAddChartSheet(t *testing.T) {
|
||||
|
@ -259,6 +264,14 @@ func TestAddChartSheet(t *testing.T) {
|
|||
assert.NoError(t, f.UpdateLinkedValue())
|
||||
|
||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddChartSheet.xlsx")))
|
||||
// Test add chart sheet with unsupported charset drawing XML.
|
||||
f.Pkg.Store("xl/drawings/drawing4.xml", MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AddChartSheet("Chart3", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"}],"title":{"name":"2D Column Chart"}}`), "XML syntax error on line 1: invalid UTF-8")
|
||||
// Test add chart sheet with unsupported charset content types.
|
||||
f = NewFile()
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AddChartSheet("Chart4", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"}],"title":{"name":"2D Column Chart"}}`), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestDeleteChart(t *testing.T) {
|
||||
|
|
|
@ -69,8 +69,8 @@ func (f *File) GetComments() (map[string][]Comment, error) {
|
|||
// getSheetComments provides the method to get the target comment reference by
|
||||
// given worksheet file path.
|
||||
func (f *File) getSheetComments(sheetFile string) string {
|
||||
rels := "xl/worksheets/_rels/" + sheetFile + ".rels"
|
||||
if sheetRels := f.relsReader(rels); sheetRels != nil {
|
||||
rels, _ := f.relsReader("xl/worksheets/_rels/" + sheetFile + ".rels")
|
||||
if sheetRels := rels; sheetRels != nil {
|
||||
sheetRels.Lock()
|
||||
defer sheetRels.Unlock()
|
||||
for _, v := range sheetRels.Relationships {
|
||||
|
@ -135,8 +135,7 @@ func (f *File) AddComment(sheet string, comment Comment) error {
|
|||
if err = f.addComment(commentsXML, comment); err != nil {
|
||||
return err
|
||||
}
|
||||
f.addContentTypePart(commentID, "comments")
|
||||
return err
|
||||
return f.addContentTypePart(commentID, "comments")
|
||||
}
|
||||
|
||||
// DeleteComment provides the method to delete comment in a sheet by given
|
||||
|
|
|
@ -112,7 +112,8 @@ func TestDecodeVMLDrawingReader(t *testing.T) {
|
|||
f := NewFile()
|
||||
path := "xl/drawings/vmlDrawing1.xml"
|
||||
f.Pkg.Store(path, MacintoshCyrillicCharset)
|
||||
f.decodeVMLDrawingReader(path)
|
||||
_, err := f.decodeVMLDrawingReader(path)
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestCommentsReader(t *testing.T) {
|
||||
|
|
36
excelize.go
36
excelize.go
|
@ -181,8 +181,10 @@ func OpenReader(r io.Reader, opts ...Options) (*File, error) {
|
|||
return f, err
|
||||
}
|
||||
f.sheetMap = f.getSheetMap()
|
||||
f.Styles, err = f.stylesReader()
|
||||
f.Theme = f.themeReader()
|
||||
if f.Styles, err = f.stylesReader(); err != nil {
|
||||
return f, err
|
||||
}
|
||||
f.Theme, err = f.themeReader()
|
||||
return f, err
|
||||
}
|
||||
|
||||
|
@ -335,7 +337,7 @@ func checkSheetR0(ws *xlsxWorksheet, sheetData *xlsxSheetData, r0 *xlsxRow) {
|
|||
// setRels provides a function to set relationships by given relationship ID,
|
||||
// XML path, relationship type, target and target mode.
|
||||
func (f *File) setRels(rID, relPath, relType, target, targetMode string) int {
|
||||
rels := f.relsReader(relPath)
|
||||
rels, _ := f.relsReader(relPath)
|
||||
if rels == nil || rID == "" {
|
||||
return f.addRels(relPath, relType, target, targetMode)
|
||||
}
|
||||
|
@ -360,7 +362,7 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int {
|
|||
uniqPart := map[string]string{
|
||||
SourceRelationshipSharedStrings: "/xl/sharedStrings.xml",
|
||||
}
|
||||
rels := f.relsReader(relPath)
|
||||
rels, _ := f.relsReader(relPath)
|
||||
if rels == nil {
|
||||
rels = &xlsxRelationships{}
|
||||
}
|
||||
|
@ -418,7 +420,10 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int {
|
|||
// </c>
|
||||
// </row>
|
||||
func (f *File) UpdateLinkedValue() error {
|
||||
wb := f.workbookReader()
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// recalculate formulas
|
||||
wb.CalcPr = nil
|
||||
for _, name := range f.GetSheetList() {
|
||||
|
@ -465,12 +470,15 @@ func (f *File) AddVBAProject(bin string) error {
|
|||
if path.Ext(bin) != ".bin" {
|
||||
return ErrAddVBAProject
|
||||
}
|
||||
wb := f.relsReader(f.getWorkbookRelsPath())
|
||||
wb.Lock()
|
||||
defer wb.Unlock()
|
||||
rels, err := f.relsReader(f.getWorkbookRelsPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rels.Lock()
|
||||
defer rels.Unlock()
|
||||
var rID int
|
||||
var ok bool
|
||||
for _, rel := range wb.Relationships {
|
||||
for _, rel := range rels.Relationships {
|
||||
if rel.Target == "vbaProject.bin" && rel.Type == SourceRelationshipVBAProject {
|
||||
ok = true
|
||||
continue
|
||||
|
@ -482,7 +490,7 @@ func (f *File) AddVBAProject(bin string) error {
|
|||
}
|
||||
rID++
|
||||
if !ok {
|
||||
wb.Relationships = append(wb.Relationships, xlsxRelationship{
|
||||
rels.Relationships = append(rels.Relationships, xlsxRelationship{
|
||||
ID: "rId" + strconv.Itoa(rID),
|
||||
Target: "vbaProject.bin",
|
||||
Type: SourceRelationshipVBAProject,
|
||||
|
@ -495,9 +503,12 @@ func (f *File) AddVBAProject(bin string) error {
|
|||
|
||||
// setContentTypePartProjectExtensions provides a function to set the content
|
||||
// type for relationship parts and the main document part.
|
||||
func (f *File) setContentTypePartProjectExtensions(contentType string) {
|
||||
func (f *File) setContentTypePartProjectExtensions(contentType string) error {
|
||||
var ok bool
|
||||
content := f.contentTypesReader()
|
||||
content, err := f.contentTypesReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content.Lock()
|
||||
defer content.Unlock()
|
||||
for _, v := range content.Defaults {
|
||||
|
@ -516,4 +527,5 @@ func (f *File) setContentTypePartProjectExtensions(contentType string) {
|
|||
ContentType: ContentTypeVBA,
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -219,26 +219,31 @@ func TestOpenReader(t *testing.T) {
|
|||
assert.EqualError(t, err, ErrWorkbookFileFormat.Error())
|
||||
|
||||
// Test open workbook with unsupported charset internal calculation chain.
|
||||
source, err := zip.OpenReader(filepath.Join("test", "Book1.xlsx"))
|
||||
assert.NoError(t, err)
|
||||
buf := new(bytes.Buffer)
|
||||
zw := zip.NewWriter(buf)
|
||||
for _, item := range source.File {
|
||||
// The following statements can be simplified as zw.Copy(item) in go1.17
|
||||
writer, err := zw.Create(item.Name)
|
||||
preset := func(filePath string) *bytes.Buffer {
|
||||
source, err := zip.OpenReader(filepath.Join("test", "Book1.xlsx"))
|
||||
assert.NoError(t, err)
|
||||
readerCloser, err := item.Open()
|
||||
buf := new(bytes.Buffer)
|
||||
zw := zip.NewWriter(buf)
|
||||
for _, item := range source.File {
|
||||
// The following statements can be simplified as zw.Copy(item) in go1.17
|
||||
writer, err := zw.Create(item.Name)
|
||||
assert.NoError(t, err)
|
||||
readerCloser, err := item.Open()
|
||||
assert.NoError(t, err)
|
||||
_, err = io.Copy(writer, readerCloser)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
fi, err := zw.Create(filePath)
|
||||
assert.NoError(t, err)
|
||||
_, err = io.Copy(writer, readerCloser)
|
||||
_, err = fi.Write(MacintoshCyrillicCharset)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, zw.Close())
|
||||
return buf
|
||||
}
|
||||
for _, defaultXMLPath := range []string{defaultXMLPathCalcChain, defaultXMLPathStyles} {
|
||||
_, err = OpenReader(preset(defaultXMLPath))
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
fi, err := zw.Create(defaultXMLPathCalcChain)
|
||||
assert.NoError(t, err)
|
||||
_, err = fi.Write(MacintoshCyrillicCharset)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, zw.Close())
|
||||
_, err = OpenReader(buf)
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
|
||||
// Test open spreadsheet with unzip size limit.
|
||||
_, err = OpenFile(filepath.Join("test", "Book1.xlsx"), Options{UnzipSizeLimit: 100})
|
||||
|
@ -466,29 +471,16 @@ func TestGetCellHyperLink(t *testing.T) {
|
|||
|
||||
func TestSetSheetBackground(t *testing.T) {
|
||||
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
err = f.SetSheetBackground("Sheet2", filepath.Join("test", "images", "background.jpg"))
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
err = f.SetSheetBackground("Sheet2", filepath.Join("test", "images", "background.jpg"))
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, f.SetSheetBackground("Sheet2", filepath.Join("test", "images", "background.jpg")))
|
||||
assert.NoError(t, f.SetSheetBackground("Sheet2", filepath.Join("test", "images", "background.jpg")))
|
||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetSheetBackground.xlsx")))
|
||||
assert.NoError(t, f.Close())
|
||||
}
|
||||
|
||||
func TestSetSheetBackgroundErrors(t *testing.T) {
|
||||
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
|
||||
if !assert.NoError(t, err) {
|
||||
t.FailNow()
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = f.SetSheetBackground("Sheet2", filepath.Join("test", "not_exists", "not_exists.png"))
|
||||
if assert.Error(t, err) {
|
||||
|
@ -497,7 +489,16 @@ func TestSetSheetBackgroundErrors(t *testing.T) {
|
|||
|
||||
err = f.SetSheetBackground("Sheet2", filepath.Join("test", "Book1.xlsx"))
|
||||
assert.EqualError(t, err, ErrImgExt.Error())
|
||||
// Test set sheet background on not exist worksheet.
|
||||
err = f.SetSheetBackground("SheetN", filepath.Join("test", "images", "background.jpg"))
|
||||
assert.EqualError(t, err, "sheet SheetN does not exist")
|
||||
assert.NoError(t, f.Close())
|
||||
|
||||
// Test set sheet background with unsupported charset content types.
|
||||
f = NewFile()
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.SetSheetBackground("Sheet1", filepath.Join("test", "images", "background.jpg")), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
// TestWriteArrayFormula tests the extended options of SetCellFormula by writing an array function
|
||||
|
@ -1027,12 +1028,6 @@ func TestGetSheetComments(t *testing.T) {
|
|||
assert.Equal(t, "", f.getSheetComments("sheet0"))
|
||||
}
|
||||
|
||||
func TestSetSheetVisible(t *testing.T) {
|
||||
f := NewFile()
|
||||
f.WorkBook.Sheets.Sheet[0].Name = "SheetN"
|
||||
assert.EqualError(t, f.SetSheetVisible("Sheet1", false), "sheet SheetN does not exist")
|
||||
}
|
||||
|
||||
func TestGetActiveSheetIndex(t *testing.T) {
|
||||
f := NewFile()
|
||||
f.WorkBook.BookViews = nil
|
||||
|
@ -1334,6 +1329,10 @@ func TestAddVBAProject(t *testing.T) {
|
|||
// Test add VBA project twice.
|
||||
assert.NoError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")))
|
||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddVBAProject.xlsm")))
|
||||
// Test add VBs with unsupported charset workbook relationships.
|
||||
f.Relationships.Delete(defaultXMLPathWorkbookRels)
|
||||
f.Pkg.Store(defaultXMLPathWorkbookRels, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AddVBAProject(filepath.Join("test", "vbaProject.bin")), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestContentTypesReader(t *testing.T) {
|
||||
|
@ -1341,7 +1340,8 @@ func TestContentTypesReader(t *testing.T) {
|
|||
f := NewFile()
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
f.contentTypesReader()
|
||||
_, err := f.contentTypesReader()
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestWorkbookReader(t *testing.T) {
|
||||
|
@ -1349,7 +1349,8 @@ func TestWorkbookReader(t *testing.T) {
|
|||
f := NewFile()
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
f.workbookReader()
|
||||
_, err := f.workbookReader()
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestWorkSheetReader(t *testing.T) {
|
||||
|
@ -1373,19 +1374,28 @@ func TestWorkSheetReader(t *testing.T) {
|
|||
func TestRelsReader(t *testing.T) {
|
||||
// Test unsupported charset.
|
||||
f := NewFile()
|
||||
rels := "xl/_rels/workbook.xml.rels"
|
||||
rels := defaultXMLPathWorkbookRels
|
||||
f.Relationships.Store(rels, nil)
|
||||
f.Pkg.Store(rels, MacintoshCyrillicCharset)
|
||||
f.relsReader(rels)
|
||||
_, err := f.relsReader(rels)
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestDeleteSheetFromWorkbookRels(t *testing.T) {
|
||||
f := NewFile()
|
||||
rels := "xl/_rels/workbook.xml.rels"
|
||||
rels := defaultXMLPathWorkbookRels
|
||||
f.Relationships.Store(rels, nil)
|
||||
assert.Equal(t, f.deleteSheetFromWorkbookRels("rID"), "")
|
||||
}
|
||||
|
||||
func TestUpdateLinkedValue(t *testing.T) {
|
||||
f := NewFile()
|
||||
// Test update lined value with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.UpdateLinkedValue(), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestAttrValToInt(t *testing.T) {
|
||||
_, err := attrValToInt("r", []xml.Attr{
|
||||
{Name: xml.Name{Local: "r"}, Value: "s"},
|
||||
|
|
15
file.go
15
file.go
|
@ -30,7 +30,7 @@ func NewFile() *File {
|
|||
f.Pkg.Store("_rels/.rels", []byte(xml.Header+templateRels))
|
||||
f.Pkg.Store(defaultXMLPathDocPropsApp, []byte(xml.Header+templateDocpropsApp))
|
||||
f.Pkg.Store(defaultXMLPathDocPropsCore, []byte(xml.Header+templateDocpropsCore))
|
||||
f.Pkg.Store("xl/_rels/workbook.xml.rels", []byte(xml.Header+templateWorkbookRels))
|
||||
f.Pkg.Store(defaultXMLPathWorkbookRels, []byte(xml.Header+templateWorkbookRels))
|
||||
f.Pkg.Store("xl/theme/theme1.xml", []byte(xml.Header+templateTheme))
|
||||
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(xml.Header+templateSheet))
|
||||
f.Pkg.Store(defaultXMLPathStyles, []byte(xml.Header+templateStyles))
|
||||
|
@ -39,18 +39,19 @@ func NewFile() *File {
|
|||
f.SheetCount = 1
|
||||
f.CalcChain, _ = f.calcChainReader()
|
||||
f.Comments = make(map[string]*xlsxComments)
|
||||
f.ContentTypes = f.contentTypesReader()
|
||||
f.ContentTypes, _ = f.contentTypesReader()
|
||||
f.Drawings = sync.Map{}
|
||||
f.Styles, _ = f.stylesReader()
|
||||
f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
|
||||
f.VMLDrawing = make(map[string]*vmlDrawing)
|
||||
f.WorkBook = f.workbookReader()
|
||||
f.WorkBook, _ = f.workbookReader()
|
||||
f.Relationships = sync.Map{}
|
||||
f.Relationships.Store("xl/_rels/workbook.xml.rels", f.relsReader("xl/_rels/workbook.xml.rels"))
|
||||
rels, _ := f.relsReader(defaultXMLPathWorkbookRels)
|
||||
f.Relationships.Store(defaultXMLPathWorkbookRels, rels)
|
||||
f.sheetMap["Sheet1"] = "xl/worksheets/sheet1.xml"
|
||||
ws, _ := f.workSheetReader("Sheet1")
|
||||
f.Sheet.Store("xl/worksheets/sheet1.xml", ws)
|
||||
f.Theme = f.themeReader()
|
||||
f.Theme, _ = f.themeReader()
|
||||
return f
|
||||
}
|
||||
|
||||
|
@ -119,7 +120,9 @@ func (f *File) WriteTo(w io.Writer, opts ...Options) (int64, error) {
|
|||
if !ok {
|
||||
return 0, ErrWorkbookFileFormat
|
||||
}
|
||||
f.setContentTypePartProjectExtensions(contentType)
|
||||
if err := f.setContentTypePartProjectExtensions(contentType); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if f.options != nil && f.options.Password != "" {
|
||||
buf, err := f.WriteToBuffer()
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
@ -79,6 +80,14 @@ func TestWriteTo(t *testing.T) {
|
|||
_, err := f.WriteTo(bufio.NewWriter(&buf))
|
||||
assert.EqualError(t, err, ErrWorkbookFileFormat.Error())
|
||||
}
|
||||
// Test write with unsupported charset content types.
|
||||
{
|
||||
f, buf := NewFile(), bytes.Buffer{}
|
||||
f.ContentTypes, f.Path = nil, filepath.Join("test", "TestWriteTo.xlsx")
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
_, err := f.WriteTo(bufio.NewWriter(&buf))
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
|
|
52
picture.go
52
picture.go
|
@ -187,7 +187,9 @@ func (f *File) AddPictureFromBytes(sheet, cell, opts, name, extension string, fi
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.addContentTypePart(drawingID, "drawings")
|
||||
if err = f.addContentTypePart(drawingID, "drawings"); err != nil {
|
||||
return err
|
||||
}
|
||||
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||
return err
|
||||
}
|
||||
|
@ -201,7 +203,7 @@ func (f *File) deleteSheetRelationships(sheet, rID string) {
|
|||
name = strings.ToLower(sheet) + ".xml"
|
||||
}
|
||||
rels := "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels"
|
||||
sheetRels := f.relsReader(rels)
|
||||
sheetRels, _ := f.relsReader(rels)
|
||||
if sheetRels == nil {
|
||||
sheetRels = &xlsxRelationships{}
|
||||
}
|
||||
|
@ -235,11 +237,15 @@ func (f *File) addSheetDrawing(sheet string, rID int) {
|
|||
|
||||
// addSheetPicture provides a function to add picture element to
|
||||
// xl/worksheets/sheet%d.xml by given worksheet name and relationship index.
|
||||
func (f *File) addSheetPicture(sheet string, rID int) {
|
||||
ws, _ := f.workSheetReader(sheet)
|
||||
func (f *File) addSheetPicture(sheet string, rID int) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ws.Picture = &xlsxPicture{
|
||||
RID: "rId" + strconv.Itoa(rID),
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// countDrawings provides a function to get drawing files count storage in the
|
||||
|
@ -378,12 +384,15 @@ func (f *File) addMedia(file []byte, ext string) string {
|
|||
|
||||
// setContentTypePartImageExtensions provides a function to set the content
|
||||
// type for relationship parts and the Main Document part.
|
||||
func (f *File) setContentTypePartImageExtensions() {
|
||||
func (f *File) setContentTypePartImageExtensions() error {
|
||||
imageTypes := map[string]string{
|
||||
"jpeg": "image/", "png": "image/", "gif": "image/", "svg": "image/", "tiff": "image/",
|
||||
"emf": "image/x-", "wmf": "image/x-", "emz": "image/x-", "wmz": "image/x-",
|
||||
}
|
||||
content := f.contentTypesReader()
|
||||
content, err := f.contentTypesReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content.Lock()
|
||||
defer content.Unlock()
|
||||
for _, file := range content.Defaults {
|
||||
|
@ -395,13 +404,17 @@ func (f *File) setContentTypePartImageExtensions() {
|
|||
ContentType: prefix + extension,
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// setContentTypePartVMLExtensions provides a function to set the content type
|
||||
// for relationship parts and the Main Document part.
|
||||
func (f *File) setContentTypePartVMLExtensions() {
|
||||
vml := false
|
||||
content := f.contentTypesReader()
|
||||
func (f *File) setContentTypePartVMLExtensions() error {
|
||||
var vml bool
|
||||
content, err := f.contentTypesReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content.Lock()
|
||||
defer content.Unlock()
|
||||
for _, v := range content.Defaults {
|
||||
|
@ -415,12 +428,13 @@ func (f *File) setContentTypePartVMLExtensions() {
|
|||
ContentType: ContentTypeVML,
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// addContentTypePart provides a function to add content type part
|
||||
// relationships in the file [Content_Types].xml by given index.
|
||||
func (f *File) addContentTypePart(index int, contentType string) {
|
||||
setContentType := map[string]func(){
|
||||
func (f *File) addContentTypePart(index int, contentType string) error {
|
||||
setContentType := map[string]func() error{
|
||||
"comments": f.setContentTypePartVMLExtensions,
|
||||
"drawings": f.setContentTypePartImageExtensions,
|
||||
}
|
||||
|
@ -446,20 +460,26 @@ func (f *File) addContentTypePart(index int, contentType string) {
|
|||
}
|
||||
s, ok := setContentType[contentType]
|
||||
if ok {
|
||||
s()
|
||||
if err := s(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
content, err := f.contentTypesReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content := f.contentTypesReader()
|
||||
content.Lock()
|
||||
defer content.Unlock()
|
||||
for _, v := range content.Overrides {
|
||||
if v.PartName == partNames[contentType] {
|
||||
return
|
||||
return err
|
||||
}
|
||||
}
|
||||
content.Overrides = append(content.Overrides, xlsxOverride{
|
||||
PartName: partNames[contentType],
|
||||
ContentType: contentTypes[contentType],
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// getSheetRelationshipsTargetByID provides a function to get Target attribute
|
||||
|
@ -471,7 +491,7 @@ func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
|
|||
name = strings.ToLower(sheet) + ".xml"
|
||||
}
|
||||
rels := "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels"
|
||||
sheetRels := f.relsReader(rels)
|
||||
sheetRels, _ := f.relsReader(rels)
|
||||
if sheetRels == nil {
|
||||
sheetRels = &xlsxRelationships{}
|
||||
}
|
||||
|
@ -630,7 +650,7 @@ func (f *File) getPictureFromWsDr(row, col int, drawingRelationships string, wsD
|
|||
// from xl/drawings/_rels/drawing%s.xml.rels by given file name and
|
||||
// relationship ID.
|
||||
func (f *File) getDrawingRelationships(rels, rID string) *xlsxRelationship {
|
||||
if drawingRels := f.relsReader(rels); drawingRels != nil {
|
||||
if drawingRels, _ := f.relsReader(rels); drawingRels != nil {
|
||||
drawingRels.Lock()
|
||||
defer drawingRels.Unlock()
|
||||
for _, v := range drawingRels.Relationships {
|
||||
|
|
|
@ -67,6 +67,12 @@ func TestAddPicture(t *testing.T) {
|
|||
// Test write file to given path.
|
||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddPicture1.xlsx")))
|
||||
assert.NoError(t, f.Close())
|
||||
|
||||
// Test add picture with unsupported charset content types.
|
||||
f = NewFile()
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AddPictureFromBytes("Sheet1", "Q1", "", "Excel Logo", ".png", file), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestAddPictureErrors(t *testing.T) {
|
||||
|
@ -236,3 +242,27 @@ func TestDrawingResize(t *testing.T) {
|
|||
ws.(*xlsxWorksheet).MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A:A"}}}
|
||||
assert.EqualError(t, f.AddPicture("Sheet1", "A1", filepath.Join("test", "images", "excel.jpg"), `{"autofit": true}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
}
|
||||
|
||||
func TestSetContentTypePartImageExtensions(t *testing.T) {
|
||||
f := NewFile()
|
||||
// Test set content type part image extensions with unsupported charset content types.
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.setContentTypePartImageExtensions(), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestSetContentTypePartVMLExtensions(t *testing.T) {
|
||||
f := NewFile()
|
||||
// Test set content type part VML extensions with unsupported charset content types.
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.setContentTypePartVMLExtensions(), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestAddContentTypePart(t *testing.T) {
|
||||
f := NewFile()
|
||||
// Test add content type part with unsupported charset content types.
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.addContentTypePart(0, "unknown"), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
|
|
@ -160,10 +160,10 @@ func (f *File) AddPivotTable(opts *PivotTableOptions) error {
|
|||
}
|
||||
pivotTableSheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(pivotTableSheetPath, "xl/worksheets/") + ".rels"
|
||||
f.addRels(pivotTableSheetRels, SourceRelationshipPivotTable, sheetRelationshipsPivotTableXML, "")
|
||||
f.addContentTypePart(pivotTableID, "pivotTable")
|
||||
f.addContentTypePart(pivotCacheID, "pivotCache")
|
||||
|
||||
return nil
|
||||
if err = f.addContentTypePart(pivotTableID, "pivotTable"); err != nil {
|
||||
return err
|
||||
}
|
||||
return f.addContentTypePart(pivotCacheID, "pivotCache")
|
||||
}
|
||||
|
||||
// parseFormatPivotTableSet provides a function to validate pivot table
|
||||
|
@ -697,7 +697,7 @@ func (f *File) getPivotTableFieldOptions(name string, fields []PivotTableField)
|
|||
|
||||
// addWorkbookPivotCache add the association ID of the pivot cache in workbook.xml.
|
||||
func (f *File) addWorkbookPivotCache(RID int) int {
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
if wb.PivotCaches == nil {
|
||||
wb.PivotCaches = &xlsxPivotCaches{}
|
||||
}
|
||||
|
|
|
@ -259,6 +259,15 @@ func TestAddPivotTable(t *testing.T) {
|
|||
// Test get pivot fields index with empty data range
|
||||
_, err = f.getPivotFieldsIndex([]PivotTableField{}, &PivotTableOptions{})
|
||||
assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
|
||||
// Test add pivot table with unsupported charset content types.
|
||||
f = NewFile()
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AddPivotTable(&PivotTableOptions{
|
||||
DataRange: "Sheet1!$A$1:$E$31",
|
||||
PivotTableRange: "Sheet1!$G$2:$M$34",
|
||||
Rows: []PivotTableField{{Data: "Year"}},
|
||||
}), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestAddPivotRowFields(t *testing.T) {
|
||||
|
|
9
rows.go
9
rows.go
|
@ -435,8 +435,13 @@ func (f *File) sharedStringsReader() (*xlsxSST, error) {
|
|||
f.sharedStringsMap[sharedStrings.SI[i].T.Val] = i
|
||||
}
|
||||
}
|
||||
f.addContentTypePart(0, "sharedStrings")
|
||||
rels := f.relsReader(relPath)
|
||||
if err = f.addContentTypePart(0, "sharedStrings"); err != nil {
|
||||
return f.SharedStrings, err
|
||||
}
|
||||
rels, err := f.relsReader(relPath)
|
||||
if err != nil {
|
||||
return f.SharedStrings, err
|
||||
}
|
||||
for _, rel := range rels.Relationships {
|
||||
if rel.Target == "/xl/sharedStrings.xml" {
|
||||
return f.SharedStrings, nil
|
||||
|
|
17
rows_test.go
17
rows_test.go
|
@ -235,9 +235,20 @@ func TestSharedStringsReader(t *testing.T) {
|
|||
f := NewFile()
|
||||
// Test read shared string with unsupported charset.
|
||||
f.Pkg.Store(defaultXMLPathSharedStrings, MacintoshCyrillicCharset)
|
||||
f.sharedStringsReader()
|
||||
si := xlsxSI{}
|
||||
assert.EqualValues(t, "", si.String())
|
||||
_, err := f.sharedStringsReader()
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
// Test read shared strings with unsupported charset content types.
|
||||
f = NewFile()
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
_, err = f.sharedStringsReader()
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
// Test read shared strings with unsupported charset workbook relationships.
|
||||
f = NewFile()
|
||||
f.Relationships.Delete(defaultXMLPathWorkbookRels)
|
||||
f.Pkg.Store(defaultXMLPathWorkbookRels, MacintoshCyrillicCharset)
|
||||
_, err = f.sharedStringsReader()
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestRowVisibility(t *testing.T) {
|
||||
|
|
3
shape.go
3
shape.go
|
@ -308,8 +308,7 @@ func (f *File) AddShape(sheet, cell, opts string) error {
|
|||
if err = f.addDrawingShape(sheet, drawingXML, cell, options); err != nil {
|
||||
return err
|
||||
}
|
||||
f.addContentTypePart(drawingID, "drawings")
|
||||
return err
|
||||
return f.addContentTypePart(drawingID, "drawings")
|
||||
}
|
||||
|
||||
// addDrawingShape provides a function to add preset geometry by given sheet,
|
||||
|
|
|
@ -87,10 +87,15 @@ func TestAddShape(t *testing.T) {
|
|||
}
|
||||
}`))
|
||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddShape2.xlsx")))
|
||||
// Test set row style with unsupported charset style sheet.
|
||||
// Test add shape with unsupported charset style sheet.
|
||||
f.Styles = nil
|
||||
f.Pkg.Store(defaultXMLPathStyles, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AddShape("Sheet1", "B30", `{"type":"rect","paragraph":[{"text":"Rectangle"},{}]}`), "XML syntax error on line 1: invalid UTF-8")
|
||||
// Test add shape with unsupported charset content types.
|
||||
f = NewFile()
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AddShape("Sheet1", "B30", `{"type":"rect","paragraph":[{"text":"Rectangle"},{}]}`), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestAddDrawingShape(t *testing.T) {
|
||||
|
|
129
sheet.go
129
sheet.go
|
@ -17,7 +17,6 @@ import (
|
|||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
@ -47,7 +46,7 @@ func (f *File) NewSheet(sheet string) int {
|
|||
}
|
||||
f.DeleteSheet(sheet)
|
||||
f.SheetCount++
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
sheetID := 0
|
||||
for _, v := range wb.Sheets.Sheet {
|
||||
if v.SheetID > sheetID {
|
||||
|
@ -56,7 +55,7 @@ func (f *File) NewSheet(sheet string) int {
|
|||
}
|
||||
sheetID++
|
||||
// Update [Content_Types].xml
|
||||
f.setContentTypes("/xl/worksheets/sheet"+strconv.Itoa(sheetID)+".xml", ContentTypeSpreadSheetMLWorksheet)
|
||||
_ = f.setContentTypes("/xl/worksheets/sheet"+strconv.Itoa(sheetID)+".xml", ContentTypeSpreadSheetMLWorksheet)
|
||||
// Create new sheet /xl/worksheets/sheet%d.xml
|
||||
f.setSheet(sheetID, sheet)
|
||||
// Update workbook.xml.rels
|
||||
|
@ -68,19 +67,17 @@ func (f *File) NewSheet(sheet 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
|
||||
|
||||
func (f *File) contentTypesReader() (*xlsxTypes, error) {
|
||||
if f.ContentTypes == nil {
|
||||
f.ContentTypes = new(xlsxTypes)
|
||||
f.ContentTypes.Lock()
|
||||
defer f.ContentTypes.Unlock()
|
||||
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathContentTypes)))).
|
||||
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathContentTypes)))).
|
||||
Decode(f.ContentTypes); err != nil && err != io.EOF {
|
||||
log.Printf("xml decode error: %s", err)
|
||||
return f.ContentTypes, err
|
||||
}
|
||||
}
|
||||
return f.ContentTypes
|
||||
return f.ContentTypes, nil
|
||||
}
|
||||
|
||||
// contentTypesWriter provides a function to save [Content_Types].xml after
|
||||
|
@ -215,14 +212,18 @@ func trimCell(column []xlsxC) []xlsxC {
|
|||
|
||||
// setContentTypes provides a function to read and update property of contents
|
||||
// type of the spreadsheet.
|
||||
func (f *File) setContentTypes(partName, contentType string) {
|
||||
content := f.contentTypesReader()
|
||||
func (f *File) setContentTypes(partName, contentType string) error {
|
||||
content, err := f.contentTypesReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content.Lock()
|
||||
defer content.Unlock()
|
||||
content.Overrides = append(content.Overrides, xlsxOverride{
|
||||
PartName: partName,
|
||||
ContentType: contentType,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// setSheet provides a function to update sheet property by given index.
|
||||
|
@ -271,7 +272,7 @@ func (f *File) SetActiveSheet(index int) {
|
|||
if index < 0 {
|
||||
index = 0
|
||||
}
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
for activeTab := range wb.Sheets.Sheet {
|
||||
if activeTab == index {
|
||||
if wb.BookViews == nil {
|
||||
|
@ -316,7 +317,7 @@ func (f *File) SetActiveSheet(index int) {
|
|||
// spreadsheet. If not found the active sheet will be return integer 0.
|
||||
func (f *File) GetActiveSheetIndex() (index int) {
|
||||
sheetID := f.getActiveSheetID()
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
if wb != nil {
|
||||
for idx, sheet := range wb.Sheets.Sheet {
|
||||
if sheet.SheetID == sheetID {
|
||||
|
@ -331,7 +332,7 @@ func (f *File) GetActiveSheetIndex() (index int) {
|
|||
// getActiveSheetID provides a function to get active sheet ID of the
|
||||
// spreadsheet. If not found the active sheet will be return integer 0.
|
||||
func (f *File) getActiveSheetID() int {
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
if wb != nil {
|
||||
if wb.BookViews != nil && len(wb.BookViews.WorkBookView) > 0 {
|
||||
activeTab := wb.BookViews.WorkBookView[0].ActiveTab
|
||||
|
@ -357,10 +358,10 @@ func (f *File) SetSheetName(source, target string) {
|
|||
if strings.EqualFold(target, source) {
|
||||
return
|
||||
}
|
||||
content := f.workbookReader()
|
||||
for k, v := range content.Sheets.Sheet {
|
||||
wb, _ := f.workbookReader()
|
||||
for k, v := range wb.Sheets.Sheet {
|
||||
if v.Name == source {
|
||||
content.Sheets.Sheet[k].Name = target
|
||||
wb.Sheets.Sheet[k].Name = target
|
||||
f.sheetMap[target] = f.sheetMap[source]
|
||||
delete(f.sheetMap, source)
|
||||
}
|
||||
|
@ -422,7 +423,7 @@ func (f *File) GetSheetIndex(sheet string) int {
|
|||
// fmt.Println(index, name)
|
||||
// }
|
||||
func (f *File) GetSheetMap() map[int]string {
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
sheetMap := map[int]string{}
|
||||
if wb != nil {
|
||||
for _, sheet := range wb.Sheets.Sheet {
|
||||
|
@ -435,7 +436,7 @@ func (f *File) GetSheetMap() map[int]string {
|
|||
// GetSheetList provides a function to get worksheets, chart sheets, and
|
||||
// dialog sheets name list of the workbook.
|
||||
func (f *File) GetSheetList() (list []string) {
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
if wb != nil {
|
||||
for _, sheet := range wb.Sheets.Sheet {
|
||||
list = append(list, sheet.Name)
|
||||
|
@ -448,8 +449,10 @@ func (f *File) GetSheetList() (list []string) {
|
|||
// of the spreadsheet.
|
||||
func (f *File) getSheetMap() map[string]string {
|
||||
maps := map[string]string{}
|
||||
for _, v := range f.workbookReader().Sheets.Sheet {
|
||||
for _, rel := range f.relsReader(f.getWorkbookRelsPath()).Relationships {
|
||||
wb, _ := f.workbookReader()
|
||||
rels, _ := f.relsReader(f.getWorkbookRelsPath())
|
||||
for _, v := range wb.Sheets.Sheet {
|
||||
for _, rel := range rels.Relationships {
|
||||
if rel.ID == v.ID {
|
||||
sheetXMLPath := f.getWorksheetPath(rel.Target)
|
||||
if _, ok := f.Pkg.Load(sheetXMLPath); ok {
|
||||
|
@ -498,10 +501,11 @@ func (f *File) SetSheetBackground(sheet, picture string) error {
|
|||
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
|
||||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
|
||||
rID := f.addRels(sheetRels, SourceRelationshipImage, strings.Replace(name, "xl", "..", 1), "")
|
||||
f.addSheetPicture(sheet, rID)
|
||||
if err = f.addSheetPicture(sheet, rID); err != nil {
|
||||
return err
|
||||
}
|
||||
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||
f.setContentTypePartImageExtensions()
|
||||
return err
|
||||
return f.setContentTypePartImageExtensions()
|
||||
}
|
||||
|
||||
// DeleteSheet provides a function to delete worksheet in a workbook by given
|
||||
|
@ -514,8 +518,8 @@ func (f *File) DeleteSheet(sheet string) {
|
|||
return
|
||||
}
|
||||
sheetName := trimSheetName(sheet)
|
||||
wb := f.workbookReader()
|
||||
wbRels := f.relsReader(f.getWorkbookRelsPath())
|
||||
wb, _ := f.workbookReader()
|
||||
wbRels, _ := f.relsReader(f.getWorkbookRelsPath())
|
||||
activeSheetName := f.GetSheetName(f.GetActiveSheetIndex())
|
||||
deleteLocalSheetID := f.GetSheetIndex(sheet)
|
||||
deleteAndAdjustDefinedNames(wb, deleteLocalSheetID)
|
||||
|
@ -537,8 +541,8 @@ func (f *File) DeleteSheet(sheet string) {
|
|||
}
|
||||
}
|
||||
target := f.deleteSheetFromWorkbookRels(v.ID)
|
||||
f.deleteSheetFromContentTypes(target)
|
||||
f.deleteCalcChain(f.getSheetID(sheet), "")
|
||||
_ = f.deleteSheetFromContentTypes(target)
|
||||
_ = f.deleteCalcChain(f.getSheetID(sheet), "")
|
||||
delete(f.sheetMap, v.Name)
|
||||
f.Pkg.Delete(sheetXML)
|
||||
f.Pkg.Delete(rels)
|
||||
|
@ -573,12 +577,12 @@ func deleteAndAdjustDefinedNames(wb *xlsxWorkbook, deleteLocalSheetID int) {
|
|||
// deleteSheetFromWorkbookRels provides a function to remove worksheet
|
||||
// relationships by given relationships ID in the file workbook.xml.rels.
|
||||
func (f *File) deleteSheetFromWorkbookRels(rID string) string {
|
||||
content := f.relsReader(f.getWorkbookRelsPath())
|
||||
content.Lock()
|
||||
defer content.Unlock()
|
||||
for k, v := range content.Relationships {
|
||||
rels, _ := f.relsReader(f.getWorkbookRelsPath())
|
||||
rels.Lock()
|
||||
defer rels.Unlock()
|
||||
for k, v := range rels.Relationships {
|
||||
if v.ID == rID {
|
||||
content.Relationships = append(content.Relationships[:k], content.Relationships[k+1:]...)
|
||||
rels.Relationships = append(rels.Relationships[:k], rels.Relationships[k+1:]...)
|
||||
return v.Target
|
||||
}
|
||||
}
|
||||
|
@ -587,11 +591,14 @@ func (f *File) deleteSheetFromWorkbookRels(rID string) string {
|
|||
|
||||
// deleteSheetFromContentTypes provides a function to remove worksheet
|
||||
// relationships by given target name in the file [Content_Types].xml.
|
||||
func (f *File) deleteSheetFromContentTypes(target string) {
|
||||
func (f *File) deleteSheetFromContentTypes(target string) error {
|
||||
if !strings.HasPrefix(target, "/") {
|
||||
target = "/xl/" + target
|
||||
}
|
||||
content := f.contentTypesReader()
|
||||
content, err := f.contentTypesReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content.Lock()
|
||||
defer content.Unlock()
|
||||
for k, v := range content.Overrides {
|
||||
|
@ -599,6 +606,7 @@ func (f *File) deleteSheetFromContentTypes(target string) {
|
|||
content.Overrides = append(content.Overrides[:k], content.Overrides[k+1:]...)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// CopySheet provides a function to duplicate a worksheet by gave source and
|
||||
|
@ -659,22 +667,25 @@ func (f *File) copySheet(from, to int) error {
|
|||
// err := f.SetSheetVisible("Sheet1", false)
|
||||
func (f *File) SetSheetVisible(sheet string, visible bool) error {
|
||||
sheet = trimSheetName(sheet)
|
||||
content := f.workbookReader()
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if visible {
|
||||
for k, v := range content.Sheets.Sheet {
|
||||
for k, v := range wb.Sheets.Sheet {
|
||||
if strings.EqualFold(v.Name, sheet) {
|
||||
content.Sheets.Sheet[k].State = ""
|
||||
wb.Sheets.Sheet[k].State = ""
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
count := 0
|
||||
for _, v := range content.Sheets.Sheet {
|
||||
for _, v := range wb.Sheets.Sheet {
|
||||
if v.State != "hidden" {
|
||||
count++
|
||||
}
|
||||
}
|
||||
for k, v := range content.Sheets.Sheet {
|
||||
for k, v := range wb.Sheets.Sheet {
|
||||
ws, err := f.workSheetReader(v.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -684,10 +695,10 @@ func (f *File) SetSheetVisible(sheet string, visible bool) error {
|
|||
tabSelected = ws.SheetViews.SheetView[0].TabSelected
|
||||
}
|
||||
if strings.EqualFold(v.Name, sheet) && count > 1 && !tabSelected {
|
||||
content.Sheets.Sheet[k].State = "hidden"
|
||||
wb.Sheets.Sheet[k].State = "hidden"
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// parsePanesOptions provides a function to parse the panes settings.
|
||||
|
@ -830,10 +841,11 @@ func (f *File) SetPanes(sheet, panes string) error {
|
|||
//
|
||||
// f.GetSheetVisible("Sheet1")
|
||||
func (f *File) GetSheetVisible(sheet string) bool {
|
||||
content, name, visible := f.workbookReader(), trimSheetName(sheet), false
|
||||
for k, v := range content.Sheets.Sheet {
|
||||
name, visible := trimSheetName(sheet), false
|
||||
wb, _ := f.workbookReader()
|
||||
for k, v := range wb.Sheets.Sheet {
|
||||
if strings.EqualFold(v.Name, name) {
|
||||
if content.Sheets.Sheet[k].State == "" || content.Sheets.Sheet[k].State == "visible" {
|
||||
if wb.Sheets.Sheet[k].State == "" || wb.Sheets.Sheet[k].State == "visible" {
|
||||
visible = true
|
||||
}
|
||||
}
|
||||
|
@ -1460,7 +1472,10 @@ func (f *File) GetPageLayout(sheet string) (PageLayoutOptions, error) {
|
|||
// Scope: "Sheet2",
|
||||
// })
|
||||
func (f *File) SetDefinedName(definedName *DefinedName) error {
|
||||
wb := f.workbookReader()
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d := xlsxDefinedName{
|
||||
Name: definedName.Name,
|
||||
Comment: definedName.Comment,
|
||||
|
@ -1499,7 +1514,10 @@ func (f *File) SetDefinedName(definedName *DefinedName) error {
|
|||
// Scope: "Sheet2",
|
||||
// })
|
||||
func (f *File) DeleteDefinedName(definedName *DefinedName) error {
|
||||
wb := f.workbookReader()
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wb.DefinedNames != nil {
|
||||
for idx, dn := range wb.DefinedNames.DefinedName {
|
||||
scope := "Workbook"
|
||||
|
@ -1512,7 +1530,7 @@ func (f *File) DeleteDefinedName(definedName *DefinedName) error {
|
|||
}
|
||||
if scope == deleteScope && dn.Name == definedName.Name {
|
||||
wb.DefinedNames.DefinedName = append(wb.DefinedNames.DefinedName[:idx], wb.DefinedNames.DefinedName[idx+1:]...)
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1523,7 +1541,7 @@ func (f *File) DeleteDefinedName(definedName *DefinedName) error {
|
|||
// or worksheet.
|
||||
func (f *File) GetDefinedName() []DefinedName {
|
||||
var definedNames []DefinedName
|
||||
wb := f.workbookReader()
|
||||
wb, _ := f.workbookReader()
|
||||
if wb.DefinedNames != nil {
|
||||
for _, dn := range wb.DefinedNames.DefinedName {
|
||||
definedName := DefinedName{
|
||||
|
@ -1715,23 +1733,22 @@ func (f *File) RemovePageBreak(sheet, cell string) 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
|
||||
func (f *File) relsReader(path string) (*xlsxRelationships, error) {
|
||||
rels, _ := f.Relationships.Load(path)
|
||||
if rels == nil {
|
||||
if _, ok := f.Pkg.Load(path); ok {
|
||||
c := xlsxRelationships{}
|
||||
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(path)))).
|
||||
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(path)))).
|
||||
Decode(&c); err != nil && err != io.EOF {
|
||||
log.Printf("xml decode error: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
f.Relationships.Store(path, &c)
|
||||
}
|
||||
}
|
||||
if rels, _ = f.Relationships.Load(path); rels != nil {
|
||||
return rels.(*xlsxRelationships)
|
||||
return rels.(*xlsxRelationships), nil
|
||||
}
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// fillSheetData ensures there are enough rows, and columns in the chosen
|
||||
|
|
|
@ -188,6 +188,17 @@ func TestDefinedName(t *testing.T) {
|
|||
assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[0].RefersTo)
|
||||
assert.Exactly(t, 1, len(f.GetDefinedName()))
|
||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDefinedName.xlsx")))
|
||||
// Test set defined name with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.SetDefinedName(&DefinedName{
|
||||
Name: "Amount", RefersTo: "Sheet1!$A$2:$D$5",
|
||||
}), "XML syntax error on line 1: invalid UTF-8")
|
||||
// Test delete defined name with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.DeleteDefinedName(&DefinedName{Name: "Amount"}),
|
||||
"XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestGroupSheets(t *testing.T) {
|
||||
|
@ -367,6 +378,32 @@ func TestGetSheetID(t *testing.T) {
|
|||
assert.NotEqual(t, -1, id)
|
||||
}
|
||||
|
||||
func TestSetSheetVisible(t *testing.T) {
|
||||
f := NewFile()
|
||||
f.WorkBook.Sheets.Sheet[0].Name = "SheetN"
|
||||
assert.EqualError(t, f.SetSheetVisible("Sheet1", false), "sheet SheetN does not exist")
|
||||
// Test set sheet visible with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.SetSheetVisible("Sheet1", false), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestSetContentTypes(t *testing.T) {
|
||||
f := NewFile()
|
||||
// Test set content type with unsupported charset content types.
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.setContentTypes("/xl/worksheets/sheet1.xml", ContentTypeSpreadSheetMLWorksheet), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestDeleteSheetFromContentTypes(t *testing.T) {
|
||||
f := NewFile()
|
||||
// Test delete sheet from content types with unsupported charset content types.
|
||||
f.ContentTypes = nil
|
||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.deleteSheetFromContentTypes("/xl/worksheets/sheet1.xml"), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func BenchmarkNewSheet(b *testing.B) {
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
|
|
34
stream.go
34
stream.go
|
@ -226,11 +226,12 @@ func (sw *StreamWriter) AddTable(hCell, vCell, opts string) error {
|
|||
|
||||
sw.tableParts = fmt.Sprintf(`<tableParts count="1"><tablePart r:id="rId%d"></tablePart></tableParts>`, rID)
|
||||
|
||||
sw.File.addContentTypePart(tableID, "table")
|
||||
|
||||
if err = sw.File.addContentTypePart(tableID, "table"); err != nil {
|
||||
return err
|
||||
}
|
||||
b, _ := xml.Marshal(table)
|
||||
sw.File.saveFileList(tableXML, b)
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Extract values from a row in the StreamWriter.
|
||||
|
@ -471,6 +472,23 @@ func setCellFormula(c *xlsxC, formula string) {
|
|||
}
|
||||
}
|
||||
|
||||
// setCellTime provides a function to set number of a cell with a time.
|
||||
func (sw *StreamWriter) setCellTime(c *xlsxC, val time.Time) error {
|
||||
var date1904, isNum bool
|
||||
wb, err := sw.File.workbookReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wb != nil && wb.WorkbookPr != nil {
|
||||
date1904 = wb.WorkbookPr.Date1904
|
||||
}
|
||||
if isNum, err = c.setCellTime(val, date1904); err == nil && isNum && c.S == 0 {
|
||||
style, _ := sw.File.NewStyle(&Style{NumFmt: 22})
|
||||
c.S = style
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setCellValFunc provides a function to set value of a cell.
|
||||
func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) error {
|
||||
var err error
|
||||
|
@ -488,15 +506,7 @@ func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) error {
|
|||
case time.Duration:
|
||||
c.T, c.V = setCellDuration(val)
|
||||
case time.Time:
|
||||
var isNum bool
|
||||
date1904, wb := false, sw.File.workbookReader()
|
||||
if wb != nil && wb.WorkbookPr != nil {
|
||||
date1904 = wb.WorkbookPr.Date1904
|
||||
}
|
||||
if isNum, err = c.setCellTime(val, date1904); isNum && c.S == 0 {
|
||||
style, _ := sw.File.NewStyle(&Style{NumFmt: 22})
|
||||
c.S = style
|
||||
}
|
||||
err = sw.setCellTime(c, val)
|
||||
case bool:
|
||||
c.T, c.V = setCellBool(val)
|
||||
case nil:
|
||||
|
|
|
@ -186,7 +186,7 @@ func TestStreamTable(t *testing.T) {
|
|||
}
|
||||
|
||||
// Write a table.
|
||||
assert.NoError(t, streamWriter.AddTable("A1", "C2", ``))
|
||||
assert.NoError(t, streamWriter.AddTable("A1", "C2", ""))
|
||||
assert.NoError(t, streamWriter.Flush())
|
||||
|
||||
// Verify the table has names.
|
||||
|
@ -198,13 +198,17 @@ func TestStreamTable(t *testing.T) {
|
|||
assert.Equal(t, "B", table.TableColumns.TableColumn[1].Name)
|
||||
assert.Equal(t, "C", table.TableColumns.TableColumn[2].Name)
|
||||
|
||||
assert.NoError(t, streamWriter.AddTable("A1", "C1", ``))
|
||||
assert.NoError(t, streamWriter.AddTable("A1", "C1", ""))
|
||||
|
||||
// Test add table with illegal options.
|
||||
assert.EqualError(t, streamWriter.AddTable("B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
|
||||
// Test add table with illegal cell reference.
|
||||
assert.EqualError(t, streamWriter.AddTable("A", "B1", `{}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
assert.EqualError(t, streamWriter.AddTable("A1", "B", `{}`), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
|
||||
// Test add table with unsupported charset content types.
|
||||
file.ContentTypes = nil
|
||||
file.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, streamWriter.AddTable("A1", "C2", ""), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestStreamMergeCells(t *testing.T) {
|
||||
|
@ -242,7 +246,7 @@ func TestStreamMarshalAttrs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStreamSetRow(t *testing.T) {
|
||||
// Test error exceptions
|
||||
// Test error exceptions.
|
||||
file := NewFile()
|
||||
defer func() {
|
||||
assert.NoError(t, file.Close())
|
||||
|
@ -250,9 +254,13 @@ func TestStreamSetRow(t *testing.T) {
|
|||
streamWriter, err := file.NewStreamWriter("Sheet1")
|
||||
assert.NoError(t, err)
|
||||
assert.EqualError(t, streamWriter.SetRow("A", []interface{}{}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
// Test set row with non-ascending row number
|
||||
// Test set row with non-ascending row number.
|
||||
assert.NoError(t, streamWriter.SetRow("A1", []interface{}{}))
|
||||
assert.EqualError(t, streamWriter.SetRow("A1", []interface{}{}), newStreamSetRowError(1).Error())
|
||||
// Test set row with unsupported charset workbook.
|
||||
file.WorkBook = nil
|
||||
file.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, streamWriter.SetRow("A2", []interface{}{time.Now()}), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestStreamSetRowNilValues(t *testing.T) {
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
@ -3357,16 +3356,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 {
|
||||
func (f *File) themeReader() (*xlsxTheme, error) {
|
||||
if _, ok := f.Pkg.Load(defaultXMLPathTheme); !ok {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
theme := xlsxTheme{XMLNSa: NameSpaceDrawingML.Value, XMLNSr: SourceRelationship.Value}
|
||||
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathTheme)))).
|
||||
Decode(&theme); err != nil && err != io.EOF {
|
||||
log.Printf("xml decoder error: %s", err)
|
||||
return &theme, err
|
||||
}
|
||||
return &theme
|
||||
return &theme, nil
|
||||
}
|
||||
|
||||
// ThemeColor applied the color with tint value.
|
||||
|
|
|
@ -366,7 +366,9 @@ func TestThemeReader(t *testing.T) {
|
|||
f := NewFile()
|
||||
// Test read theme with unsupported charset.
|
||||
f.Pkg.Store(defaultXMLPathTheme, MacintoshCyrillicCharset)
|
||||
assert.EqualValues(t, &xlsxTheme{XMLNSa: NameSpaceDrawingML.Value, XMLNSr: SourceRelationship.Value}, f.themeReader())
|
||||
theme, err := f.themeReader()
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
assert.EqualValues(t, &xlsxTheme{XMLNSa: NameSpaceDrawingML.Value, XMLNSr: SourceRelationship.Value}, theme)
|
||||
}
|
||||
|
||||
func TestSetCellStyle(t *testing.T) {
|
||||
|
|
8
table.go
8
table.go
|
@ -94,8 +94,7 @@ func (f *File) AddTable(sheet, hCell, vCell, opts string) error {
|
|||
if err = f.addTable(sheet, tableXML, hCol, hRow, vCol, vRow, tableID, options); err != nil {
|
||||
return err
|
||||
}
|
||||
f.addContentTypePart(tableID, "table")
|
||||
return err
|
||||
return f.addContentTypePart(tableID, "table")
|
||||
}
|
||||
|
||||
// countTables provides a function to get table files count storage in the
|
||||
|
@ -301,7 +300,10 @@ func (f *File) AutoFilter(sheet, hCell, vCell, opts string) error {
|
|||
cellStart, _ := CoordinatesToCellName(hCol, hRow, true)
|
||||
cellEnd, _ := CoordinatesToCellName(vCol, vRow, true)
|
||||
ref, filterDB := cellStart+":"+cellEnd, "_xlnm._FilterDatabase"
|
||||
wb := f.workbookReader()
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sheetID := f.GetSheetIndex(sheet)
|
||||
filterRange := fmt.Sprintf("'%s'!%s", sheet, ref)
|
||||
d := xlsxDefinedName{
|
||||
|
|
|
@ -78,9 +78,13 @@ func TestAutoFilter(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// Test AutoFilter with illegal cell reference.
|
||||
// Test add auto filter with illegal cell reference.
|
||||
assert.EqualError(t, f.AutoFilter("Sheet1", "A", "B1", ""), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
assert.EqualError(t, f.AutoFilter("Sheet1", "A1", "B", ""), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
|
||||
// Test add auto filter with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.AutoFilter("Sheet1", "D4", "B1", formats[0]), "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
||||
func TestAutoFilterError(t *testing.T) {
|
||||
|
|
|
@ -23,6 +23,7 @@ const (
|
|||
defaultXMLPathStyles = "xl/styles.xml"
|
||||
defaultXMLPathTheme = "xl/theme/theme1.xml"
|
||||
defaultXMLPathWorkbook = "xl/workbook.xml"
|
||||
defaultXMLPathWorkbookRels = "xl/_rels/workbook.xml.rels"
|
||||
defaultTempFileSST = "sharedStrings"
|
||||
)
|
||||
|
||||
|
|
26
workbook.go
26
workbook.go
|
@ -15,7 +15,6 @@ import (
|
|||
"bytes"
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -23,7 +22,10 @@ import (
|
|||
|
||||
// SetWorkbookProps provides a function to sets workbook properties.
|
||||
func (f *File) SetWorkbookProps(opts *WorkbookPropsOptions) error {
|
||||
wb := f.workbookReader()
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wb.WorkbookPr == nil {
|
||||
wb.WorkbookPr = new(xlsxWorkbookPr)
|
||||
}
|
||||
|
@ -44,20 +46,24 @@ func (f *File) SetWorkbookProps(opts *WorkbookPropsOptions) error {
|
|||
|
||||
// GetWorkbookProps provides a function to gets workbook properties.
|
||||
func (f *File) GetWorkbookProps() (WorkbookPropsOptions, error) {
|
||||
wb, opts := f.workbookReader(), WorkbookPropsOptions{}
|
||||
var opts WorkbookPropsOptions
|
||||
wb, err := f.workbookReader()
|
||||
if err != nil {
|
||||
return opts, err
|
||||
}
|
||||
if wb.WorkbookPr != nil {
|
||||
opts.Date1904 = boolPtr(wb.WorkbookPr.Date1904)
|
||||
opts.FilterPrivacy = boolPtr(wb.WorkbookPr.FilterPrivacy)
|
||||
opts.CodeName = stringPtr(wb.WorkbookPr.CodeName)
|
||||
}
|
||||
return opts, nil
|
||||
return opts, err
|
||||
}
|
||||
|
||||
// setWorkbook update workbook property of the spreadsheet. Maximum 31
|
||||
// characters are allowed in sheet title.
|
||||
func (f *File) setWorkbook(name string, sheetID, rid int) {
|
||||
content := f.workbookReader()
|
||||
content.Sheets.Sheet = append(content.Sheets.Sheet, xlsxSheet{
|
||||
wb, _ := f.workbookReader()
|
||||
wb.Sheets.Sheet = append(wb.Sheets.Sheet, xlsxSheet{
|
||||
Name: trimSheetName(name),
|
||||
SheetID: sheetID,
|
||||
ID: "rId" + strconv.Itoa(rid),
|
||||
|
@ -67,7 +73,7 @@ func (f *File) setWorkbook(name string, sheetID, rid int) {
|
|||
// getWorkbookPath provides a function to get the path of the workbook.xml in
|
||||
// the spreadsheet.
|
||||
func (f *File) getWorkbookPath() (path string) {
|
||||
if rels := f.relsReader("_rels/.rels"); rels != nil {
|
||||
if rels, _ := f.relsReader("_rels/.rels"); rels != nil {
|
||||
rels.Lock()
|
||||
defer rels.Unlock()
|
||||
for _, rel := range rels.Relationships {
|
||||
|
@ -95,7 +101,7 @@ func (f *File) getWorkbookRelsPath() (path string) {
|
|||
|
||||
// workbookReader provides a function to get the pointer to the workbook.xml
|
||||
// structure after deserialization.
|
||||
func (f *File) workbookReader() *xlsxWorkbook {
|
||||
func (f *File) workbookReader() (*xlsxWorkbook, error) {
|
||||
var err error
|
||||
if f.WorkBook == nil {
|
||||
wbPath := f.getWorkbookPath()
|
||||
|
@ -107,10 +113,10 @@ func (f *File) workbookReader() *xlsxWorkbook {
|
|||
}
|
||||
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(wbPath)))).
|
||||
Decode(f.WorkBook); err != nil && err != io.EOF {
|
||||
log.Printf("xml decode error: %s", err)
|
||||
return f.WorkBook, err
|
||||
}
|
||||
}
|
||||
return f.WorkBook
|
||||
return f.WorkBook, err
|
||||
}
|
||||
|
||||
// workBookWriter provides a function to save workbook.xml after serialize
|
||||
|
|
|
@ -9,7 +9,8 @@ import (
|
|||
func TestWorkbookProps(t *testing.T) {
|
||||
f := NewFile()
|
||||
assert.NoError(t, f.SetWorkbookProps(nil))
|
||||
wb := f.workbookReader()
|
||||
wb, err := f.workbookReader()
|
||||
assert.NoError(t, err)
|
||||
wb.WorkbookPr = nil
|
||||
expected := WorkbookPropsOptions{
|
||||
Date1904: boolPtr(true),
|
||||
|
@ -20,4 +21,13 @@ func TestWorkbookProps(t *testing.T) {
|
|||
opts, err := f.GetWorkbookProps()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expected, opts)
|
||||
// Test set workbook properties with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
assert.EqualError(t, f.SetWorkbookProps(&expected), "XML syntax error on line 1: invalid UTF-8")
|
||||
// Test get workbook properties with unsupported charset workbook.
|
||||
f.WorkBook = nil
|
||||
f.Pkg.Store(defaultXMLPathWorkbook, MacintoshCyrillicCharset)
|
||||
_, err = f.GetWorkbookProps()
|
||||
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue