Fix #724, standardize variable naming and update unit tests

This commit is contained in:
xuri 2020-11-10 23:48:09 +08:00
parent 5dd0b4aec2
commit 2514bb16c6
27 changed files with 439 additions and 437 deletions

View File

@ -13,6 +13,7 @@ go:
os: os:
- linux - linux
- osx - osx
- windows
env: env:
jobs: jobs:

View File

@ -51,7 +51,7 @@ func main() {
f.SetCellValue("Sheet1", "B2", 100) f.SetCellValue("Sheet1", "B2", 100)
// Set active sheet of the workbook. // Set active sheet of the workbook.
f.SetActiveSheet(index) f.SetActiveSheet(index)
// Save xlsx file by the given path. // Save spreadsheet by the given path.
if err := f.SaveAs("Book1.xlsx"); err != nil { if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err) fmt.Println(err)
} }
@ -124,7 +124,7 @@ func main() {
fmt.Println(err) fmt.Println(err)
return return
} }
// Save xlsx file by the given path. // Save spreadsheet by the given path.
if err := f.SaveAs("Book1.xlsx"); err != nil { if err := f.SaveAs("Book1.xlsx"); err != nil {
fmt.Println(err) fmt.Println(err)
} }
@ -163,7 +163,7 @@ func main() {
if err := f.AddPicture("Sheet1", "H2", "image.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`); err != nil { if err := f.AddPicture("Sheet1", "H2", "image.gif", `{"x_offset": 15, "y_offset": 10, "print_obj": true, "lock_aspect_ratio": false, "locked": false}`); err != nil {
fmt.Println(err) fmt.Println(err)
} }
// Save the xlsx file with the origin path. // Save the spreadsheet with the origin path.
if err = f.Save(); err != nil { if err = f.Save(); err != nil {
fmt.Println(err) fmt.Println(err)
} }

View File

@ -35,30 +35,30 @@ const (
// TODO: adjustPageBreaks, adjustComments, adjustDataValidations, adjustProtectedCells // TODO: adjustPageBreaks, adjustComments, adjustDataValidations, adjustProtectedCells
// //
func (f *File) adjustHelper(sheet string, dir adjustDirection, num, offset int) error { func (f *File) adjustHelper(sheet string, dir adjustDirection, num, offset int) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
if dir == rows { if dir == rows {
f.adjustRowDimensions(xlsx, num, offset) f.adjustRowDimensions(ws, num, offset)
} else { } else {
f.adjustColDimensions(xlsx, num, offset) f.adjustColDimensions(ws, num, offset)
} }
f.adjustHyperlinks(xlsx, sheet, dir, num, offset) f.adjustHyperlinks(ws, sheet, dir, num, offset)
if err = f.adjustMergeCells(xlsx, dir, num, offset); err != nil { if err = f.adjustMergeCells(ws, dir, num, offset); err != nil {
return err return err
} }
if err = f.adjustAutoFilter(xlsx, dir, num, offset); err != nil { if err = f.adjustAutoFilter(ws, dir, num, offset); err != nil {
return err return err
} }
if err = f.adjustCalcChain(dir, num, offset); err != nil { if err = f.adjustCalcChain(dir, num, offset); err != nil {
return err return err
} }
checkSheet(xlsx) checkSheet(ws)
_ = checkRow(xlsx) _ = checkRow(ws)
if xlsx.MergeCells != nil && len(xlsx.MergeCells.Cells) == 0 { if ws.MergeCells != nil && len(ws.MergeCells.Cells) == 0 {
xlsx.MergeCells = nil ws.MergeCells = nil
} }
return nil return nil
@ -66,13 +66,13 @@ func (f *File) adjustHelper(sheet string, dir adjustDirection, num, offset int)
// adjustColDimensions provides a function to update column dimensions when // adjustColDimensions provides a function to update column dimensions when
// inserting or deleting rows or columns. // inserting or deleting rows or columns.
func (f *File) adjustColDimensions(xlsx *xlsxWorksheet, col, offset int) { func (f *File) adjustColDimensions(ws *xlsxWorksheet, col, offset int) {
for rowIdx := range xlsx.SheetData.Row { for rowIdx := range ws.SheetData.Row {
for colIdx, v := range xlsx.SheetData.Row[rowIdx].C { for colIdx, v := range ws.SheetData.Row[rowIdx].C {
cellCol, cellRow, _ := CellNameToCoordinates(v.R) cellCol, cellRow, _ := CellNameToCoordinates(v.R)
if col <= cellCol { if col <= cellCol {
if newCol := cellCol + offset; newCol > 0 { if newCol := cellCol + offset; newCol > 0 {
xlsx.SheetData.Row[rowIdx].C[colIdx].R, _ = CoordinatesToCellName(newCol, cellRow) ws.SheetData.Row[rowIdx].C[colIdx].R, _ = CoordinatesToCellName(newCol, cellRow)
} }
} }
} }
@ -81,9 +81,9 @@ func (f *File) adjustColDimensions(xlsx *xlsxWorksheet, col, offset int) {
// adjustRowDimensions provides a function to update row dimensions when // adjustRowDimensions provides a function to update row dimensions when
// inserting or deleting rows or columns. // inserting or deleting rows or columns.
func (f *File) adjustRowDimensions(xlsx *xlsxWorksheet, row, offset int) { func (f *File) adjustRowDimensions(ws *xlsxWorksheet, row, offset int) {
for i := range xlsx.SheetData.Row { for i := range ws.SheetData.Row {
r := &xlsx.SheetData.Row[i] r := &ws.SheetData.Row[i]
if newRow := r.R + offset; r.R >= row && newRow > 0 { if newRow := r.R + offset; r.R >= row && newRow > 0 {
f.ajustSingleRowDimensions(r, newRow) f.ajustSingleRowDimensions(r, newRow)
} }
@ -101,38 +101,35 @@ func (f *File) ajustSingleRowDimensions(r *xlsxRow, num int) {
// adjustHyperlinks provides a function to update hyperlinks when inserting or // adjustHyperlinks provides a function to update hyperlinks when inserting or
// deleting rows or columns. // deleting rows or columns.
func (f *File) adjustHyperlinks(xlsx *xlsxWorksheet, sheet string, dir adjustDirection, num, offset int) { func (f *File) adjustHyperlinks(ws *xlsxWorksheet, sheet string, dir adjustDirection, num, offset int) {
// short path // short path
if xlsx.Hyperlinks == nil || len(xlsx.Hyperlinks.Hyperlink) == 0 { if ws.Hyperlinks == nil || len(ws.Hyperlinks.Hyperlink) == 0 {
return return
} }
// order is important // order is important
if offset < 0 { if offset < 0 {
for i := len(xlsx.Hyperlinks.Hyperlink) - 1; i >= 0; i-- { for i := len(ws.Hyperlinks.Hyperlink) - 1; i >= 0; i-- {
linkData := xlsx.Hyperlinks.Hyperlink[i] linkData := ws.Hyperlinks.Hyperlink[i]
colNum, rowNum, _ := CellNameToCoordinates(linkData.Ref) colNum, rowNum, _ := CellNameToCoordinates(linkData.Ref)
if (dir == rows && num == rowNum) || (dir == columns && num == colNum) { if (dir == rows && num == rowNum) || (dir == columns && num == colNum) {
f.deleteSheetRelationships(sheet, linkData.RID) f.deleteSheetRelationships(sheet, linkData.RID)
if len(xlsx.Hyperlinks.Hyperlink) > 1 { if len(ws.Hyperlinks.Hyperlink) > 1 {
xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink[:i], ws.Hyperlinks.Hyperlink = append(ws.Hyperlinks.Hyperlink[:i],
xlsx.Hyperlinks.Hyperlink[i+1:]...) ws.Hyperlinks.Hyperlink[i+1:]...)
} else { } else {
xlsx.Hyperlinks = nil ws.Hyperlinks = nil
} }
} }
} }
} }
if ws.Hyperlinks == nil {
if xlsx.Hyperlinks == nil {
return return
} }
for i := range ws.Hyperlinks.Hyperlink {
for i := range xlsx.Hyperlinks.Hyperlink { link := &ws.Hyperlinks.Hyperlink[i] // get reference
link := &xlsx.Hyperlinks.Hyperlink[i] // get reference
colNum, rowNum, _ := CellNameToCoordinates(link.Ref) colNum, rowNum, _ := CellNameToCoordinates(link.Ref)
if dir == rows { if dir == rows {
if rowNum >= num { if rowNum >= num {
link.Ref, _ = CoordinatesToCellName(colNum, rowNum+offset) link.Ref, _ = CoordinatesToCellName(colNum, rowNum+offset)
@ -147,21 +144,21 @@ func (f *File) adjustHyperlinks(xlsx *xlsxWorksheet, sheet string, dir adjustDir
// adjustAutoFilter provides a function to update the auto filter when // adjustAutoFilter provides a function to update the auto filter when
// inserting or deleting rows or columns. // inserting or deleting rows or columns.
func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, offset int) error { func (f *File) adjustAutoFilter(ws *xlsxWorksheet, dir adjustDirection, num, offset int) error {
if xlsx.AutoFilter == nil { if ws.AutoFilter == nil {
return nil return nil
} }
coordinates, err := f.areaRefToCoordinates(xlsx.AutoFilter.Ref) coordinates, err := f.areaRefToCoordinates(ws.AutoFilter.Ref)
if err != nil { if err != nil {
return err return err
} }
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3] x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
if (dir == rows && y1 == num && offset < 0) || (dir == columns && x1 == num && x2 == num) { if (dir == rows && y1 == num && offset < 0) || (dir == columns && x1 == num && x2 == num) {
xlsx.AutoFilter = nil ws.AutoFilter = nil
for rowIdx := range xlsx.SheetData.Row { for rowIdx := range ws.SheetData.Row {
rowData := &xlsx.SheetData.Row[rowIdx] rowData := &ws.SheetData.Row[rowIdx]
if rowData.R > y1 && rowData.R <= y2 { if rowData.R > y1 && rowData.R <= y2 {
rowData.Hidden = false rowData.Hidden = false
} }
@ -172,7 +169,7 @@ func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, o
coordinates = f.adjustAutoFilterHelper(dir, coordinates, num, offset) coordinates = f.adjustAutoFilterHelper(dir, coordinates, num, offset)
x1, y1, x2, y2 = coordinates[0], coordinates[1], coordinates[2], coordinates[3] x1, y1, x2, y2 = coordinates[0], coordinates[1], coordinates[2], coordinates[3]
if xlsx.AutoFilter.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil { if ws.AutoFilter.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil {
return err return err
} }
return nil return nil
@ -251,13 +248,13 @@ func (f *File) coordinatesToAreaRef(coordinates []int) (string, error) {
// adjustMergeCells provides a function to update merged cells when inserting // adjustMergeCells provides a function to update merged cells when inserting
// or deleting rows or columns. // or deleting rows or columns.
func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, dir adjustDirection, num, offset int) error { func (f *File) adjustMergeCells(ws *xlsxWorksheet, dir adjustDirection, num, offset int) error {
if xlsx.MergeCells == nil { if ws.MergeCells == nil {
return nil return nil
} }
for i := 0; i < len(xlsx.MergeCells.Cells); i++ { for i := 0; i < len(ws.MergeCells.Cells); i++ {
areaData := xlsx.MergeCells.Cells[i] areaData := ws.MergeCells.Cells[i]
coordinates, err := f.areaRefToCoordinates(areaData.Ref) coordinates, err := f.areaRefToCoordinates(areaData.Ref)
if err != nil { if err != nil {
return err return err
@ -265,21 +262,21 @@ func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, dir adjustDirection, num, o
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3] x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
if dir == rows { if dir == rows {
if y1 == num && y2 == num && offset < 0 { if y1 == num && y2 == num && offset < 0 {
f.deleteMergeCell(xlsx, i) f.deleteMergeCell(ws, i)
i-- i--
} }
y1 = f.adjustMergeCellsHelper(y1, num, offset) y1 = f.adjustMergeCellsHelper(y1, num, offset)
y2 = f.adjustMergeCellsHelper(y2, num, offset) y2 = f.adjustMergeCellsHelper(y2, num, offset)
} else { } else {
if x1 == num && x2 == num && offset < 0 { if x1 == num && x2 == num && offset < 0 {
f.deleteMergeCell(xlsx, i) f.deleteMergeCell(ws, i)
i-- i--
} }
x1 = f.adjustMergeCellsHelper(x1, num, offset) x1 = f.adjustMergeCellsHelper(x1, num, offset)
x2 = f.adjustMergeCellsHelper(x2, num, offset) x2 = f.adjustMergeCellsHelper(x2, num, offset)
} }
if x1 == x2 && y1 == y2 { if x1 == x2 && y1 == y2 {
f.deleteMergeCell(xlsx, i) f.deleteMergeCell(ws, i)
i-- i--
} }
if areaData.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil { if areaData.Ref, err = f.coordinatesToAreaRef([]int{x1, y1, x2, y2}); err != nil {
@ -304,10 +301,10 @@ func (f *File) adjustMergeCellsHelper(pivot, num, offset int) int {
} }
// deleteMergeCell provides a function to delete merged cell by given index. // deleteMergeCell provides a function to delete merged cell by given index.
func (f *File) deleteMergeCell(sheet *xlsxWorksheet, idx int) { func (f *File) deleteMergeCell(ws *xlsxWorksheet, idx int) {
if len(sheet.MergeCells.Cells) > idx { if len(ws.MergeCells.Cells) > idx {
sheet.MergeCells.Cells = append(sheet.MergeCells.Cells[:idx], sheet.MergeCells.Cells[idx+1:]...) ws.MergeCells.Cells = append(ws.MergeCells.Cells[:idx], ws.MergeCells.Cells[idx+1:]...)
sheet.MergeCells.Count = len(sheet.MergeCells.Cells) ws.MergeCells.Count = len(ws.MergeCells.Cells)
} }
} }

View File

@ -7,6 +7,7 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/xuri/efp"
) )
func TestCalcCellValue(t *testing.T) { func TestCalcCellValue(t *testing.T) {
@ -854,6 +855,18 @@ func TestCalcCellValue(t *testing.T) {
} }
func TestCalculate(t *testing.T) {
err := `strconv.ParseFloat: parsing "string": invalid syntax`
opd := NewStack()
opd.Push(efp.Token{TValue: "string"})
opt := efp.Token{TValue: "-", TType: efp.TokenTypeOperatorPrefix}
assert.EqualError(t, calculate(opd, opt), err)
opd.Push(efp.Token{TValue: "string"})
opd.Push(efp.Token{TValue: "string"})
opt = efp.Token{TValue: "-", TType: efp.TokenTypeOperatorInfix}
assert.EqualError(t, calculate(opd, opt), err)
}
func TestCalcCellValueWithDefinedName(t *testing.T) { func TestCalcCellValueWithDefinedName(t *testing.T) {
cellData := [][]interface{}{ cellData := [][]interface{}{
{"A1 value", "B1 value", nil}, {"A1 value", "B1 value", nil},

112
cell.go
View File

@ -131,15 +131,15 @@ func (f *File) setCellIntFunc(sheet, axis string, value interface{}) error {
// setCellTimeFunc provides a method to process time type of value for // setCellTimeFunc provides a method to process time type of value for
// SetCellValue. // SetCellValue.
func (f *File) setCellTimeFunc(sheet, axis string, value time.Time) error { func (f *File) setCellTimeFunc(sheet, axis string, value time.Time) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis) cellData, col, _, err := f.prepareCell(ws, sheet, axis)
if err != nil { if err != nil {
return err return err
} }
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S) cellData.S = f.prepareCellStyle(ws, col, cellData.S)
var isNum bool var isNum bool
cellData.T, cellData.V, isNum, err = setCellTime(value) cellData.T, cellData.V, isNum, err = setCellTime(value)
@ -178,15 +178,15 @@ func setCellDuration(value time.Duration) (t string, v string) {
// SetCellInt provides a function to set int type value of a cell by given // SetCellInt provides a function to set int type value of a cell by given
// worksheet name, cell coordinates and cell value. // worksheet name, cell coordinates and cell value.
func (f *File) SetCellInt(sheet, axis string, value int) error { func (f *File) SetCellInt(sheet, axis string, value int) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis) cellData, col, _, err := f.prepareCell(ws, sheet, axis)
if err != nil { if err != nil {
return err return err
} }
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S) cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.T, cellData.V = setCellInt(value) cellData.T, cellData.V = setCellInt(value)
return err return err
} }
@ -199,15 +199,15 @@ func setCellInt(value int) (t string, v string) {
// SetCellBool provides a function to set bool type value of a cell by given // SetCellBool provides a function to set bool type value of a cell by given
// worksheet name, cell name and cell value. // worksheet name, cell name and cell value.
func (f *File) SetCellBool(sheet, axis string, value bool) error { func (f *File) SetCellBool(sheet, axis string, value bool) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis) cellData, col, _, err := f.prepareCell(ws, sheet, axis)
if err != nil { if err != nil {
return err return err
} }
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S) cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.T, cellData.V = setCellBool(value) cellData.T, cellData.V = setCellBool(value)
return err return err
} }
@ -232,15 +232,15 @@ func setCellBool(value bool) (t string, v string) {
// f.SetCellFloat("Sheet1", "A1", float64(x), 2, 32) // f.SetCellFloat("Sheet1", "A1", float64(x), 2, 32)
// //
func (f *File) SetCellFloat(sheet, axis string, value float64, prec, bitSize int) error { func (f *File) SetCellFloat(sheet, axis string, value float64, prec, bitSize int) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis) cellData, col, _, err := f.prepareCell(ws, sheet, axis)
if err != nil { if err != nil {
return err return err
} }
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S) cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.T, cellData.V = setCellFloat(value, prec, bitSize) cellData.T, cellData.V = setCellFloat(value, prec, bitSize)
return err return err
} }
@ -253,15 +253,15 @@ func setCellFloat(value float64, prec, bitSize int) (t string, v string) {
// SetCellStr provides a function to set string type value of a cell. Total // SetCellStr provides a function to set string type value of a cell. Total
// number of characters that a cell can contain 32767 characters. // number of characters that a cell can contain 32767 characters.
func (f *File) SetCellStr(sheet, axis, value string) error { func (f *File) SetCellStr(sheet, axis, value string) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis) cellData, col, _, err := f.prepareCell(ws, sheet, axis)
if err != nil { if err != nil {
return err return err
} }
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S) cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.T, cellData.V = f.setCellString(value) cellData.T, cellData.V = f.setCellString(value)
return err return err
} }
@ -321,15 +321,15 @@ func setCellStr(value string) (t string, v string, ns xml.Attr) {
// SetCellDefault provides a function to set string type value of a cell as // SetCellDefault provides a function to set string type value of a cell as
// default format without escaping the cell. // default format without escaping the cell.
func (f *File) SetCellDefault(sheet, axis, value string) error { func (f *File) SetCellDefault(sheet, axis, value string) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis) cellData, col, _, err := f.prepareCell(ws, sheet, axis)
if err != nil { if err != nil {
return err return err
} }
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S) cellData.S = f.prepareCellStyle(ws, col, cellData.S)
cellData.T, cellData.V = setCellDefault(value) cellData.T, cellData.V = setCellDefault(value)
return err return err
} }
@ -362,11 +362,11 @@ type FormulaOpts struct {
// SetCellFormula provides a function to set cell formula by given string and // SetCellFormula provides a function to set cell formula by given string and
// worksheet name. // worksheet name.
func (f *File) SetCellFormula(sheet, axis, formula string, opts ...FormulaOpts) error { func (f *File) SetCellFormula(sheet, axis, formula string, opts ...FormulaOpts) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
cellData, _, _, err := f.prepareCell(xlsx, sheet, axis) cellData, _, _, err := f.prepareCell(ws, sheet, axis)
if err != nil { if err != nil {
return err return err
} }
@ -409,16 +409,16 @@ func (f *File) GetCellHyperLink(sheet, axis string) (bool, string, error) {
return false, "", err return false, "", err
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return false, "", err return false, "", err
} }
axis, err = f.mergeCellsParser(xlsx, axis) axis, err = f.mergeCellsParser(ws, axis)
if err != nil { if err != nil {
return false, "", err return false, "", err
} }
if xlsx.Hyperlinks != nil { if ws.Hyperlinks != nil {
for _, link := range xlsx.Hyperlinks.Hyperlink { for _, link := range ws.Hyperlinks.Hyperlink {
if link.Ref == axis { if link.Ref == axis {
if link.RID != "" { if link.RID != "" {
return true, f.getSheetRelationshipsTargetByID(sheet, link.RID), err return true, f.getSheetRelationshipsTargetByID(sheet, link.RID), err
@ -451,22 +451,22 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) error {
return err return err
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
axis, err = f.mergeCellsParser(xlsx, axis) axis, err = f.mergeCellsParser(ws, axis)
if err != nil { if err != nil {
return err return err
} }
var linkData xlsxHyperlink var linkData xlsxHyperlink
if xlsx.Hyperlinks == nil { if ws.Hyperlinks == nil {
xlsx.Hyperlinks = new(xlsxHyperlinks) ws.Hyperlinks = new(xlsxHyperlinks)
} }
if len(xlsx.Hyperlinks.Hyperlink) > TotalSheetHyperlinks { if len(ws.Hyperlinks.Hyperlink) > TotalSheetHyperlinks {
return errors.New("over maximum limit hyperlinks in a worksheet") return errors.New("over maximum limit hyperlinks in a worksheet")
} }
@ -489,7 +489,7 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) error {
return fmt.Errorf("invalid link type %q", linkType) return fmt.Errorf("invalid link type %q", linkType)
} }
xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink, linkData) ws.Hyperlinks.Hyperlink = append(ws.Hyperlinks.Hyperlink, linkData)
return nil return nil
} }
@ -685,11 +685,11 @@ func (f *File) SetSheetRow(sheet, axis string, slice interface{}) error {
} }
// getCellInfo does common preparation for all SetCell* methods. // getCellInfo does common preparation for all SetCell* methods.
func (f *File) prepareCell(xlsx *xlsxWorksheet, sheet, cell string) (*xlsxC, int, int, error) { func (f *File) prepareCell(ws *xlsxWorksheet, sheet, cell string) (*xlsxC, int, int, error) {
xlsx.Lock() ws.Lock()
defer xlsx.Unlock() defer ws.Unlock()
var err error var err error
cell, err = f.mergeCellsParser(xlsx, cell) cell, err = f.mergeCellsParser(ws, cell)
if err != nil { if err != nil {
return nil, 0, 0, err return nil, 0, 0, err
} }
@ -698,19 +698,19 @@ func (f *File) prepareCell(xlsx *xlsxWorksheet, sheet, cell string) (*xlsxC, int
return nil, 0, 0, err return nil, 0, 0, err
} }
prepareSheetXML(xlsx, col, row) prepareSheetXML(ws, col, row)
return &xlsx.SheetData.Row[row-1].C[col-1], col, row, err return &ws.SheetData.Row[row-1].C[col-1], col, row, err
} }
// getCellStringFunc does common value extraction workflow for all GetCell* // getCellStringFunc does common value extraction workflow for all GetCell*
// methods. Passed function implements specific part of required logic. // methods. Passed function implements specific part of required logic.
func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c *xlsxC) (string, bool, error)) (string, error) { func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c *xlsxC) (string, bool, error)) (string, error) {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return "", err return "", err
} }
axis, err = f.mergeCellsParser(xlsx, axis) axis, err = f.mergeCellsParser(ws, axis)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -719,12 +719,12 @@ func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c
return "", err return "", err
} }
xlsx.Lock() ws.Lock()
defer xlsx.Unlock() defer ws.Unlock()
lastRowNum := 0 lastRowNum := 0
if l := len(xlsx.SheetData.Row); l > 0 { if l := len(ws.SheetData.Row); l > 0 {
lastRowNum = xlsx.SheetData.Row[l-1].R lastRowNum = ws.SheetData.Row[l-1].R
} }
// keep in mind: row starts from 1 // keep in mind: row starts from 1
@ -732,8 +732,8 @@ func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c
return "", nil return "", nil
} }
for rowIdx := range xlsx.SheetData.Row { for rowIdx := range ws.SheetData.Row {
rowData := &xlsx.SheetData.Row[rowIdx] rowData := &ws.SheetData.Row[rowIdx]
if rowData.R != row { if rowData.R != row {
continue continue
} }
@ -742,7 +742,7 @@ func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c
if axis != colData.R { if axis != colData.R {
continue continue
} }
val, ok, err := fn(xlsx, colData) val, ok, err := fn(ws, colData)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -776,7 +776,7 @@ func (f *File) formattedValue(s int, v string) string {
for _, xlsxFmt := range styleSheet.NumFmts.NumFmt { for _, xlsxFmt := range styleSheet.NumFmts.NumFmt {
if xlsxFmt.NumFmtID == numFmtId { if xlsxFmt.NumFmtID == numFmtId {
format := strings.ToLower(xlsxFmt.FormatCode) format := strings.ToLower(xlsxFmt.FormatCode)
if strings.Contains(format, "y") || strings.Contains(format, "m") || strings.Contains(format, "d") || strings.Contains(format, "h") { if strings.Contains(format, "y") || strings.Contains(format, "m") || strings.Contains(strings.Replace(format, "red", "", -1), "d") || strings.Contains(format, "h") {
return parseTime(v, format) return parseTime(v, format)
} }
@ -788,9 +788,9 @@ func (f *File) formattedValue(s int, v string) string {
// prepareCellStyle provides a function to prepare style index of cell in // prepareCellStyle provides a function to prepare style index of cell in
// worksheet by given column index and style index. // worksheet by given column index and style index.
func (f *File) prepareCellStyle(xlsx *xlsxWorksheet, col, style int) int { func (f *File) prepareCellStyle(ws *xlsxWorksheet, col, style int) int {
if xlsx.Cols != nil && style == 0 { if ws.Cols != nil && style == 0 {
for _, c := range xlsx.Cols.Col { for _, c := range ws.Cols.Col {
if c.Min <= col && col <= c.Max { if c.Min <= col && col <= c.Max {
style = c.Style style = c.Style
} }
@ -801,16 +801,16 @@ func (f *File) prepareCellStyle(xlsx *xlsxWorksheet, col, style int) int {
// mergeCellsParser provides a function to check merged cells in worksheet by // mergeCellsParser provides a function to check merged cells in worksheet by
// given axis. // given axis.
func (f *File) mergeCellsParser(xlsx *xlsxWorksheet, axis string) (string, error) { func (f *File) mergeCellsParser(ws *xlsxWorksheet, axis string) (string, error) {
axis = strings.ToUpper(axis) axis = strings.ToUpper(axis)
if xlsx.MergeCells != nil { if ws.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ { for i := 0; i < len(ws.MergeCells.Cells); i++ {
ok, err := f.checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) ok, err := f.checkCellInArea(axis, ws.MergeCells.Cells[i].Ref)
if err != nil { if err != nil {
return axis, err return axis, err
} }
if ok { if ok {
axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0] axis = strings.Split(ws.MergeCells.Cells[i].Ref, ":")[0]
} }
} }
} }
@ -863,8 +863,8 @@ func isOverlap(rect1, rect2 []int) bool {
// //
// Note that this function not validate ref tag to check the cell if or not in // Note that this function not validate ref tag to check the cell if or not in
// allow area, and always return origin shared formula. // allow area, and always return origin shared formula.
func getSharedForumula(xlsx *xlsxWorksheet, si string) string { func getSharedForumula(ws *xlsxWorksheet, si string) string {
for _, r := range xlsx.SheetData.Row { for _, r := range ws.SheetData.Row {
for _, c := range r.C { for _, c := range r.C {
if c.F != nil && c.F.Ref != "" && c.F.T == STCellFormulaTypeShared && c.F.Si == si { if c.F != nil && c.F.Ref != "" && c.F.T == STCellFormulaTypeShared && c.F.Si == si {
return c.F.Content return c.F.Content

View File

@ -527,7 +527,7 @@ func parseFormatChartSet(formatSet string) (*formatChart, error) {
// fmt.Println(err) // fmt.Println(err)
// return // return
// } // }
// // Save xlsx file by the given path. // // Save spreadsheet by the given path.
// if err := f.SaveAs("Book1.xlsx"); err != nil { // if err := f.SaveAs("Book1.xlsx"); err != nil {
// fmt.Println(err) // fmt.Println(err)
// } // }
@ -725,7 +725,7 @@ func parseFormatChartSet(formatSet string) (*formatChart, error) {
// fmt.Println(err) // fmt.Println(err)
// return // return
// } // }
// // Save xlsx file by the given path. // // Save spreadsheet file by the given path.
// if err := f.SaveAs("Book1.xlsx"); err != nil { // if err := f.SaveAs("Book1.xlsx"); err != nil {
// fmt.Println(err) // fmt.Println(err)
// } // }
@ -733,7 +733,7 @@ func parseFormatChartSet(formatSet string) (*formatChart, error) {
// //
func (f *File) AddChart(sheet, cell, format string, combo ...string) error { func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
// Read sheet data. // Read sheet data.
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -745,7 +745,7 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
drawingID := f.countDrawings() + 1 drawingID := f.countDrawings() + 1
chartID := f.countCharts() + 1 chartID := f.countCharts() + 1
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml" drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
drawingID, drawingXML = f.prepareDrawing(xlsx, drawingID, sheet, drawingXML) drawingID, drawingXML = f.prepareDrawing(ws, drawingID, sheet, drawingXML)
drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels" drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "") drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
err = f.addDrawingChart(sheet, drawingXML, cell, formatSet.Dimension.Width, formatSet.Dimension.Height, drawingRID, &formatSet.Format) err = f.addDrawingChart(sheet, drawingXML, cell, formatSet.Dimension.Width, formatSet.Dimension.Height, drawingRID, &formatSet.Format)

View File

@ -11,8 +11,8 @@ import (
) )
func TestChartSize(t *testing.T) { func TestChartSize(t *testing.T) {
xlsx := NewFile() f := NewFile()
sheet1 := xlsx.GetSheetName(0) sheet1 := f.GetSheetName(0)
categories := map[string]string{ categories := map[string]string{
"A2": "Small", "A2": "Small",
@ -23,7 +23,7 @@ func TestChartSize(t *testing.T) {
"D1": "Pear", "D1": "Pear",
} }
for cell, v := range categories { for cell, v := range categories {
assert.NoError(t, xlsx.SetCellValue(sheet1, cell, v)) assert.NoError(t, f.SetCellValue(sheet1, cell, v))
} }
values := map[string]int{ values := map[string]int{
@ -38,10 +38,10 @@ func TestChartSize(t *testing.T) {
"D4": 8, "D4": 8,
} }
for cell, v := range values { for cell, v := range values {
assert.NoError(t, xlsx.SetCellValue(sheet1, cell, v)) assert.NoError(t, f.SetCellValue(sheet1, cell, v))
} }
assert.NoError(t, xlsx.AddChart("Sheet1", "E4", `{"type":"col3DClustered","dimension":{"width":640, "height":480},`+ assert.NoError(t, f.AddChart("Sheet1", "E4", `{"type":"col3DClustered","dimension":{"width":640, "height":480},`+
`"series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},`+ `"series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},`+
`{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},`+ `{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},`+
`{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],`+ `{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],`+
@ -49,8 +49,8 @@ func TestChartSize(t *testing.T) {
var buffer bytes.Buffer var buffer bytes.Buffer
// Save xlsx file by the given path. // Save spreadsheet by the given path.
assert.NoError(t, xlsx.Write(&buffer)) assert.NoError(t, f.Write(&buffer))
newFile, err := OpenReader(&buffer) newFile, err := OpenReader(&buffer)
assert.NoError(t, err) assert.NoError(t, err)
@ -256,8 +256,8 @@ func TestDeleteChart(t *testing.T) {
func TestChartWithLogarithmicBase(t *testing.T) { func TestChartWithLogarithmicBase(t *testing.T) {
// Create test XLSX file with data // Create test XLSX file with data
xlsx := NewFile() f := NewFile()
sheet1 := xlsx.GetSheetName(0) sheet1 := f.GetSheetName(0)
categories := map[string]float64{ categories := map[string]float64{
"A1": 1, "A1": 1,
"A2": 2, "A2": 2,
@ -281,46 +281,46 @@ func TestChartWithLogarithmicBase(t *testing.T) {
"B10": 5000, "B10": 5000,
} }
for cell, v := range categories { for cell, v := range categories {
assert.NoError(t, xlsx.SetCellValue(sheet1, cell, v)) assert.NoError(t, f.SetCellValue(sheet1, cell, v))
} }
// Add two chart, one without and one with log scaling // Add two chart, one without and one with log scaling
assert.NoError(t, xlsx.AddChart(sheet1, "C1", assert.NoError(t, f.AddChart(sheet1, "C1",
`{"type":"line","dimension":{"width":640, "height":480},`+ `{"type":"line","dimension":{"width":640, "height":480},`+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+ `"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
`"title":{"name":"Line chart without log scaling"}}`)) `"title":{"name":"Line chart without log scaling"}}`))
assert.NoError(t, xlsx.AddChart(sheet1, "M1", assert.NoError(t, f.AddChart(sheet1, "M1",
`{"type":"line","dimension":{"width":640, "height":480},`+ `{"type":"line","dimension":{"width":640, "height":480},`+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+ `"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
`"y_axis":{"logbase":10.5},`+ `"y_axis":{"logbase":10.5},`+
`"title":{"name":"Line chart with log 10 scaling"}}`)) `"title":{"name":"Line chart with log 10 scaling"}}`))
assert.NoError(t, xlsx.AddChart(sheet1, "A25", assert.NoError(t, f.AddChart(sheet1, "A25",
`{"type":"line","dimension":{"width":320, "height":240},`+ `{"type":"line","dimension":{"width":320, "height":240},`+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+ `"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
`"y_axis":{"logbase":1.9},`+ `"y_axis":{"logbase":1.9},`+
`"title":{"name":"Line chart with log 1.9 scaling"}}`)) `"title":{"name":"Line chart with log 1.9 scaling"}}`))
assert.NoError(t, xlsx.AddChart(sheet1, "F25", assert.NoError(t, f.AddChart(sheet1, "F25",
`{"type":"line","dimension":{"width":320, "height":240},`+ `{"type":"line","dimension":{"width":320, "height":240},`+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+ `"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
`"y_axis":{"logbase":2},`+ `"y_axis":{"logbase":2},`+
`"title":{"name":"Line chart with log 2 scaling"}}`)) `"title":{"name":"Line chart with log 2 scaling"}}`))
assert.NoError(t, xlsx.AddChart(sheet1, "K25", assert.NoError(t, f.AddChart(sheet1, "K25",
`{"type":"line","dimension":{"width":320, "height":240},`+ `{"type":"line","dimension":{"width":320, "height":240},`+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+ `"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
`"y_axis":{"logbase":1000.1},`+ `"y_axis":{"logbase":1000.1},`+
`"title":{"name":"Line chart with log 1000.1 scaling"}}`)) `"title":{"name":"Line chart with log 1000.1 scaling"}}`))
assert.NoError(t, xlsx.AddChart(sheet1, "P25", assert.NoError(t, f.AddChart(sheet1, "P25",
`{"type":"line","dimension":{"width":320, "height":240},`+ `{"type":"line","dimension":{"width":320, "height":240},`+
`"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+ `"series":[{"name":"value","categories":"Sheet1!$A$1:$A$19","values":"Sheet1!$B$1:$B$10"}],`+
`"y_axis":{"logbase":1000},`+ `"y_axis":{"logbase":1000},`+
`"title":{"name":"Line chart with log 1000 scaling"}}`)) `"title":{"name":"Line chart with log 1000 scaling"}}`))
// Export XLSX file for human confirmation // Export XLSX file for human confirmation
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestChartWithLogarithmicBase10.xlsx"))) assert.NoError(t, f.SaveAs(filepath.Join("test", "TestChartWithLogarithmicBase10.xlsx")))
// Write the XLSX file to a buffer // Write the XLSX file to a buffer
var buffer bytes.Buffer var buffer bytes.Buffer
assert.NoError(t, xlsx.Write(&buffer)) assert.NoError(t, f.Write(&buffer))
// Read back the XLSX file from the buffer // Read back the XLSX file from the buffer
newFile, err := OpenReader(&buffer) newFile, err := OpenReader(&buffer)

62
col.go
View File

@ -224,16 +224,16 @@ func (f *File) GetColVisible(sheet, col string) (bool, error) {
return visible, err return visible, err
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return false, err return false, err
} }
if xlsx.Cols == nil { if ws.Cols == nil {
return visible, err return visible, err
} }
for c := range xlsx.Cols.Col { for c := range ws.Cols.Col {
colData := &xlsx.Cols.Col[c] colData := &ws.Cols.Col[c]
if colData.Min <= colNum && colNum <= colData.Max { if colData.Min <= colNum && colNum <= colData.Max {
visible = !colData.Hidden visible = !colData.Hidden
} }
@ -271,7 +271,7 @@ func (f *File) SetColVisible(sheet, columns string, visible bool) error {
if max < min { if max < min {
min, max = max, min min, max = max, min
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -282,13 +282,13 @@ func (f *File) SetColVisible(sheet, columns string, visible bool) error {
Hidden: !visible, Hidden: !visible,
CustomWidth: true, CustomWidth: true,
} }
if xlsx.Cols == nil { if ws.Cols == nil {
cols := xlsxCols{} cols := xlsxCols{}
cols.Col = append(cols.Col, colData) cols.Col = append(cols.Col, colData)
xlsx.Cols = &cols ws.Cols = &cols
return nil return nil
} }
xlsx.Cols.Col = flatCols(colData, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol { ws.Cols.Col = flatCols(colData, ws.Cols.Col, func(fc, c xlsxCol) xlsxCol {
fc.BestFit = c.BestFit fc.BestFit = c.BestFit
fc.Collapsed = c.Collapsed fc.Collapsed = c.Collapsed
fc.CustomWidth = c.CustomWidth fc.CustomWidth = c.CustomWidth
@ -313,15 +313,15 @@ func (f *File) GetColOutlineLevel(sheet, col string) (uint8, error) {
if err != nil { if err != nil {
return level, err return level, err
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if xlsx.Cols == nil { if ws.Cols == nil {
return level, err return level, err
} }
for c := range xlsx.Cols.Col { for c := range ws.Cols.Col {
colData := &xlsx.Cols.Col[c] colData := &ws.Cols.Col[c]
if colData.Min <= colNum && colNum <= colData.Max { if colData.Min <= colNum && colNum <= colData.Max {
level = colData.OutlineLevel level = colData.OutlineLevel
} }
@ -349,17 +349,17 @@ func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
OutlineLevel: level, OutlineLevel: level,
CustomWidth: true, CustomWidth: true,
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
if xlsx.Cols == nil { if ws.Cols == nil {
cols := xlsxCols{} cols := xlsxCols{}
cols.Col = append(cols.Col, colData) cols.Col = append(cols.Col, colData)
xlsx.Cols = &cols ws.Cols = &cols
return err return err
} }
xlsx.Cols.Col = flatCols(colData, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol { ws.Cols.Col = flatCols(colData, ws.Cols.Col, func(fc, c xlsxCol) xlsxCol {
fc.BestFit = c.BestFit fc.BestFit = c.BestFit
fc.Collapsed = c.Collapsed fc.Collapsed = c.Collapsed
fc.CustomWidth = c.CustomWidth fc.CustomWidth = c.CustomWidth
@ -384,7 +384,7 @@ func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
// err = f.SetColStyle("Sheet1", "C:F", style) // err = f.SetColStyle("Sheet1", "C:F", style)
// //
func (f *File) SetColStyle(sheet, columns string, styleID int) error { func (f *File) SetColStyle(sheet, columns string, styleID int) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -408,15 +408,15 @@ func (f *File) SetColStyle(sheet, columns string, styleID int) error {
if max < min { if max < min {
min, max = max, min min, max = max, min
} }
if xlsx.Cols == nil { if ws.Cols == nil {
xlsx.Cols = &xlsxCols{} ws.Cols = &xlsxCols{}
} }
xlsx.Cols.Col = flatCols(xlsxCol{ ws.Cols.Col = flatCols(xlsxCol{
Min: min, Min: min,
Max: max, Max: max,
Width: 9, Width: 9,
Style: styleID, Style: styleID,
}, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol { }, ws.Cols.Col, func(fc, c xlsxCol) xlsxCol {
fc.BestFit = c.BestFit fc.BestFit = c.BestFit
fc.Collapsed = c.Collapsed fc.Collapsed = c.Collapsed
fc.CustomWidth = c.CustomWidth fc.CustomWidth = c.CustomWidth
@ -451,7 +451,7 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) error
min, max = max, min min, max = max, min
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -461,13 +461,13 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) error
Width: width, Width: width,
CustomWidth: true, CustomWidth: true,
} }
if xlsx.Cols == nil { if ws.Cols == nil {
cols := xlsxCols{} cols := xlsxCols{}
cols.Col = append(cols.Col, col) cols.Col = append(cols.Col, col)
xlsx.Cols = &cols ws.Cols = &cols
return err return err
} }
xlsx.Cols.Col = flatCols(col, xlsx.Cols.Col, func(fc, c xlsxCol) xlsxCol { ws.Cols.Col = flatCols(col, ws.Cols.Col, func(fc, c xlsxCol) xlsxCol {
fc.BestFit = c.BestFit fc.BestFit = c.BestFit
fc.Collapsed = c.Collapsed fc.Collapsed = c.Collapsed
fc.Hidden = c.Hidden fc.Hidden = c.Hidden
@ -623,13 +623,13 @@ func (f *File) GetColWidth(sheet, col string) (float64, error) {
if err != nil { if err != nil {
return defaultColWidthPixels, err return defaultColWidthPixels, err
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return defaultColWidthPixels, err return defaultColWidthPixels, err
} }
if xlsx.Cols != nil { if ws.Cols != nil {
var width float64 var width float64
for _, v := range xlsx.Cols.Col { for _, v := range ws.Cols.Col {
if v.Min <= colNum && colNum <= v.Max { if v.Min <= colNum && colNum <= v.Max {
width = v.Width width = v.Width
} }
@ -670,12 +670,12 @@ func (f *File) RemoveCol(sheet, col string) error {
return err return err
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
for rowIdx := range xlsx.SheetData.Row { for rowIdx := range ws.SheetData.Row {
rowData := &xlsx.SheetData.Row[rowIdx] rowData := &ws.SheetData.Row[rowIdx]
for colIdx := range rowData.C { for colIdx := range rowData.C {
colName, _, _ := SplitCellName(rowData.C[colIdx].R) colName, _, _ := SplitCellName(rowData.C[colIdx].R)
if colName == col { if colName == col {

View File

@ -91,7 +91,7 @@ func (f *File) AddComment(sheet, cell, format string) error {
return err return err
} }
// Read sheet data. // Read sheet data.
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -99,9 +99,9 @@ func (f *File) AddComment(sheet, cell, format string) error {
drawingVML := "xl/drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml" drawingVML := "xl/drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
sheetRelationshipsComments := "../comments" + strconv.Itoa(commentID) + ".xml" sheetRelationshipsComments := "../comments" + strconv.Itoa(commentID) + ".xml"
sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml" sheetRelationshipsDrawingVML := "../drawings/vmlDrawing" + strconv.Itoa(commentID) + ".vml"
if xlsx.LegacyDrawing != nil { if ws.LegacyDrawing != nil {
// The worksheet already has a comments relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml. // The worksheet already has a comments relationships, use the relationships drawing ../drawings/vmlDrawing%d.vml.
sheetRelationshipsDrawingVML = f.getSheetRelationshipsTargetByID(sheet, xlsx.LegacyDrawing.RID) sheetRelationshipsDrawingVML = f.getSheetRelationshipsTargetByID(sheet, ws.LegacyDrawing.RID)
commentID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml")) commentID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingVML, "../drawings/vmlDrawing"), ".vml"))
drawingVML = strings.Replace(sheetRelationshipsDrawingVML, "..", "xl", -1) drawingVML = strings.Replace(sheetRelationshipsDrawingVML, "..", "xl", -1)
} else { } else {

View File

@ -17,7 +17,7 @@ var trueExpectedDateList = []dateTest{
{0.0000000000000000, time.Date(1899, time.December, 30, 0, 0, 0, 0, time.UTC)}, {0.0000000000000000, time.Date(1899, time.December, 30, 0, 0, 0, 0, time.UTC)},
{25569.000000000000, time.Unix(0, 0).UTC()}, {25569.000000000000, time.Unix(0, 0).UTC()},
// Expected values extracted from real xlsx file // Expected values extracted from real spreadsheet
{1.0000000000000000, time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC)}, {1.0000000000000000, time.Date(1900, time.January, 1, 0, 0, 0, 0, time.UTC)},
{1.0000115740740740, time.Date(1900, time.January, 1, 0, 0, 1, 0, time.UTC)}, {1.0000115740740740, time.Date(1900, time.January, 1, 0, 0, 1, 0, time.UTC)},
{1.0006944444444446, time.Date(1900, time.January, 1, 0, 1, 0, 0, time.UTC)}, {1.0006944444444446, time.Date(1900, time.January, 1, 0, 1, 0, 0, time.UTC)},

View File

@ -24,11 +24,11 @@ import (
// prepareDrawing provides a function to prepare drawing ID and XML by given // prepareDrawing provides a function to prepare drawing ID and XML by given
// drawingID, worksheet name and default drawingXML. // drawingID, worksheet name and default drawingXML.
func (f *File) prepareDrawing(xlsx *xlsxWorksheet, drawingID int, sheet, drawingXML string) (int, string) { func (f *File) prepareDrawing(ws *xlsxWorksheet, drawingID int, sheet, drawingXML string) (int, string) {
sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml" sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
if xlsx.Drawing != nil { if ws.Drawing != nil {
// The worksheet already has a picture or chart relationships, use the relationships drawing ../drawings/drawing%d.xml. // The worksheet already has a picture or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID) sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID)
drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml")) drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1) drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
} else { } else {
@ -42,13 +42,13 @@ func (f *File) prepareDrawing(xlsx *xlsxWorksheet, drawingID int, sheet, drawing
// prepareChartSheetDrawing provides a function to prepare drawing ID and XML // prepareChartSheetDrawing provides a function to prepare drawing ID and XML
// by given drawingID, worksheet name and default drawingXML. // by given drawingID, worksheet name and default drawingXML.
func (f *File) prepareChartSheetDrawing(xlsx *xlsxChartsheet, drawingID int, sheet string) { func (f *File) prepareChartSheetDrawing(cs *xlsxChartsheet, drawingID int, sheet string) {
sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml" sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
// Only allow one chart in a chartsheet. // Only allow one chart in a chartsheet.
sheetRels := "xl/chartsheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/chartsheets/") + ".rels" sheetRels := "xl/chartsheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/chartsheets/") + ".rels"
rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "") rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
f.addSheetNameSpace(sheet, SourceRelationship) f.addSheetNameSpace(sheet, SourceRelationship)
xlsx.Drawing = &xlsxDrawing{ cs.Drawing = &xlsxDrawing{
RID: "rId" + strconv.Itoa(rID), RID: "rId" + strconv.Itoa(rID),
} }
return return

View File

@ -166,7 +166,7 @@ func (f *File) setDefaultTimeStyle(sheet, axis string, format int) error {
// workSheetReader provides a function to get the pointer to the structure // workSheetReader provides a function to get the pointer to the structure
// after deserialization by given worksheet name. // after deserialization by given worksheet name.
func (f *File) workSheetReader(sheet string) (xlsx *xlsxWorksheet, err error) { func (f *File) workSheetReader(sheet string) (ws *xlsxWorksheet, err error) {
f.Lock() f.Lock()
defer f.Unlock() defer f.Unlock()
var ( var (
@ -178,18 +178,18 @@ func (f *File) workSheetReader(sheet string) (xlsx *xlsxWorksheet, err error) {
err = fmt.Errorf("sheet %s is not exist", sheet) err = fmt.Errorf("sheet %s is not exist", sheet)
return return
} }
if xlsx = f.Sheet[name]; f.Sheet[name] == nil { if ws = f.Sheet[name]; f.Sheet[name] == nil {
if strings.HasPrefix(name, "xl/chartsheets") { if strings.HasPrefix(name, "xl/chartsheets") {
err = fmt.Errorf("sheet %s is chart sheet", sheet) err = fmt.Errorf("sheet %s is chart sheet", sheet)
return return
} }
xlsx = new(xlsxWorksheet) ws = new(xlsxWorksheet)
if _, ok := f.xmlAttr[name]; !ok { if _, ok := f.xmlAttr[name]; !ok {
d := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(name)))) d := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(name))))
f.xmlAttr[name] = append(f.xmlAttr[name], getRootElement(d)...) f.xmlAttr[name] = append(f.xmlAttr[name], getRootElement(d)...)
} }
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(name)))). if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(name)))).
Decode(xlsx); err != nil && err != io.EOF { Decode(ws); err != nil && err != io.EOF {
err = fmt.Errorf("xml decode error: %s", err) err = fmt.Errorf("xml decode error: %s", err)
return return
} }
@ -198,13 +198,13 @@ func (f *File) workSheetReader(sheet string) (xlsx *xlsxWorksheet, err error) {
f.checked = make(map[string]bool) f.checked = make(map[string]bool)
} }
if ok = f.checked[name]; !ok { if ok = f.checked[name]; !ok {
checkSheet(xlsx) checkSheet(ws)
if err = checkRow(xlsx); err != nil { if err = checkRow(ws); err != nil {
return return
} }
f.checked[name] = true f.checked[name] = true
} }
f.Sheet[name] = xlsx f.Sheet[name] = ws
} }
return return
@ -212,9 +212,9 @@ func (f *File) workSheetReader(sheet string) (xlsx *xlsxWorksheet, err error) {
// checkSheet provides a function to fill each row element and make that is // checkSheet provides a function to fill each row element and make that is
// continuous in a worksheet of XML. // continuous in a worksheet of XML.
func checkSheet(xlsx *xlsxWorksheet) { func checkSheet(ws *xlsxWorksheet) {
var row int var row int
for _, r := range xlsx.SheetData.Row { for _, r := range ws.SheetData.Row {
if r.R != 0 && r.R > row { if r.R != 0 && r.R > row {
row = r.R row = r.R
continue continue
@ -223,7 +223,7 @@ func checkSheet(xlsx *xlsxWorksheet) {
} }
sheetData := xlsxSheetData{Row: make([]xlsxRow, row)} sheetData := xlsxSheetData{Row: make([]xlsxRow, row)}
row = 0 row = 0
for _, r := range xlsx.SheetData.Row { for _, r := range ws.SheetData.Row {
if r.R != 0 { if r.R != 0 {
sheetData.Row[r.R-1] = r sheetData.Row[r.R-1] = r
row = r.R row = r.R
@ -236,7 +236,7 @@ func checkSheet(xlsx *xlsxWorksheet) {
for i := 1; i <= row; i++ { for i := 1; i <= row; i++ {
sheetData.Row[i-1].R = i sheetData.Row[i-1].R = i
} }
xlsx.SheetData = sheetData ws.SheetData = sheetData
} }
// addRels provides a function to add relationships by given XML path, // addRels provides a function to add relationships by given XML path,

View File

@ -21,14 +21,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestCurrency(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
// f.NewSheet("Sheet3")
go f.SetCellValue("Sheet1", "A1", "value")
go f.SetCellValue("Sheet2", "A1", "value")
}
func TestOpenFile(t *testing.T) { func TestOpenFile(t *testing.T) {
// Test update the spreadsheet file. // Test update the spreadsheet file.
f, err := OpenFile(filepath.Join("test", "Book1.xlsx")) f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))

View File

@ -23,7 +23,7 @@ import (
// NewFile provides a function to create new file by default template. For // NewFile provides a function to create new file by default template. For
// example: // example:
// //
// xlsx := NewFile() // f := NewFile()
// //
func NewFile() *File { func NewFile() *File {
file := make(map[string][]byte) file := make(map[string][]byte)
@ -54,7 +54,7 @@ func NewFile() *File {
return f return f
} }
// Save provides a function to override the xlsx file with origin path. // Save provides a function to override the spreadsheet with origin path.
func (f *File) Save() error { func (f *File) Save() error {
if f.Path == "" { if f.Path == "" {
return fmt.Errorf("no path defined for file, consider File.WriteTo or File.Write") return fmt.Errorf("no path defined for file, consider File.WriteTo or File.Write")
@ -62,7 +62,7 @@ func (f *File) Save() error {
return f.SaveAs(f.Path) return f.SaveAs(f.Path)
} }
// SaveAs provides a function to create or update to an xlsx file at the // SaveAs provides a function to create or update to an spreadsheet at the
// provided path. // provided path.
func (f *File) SaveAs(name string, opt ...Options) error { func (f *File) SaveAs(name string, opt ...Options) error {
if len(name) > MaxFileNameLength { if len(name) > MaxFileNameLength {

View File

@ -24,7 +24,7 @@ func BenchmarkWrite(b *testing.B) {
} }
} }
} }
// Save xlsx file by the given path. // Save spreadsheet by the given path.
err := f.SaveAs("./test.xlsx") err := f.SaveAs("./test.xlsx")
if err != nil { if err != nil {
b.Error(err) b.Error(err)

View File

@ -47,14 +47,14 @@ func (f *File) MergeCell(sheet, hcell, vcell string) error {
hcell, _ = CoordinatesToCellName(rect1[0], rect1[1]) hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
vcell, _ = CoordinatesToCellName(rect1[2], rect1[3]) vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
ref := hcell + ":" + vcell ref := hcell + ":" + vcell
if xlsx.MergeCells != nil { if ws.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ { for i := 0; i < len(ws.MergeCells.Cells); i++ {
cellData := xlsx.MergeCells.Cells[i] cellData := ws.MergeCells.Cells[i]
if cellData == nil { if cellData == nil {
continue continue
} }
@ -70,7 +70,7 @@ func (f *File) MergeCell(sheet, hcell, vcell string) error {
// Delete the merged cells of the overlapping area. // Delete the merged cells of the overlapping area.
if isOverlap(rect1, rect2) { if isOverlap(rect1, rect2) {
xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...) ws.MergeCells.Cells = append(ws.MergeCells.Cells[:i], ws.MergeCells.Cells[i+1:]...)
i-- i--
if rect1[0] > rect2[0] { if rect1[0] > rect2[0] {
@ -93,11 +93,11 @@ func (f *File) MergeCell(sheet, hcell, vcell string) error {
ref = hcell + ":" + vcell ref = hcell + ":" + vcell
} }
} }
xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &xlsxMergeCell{Ref: ref}) ws.MergeCells.Cells = append(ws.MergeCells.Cells, &xlsxMergeCell{Ref: ref})
} else { } else {
xlsx.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ref}}} ws.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ref}}}
} }
xlsx.MergeCells.Count = len(xlsx.MergeCells.Cells) ws.MergeCells.Count = len(ws.MergeCells.Cells)
return err return err
} }
@ -108,7 +108,7 @@ func (f *File) MergeCell(sheet, hcell, vcell string) error {
// //
// Attention: overlapped areas will also be unmerged. // Attention: overlapped areas will also be unmerged.
func (f *File) UnmergeCell(sheet string, hcell, vcell string) error { func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -121,12 +121,12 @@ func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
_ = sortCoordinates(rect1) _ = sortCoordinates(rect1)
// return nil since no MergeCells in the sheet // return nil since no MergeCells in the sheet
if xlsx.MergeCells == nil { if ws.MergeCells == nil {
return nil return nil
} }
i := 0 i := 0
for _, cellData := range xlsx.MergeCells.Cells { for _, cellData := range ws.MergeCells.Cells {
if cellData == nil { if cellData == nil {
continue continue
} }
@ -143,11 +143,11 @@ func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
if isOverlap(rect1, rect2) { if isOverlap(rect1, rect2) {
continue continue
} }
xlsx.MergeCells.Cells[i] = cellData ws.MergeCells.Cells[i] = cellData
i++ i++
} }
xlsx.MergeCells.Cells = xlsx.MergeCells.Cells[:i] ws.MergeCells.Cells = ws.MergeCells.Cells[:i]
xlsx.MergeCells.Count = len(xlsx.MergeCells.Cells) ws.MergeCells.Count = len(ws.MergeCells.Cells)
return nil return nil
} }
@ -155,15 +155,15 @@ func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
// currently. // currently.
func (f *File) GetMergeCells(sheet string) ([]MergeCell, error) { func (f *File) GetMergeCells(sheet string) ([]MergeCell, error) {
var mergeCells []MergeCell var mergeCells []MergeCell
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return mergeCells, err return mergeCells, err
} }
if xlsx.MergeCells != nil { if ws.MergeCells != nil {
mergeCells = make([]MergeCell, 0, len(xlsx.MergeCells.Cells)) mergeCells = make([]MergeCell, 0, len(ws.MergeCells.Cells))
for i := range xlsx.MergeCells.Cells { for i := range ws.MergeCells.Cells {
ref := xlsx.MergeCells.Cells[i].Ref ref := ws.MergeCells.Cells[i].Ref
axis := strings.Split(ref, ":")[0] axis := strings.Split(ref, ":")[0]
val, _ := f.GetCellValue(sheet, axis) val, _ := f.GetCellValue(sheet, axis)
mergeCells = append(mergeCells, []string{ref, val}) mergeCells = append(mergeCells, []string{ref, val})

View File

@ -145,14 +145,14 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
return err return err
} }
// Read sheet data. // Read sheet data.
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
// Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder. // Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
drawingID := f.countDrawings() + 1 drawingID := f.countDrawings() + 1
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml" drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
drawingID, drawingXML = f.prepareDrawing(xlsx, drawingID, sheet, drawingXML) drawingID, drawingXML = f.prepareDrawing(ws, drawingID, sheet, drawingXML)
drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels" drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
mediaStr := ".." + strings.TrimPrefix(f.addMedia(file, ext), "xl") mediaStr := ".." + strings.TrimPrefix(f.addMedia(file, ext), "xl")
drawingRID := f.addRels(drawingRels, SourceRelationshipImage, mediaStr, hyperlinkType) drawingRID := f.addRels(drawingRels, SourceRelationshipImage, mediaStr, hyperlinkType)
@ -459,14 +459,14 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
} }
col-- col--
row-- row--
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
if xlsx.Drawing == nil { if ws.Drawing == nil {
return "", nil, err return "", nil, err
} }
target := f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID) target := f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID)
drawingXML := strings.Replace(target, "..", "xl", -1) drawingXML := strings.Replace(target, "..", "xl", -1)
_, ok := f.XLSX[drawingXML] _, ok := f.XLSX[drawingXML]
if !ok { if !ok {

123
rows.go
View File

@ -228,25 +228,25 @@ func (f *File) SetRowHeight(sheet string, row int, height float64) error {
if height > MaxRowHeight { if height > MaxRowHeight {
return errors.New("the height of the row must be smaller than or equal to 409 points") return errors.New("the height of the row must be smaller than or equal to 409 points")
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
prepareSheetXML(xlsx, 0, row) prepareSheetXML(ws, 0, row)
rowIdx := row - 1 rowIdx := row - 1
xlsx.SheetData.Row[rowIdx].Ht = height ws.SheetData.Row[rowIdx].Ht = height
xlsx.SheetData.Row[rowIdx].CustomHeight = true ws.SheetData.Row[rowIdx].CustomHeight = true
return nil return nil
} }
// getRowHeight provides a function to get row height in pixels by given sheet // getRowHeight provides a function to get row height in pixels by given sheet
// name and row index. // name and row index.
func (f *File) getRowHeight(sheet string, row int) int { func (f *File) getRowHeight(sheet string, row int) int {
xlsx, _ := f.workSheetReader(sheet) ws, _ := f.workSheetReader(sheet)
for i := range xlsx.SheetData.Row { for i := range ws.SheetData.Row {
v := &xlsx.SheetData.Row[i] v := &ws.SheetData.Row[i]
if v.R == row+1 && v.Ht != 0 { if v.R == row+1 && v.Ht != 0 {
return int(convertRowHeightToPixels(v.Ht)) return int(convertRowHeightToPixels(v.Ht))
} }
@ -322,28 +322,28 @@ func (f *File) sharedStringsReader() *xlsxSST {
} }
// getValueFrom return a value from a column/row cell, this function is // getValueFrom return a value from a column/row cell, this function is
// inteded to be used with for range on rows an argument with the xlsx opened // inteded to be used with for range on rows an argument with the spreadsheet
// file. // opened file.
func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) { func (c *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
f.Lock() f.Lock()
defer f.Unlock() defer f.Unlock()
switch xlsx.T { switch c.T {
case "s": case "s":
if xlsx.V != "" { if c.V != "" {
xlsxSI := 0 xlsxSI := 0
xlsxSI, _ = strconv.Atoi(xlsx.V) xlsxSI, _ = strconv.Atoi(c.V)
if len(d.SI) > xlsxSI { if len(d.SI) > xlsxSI {
return f.formattedValue(xlsx.S, d.SI[xlsxSI].String()), nil return f.formattedValue(c.S, d.SI[xlsxSI].String()), nil
} }
} }
return f.formattedValue(xlsx.S, xlsx.V), nil return f.formattedValue(c.S, c.V), nil
case "str": case "str":
return f.formattedValue(xlsx.S, xlsx.V), nil return f.formattedValue(c.S, c.V), nil
case "inlineStr": case "inlineStr":
if xlsx.IS != nil { if c.IS != nil {
return f.formattedValue(xlsx.S, xlsx.IS.String()), nil return f.formattedValue(c.S, c.IS.String()), nil
} }
return f.formattedValue(xlsx.S, xlsx.V), nil return f.formattedValue(c.S, c.V), nil
default: default:
// correct numeric values as legacy Excel app // correct numeric values as legacy Excel app
// https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel // https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel
@ -351,20 +351,19 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
// Although this number has a decimal representation that is an infinite string of ones, // Although this number has a decimal representation that is an infinite string of ones,
// Excel displays only the leading 15 figures. In the second line, the number one is added to the fraction, and again Excel displays only 15 figures. // Excel displays only the leading 15 figures. In the second line, the number one is added to the fraction, and again Excel displays only 15 figures.
const precision = 1000000000000000 const precision = 1000000000000000
if len(xlsx.V) > 16 { if len(c.V) > 16 {
num, err := strconv.ParseFloat(xlsx.V, 64) num, err := strconv.ParseFloat(c.V, 64)
if err != nil { if err != nil {
return "", err return "", err
} }
num = math.Round(num*precision) / precision num = math.Round(num*precision) / precision
val := fmt.Sprintf("%g", num) val := fmt.Sprintf("%g", num)
if val != xlsx.V { if val != c.V {
return f.formattedValue(xlsx.S, val), nil return f.formattedValue(c.S, val), nil
} }
} }
return f.formattedValue(c.S, c.V), nil
return f.formattedValue(xlsx.S, xlsx.V), nil
} }
} }
@ -378,12 +377,12 @@ func (f *File) SetRowVisible(sheet string, row int, visible bool) error {
return newInvalidRowNumberError(row) return newInvalidRowNumberError(row)
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
prepareSheetXML(xlsx, 0, row) prepareSheetXML(ws, 0, row)
xlsx.SheetData.Row[row-1].Hidden = !visible ws.SheetData.Row[row-1].Hidden = !visible
return nil return nil
} }
@ -398,14 +397,14 @@ func (f *File) GetRowVisible(sheet string, row int) (bool, error) {
return false, newInvalidRowNumberError(row) return false, newInvalidRowNumberError(row)
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return false, err return false, err
} }
if row > len(xlsx.SheetData.Row) { if row > len(ws.SheetData.Row) {
return false, nil return false, nil
} }
return !xlsx.SheetData.Row[row-1].Hidden, nil return !ws.SheetData.Row[row-1].Hidden, nil
} }
// SetRowOutlineLevel provides a function to set outline level number of a // SetRowOutlineLevel provides a function to set outline level number of a
@ -421,12 +420,12 @@ func (f *File) SetRowOutlineLevel(sheet string, row int, level uint8) error {
if level > 7 || level < 1 { if level > 7 || level < 1 {
return errors.New("invalid outline level") return errors.New("invalid outline level")
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
prepareSheetXML(xlsx, 0, row) prepareSheetXML(ws, 0, row)
xlsx.SheetData.Row[row-1].OutlineLevel = level ws.SheetData.Row[row-1].OutlineLevel = level
return nil return nil
} }
@ -440,14 +439,14 @@ func (f *File) GetRowOutlineLevel(sheet string, row int) (uint8, error) {
if row < 1 { if row < 1 {
return 0, newInvalidRowNumberError(row) return 0, newInvalidRowNumberError(row)
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if row > len(xlsx.SheetData.Row) { if row > len(ws.SheetData.Row) {
return 0, nil return 0, nil
} }
return xlsx.SheetData.Row[row-1].OutlineLevel, nil return ws.SheetData.Row[row-1].OutlineLevel, nil
} }
// RemoveRow provides a function to remove single row by given worksheet name // RemoveRow provides a function to remove single row by given worksheet name
@ -464,22 +463,22 @@ func (f *File) RemoveRow(sheet string, row int) error {
return newInvalidRowNumberError(row) return newInvalidRowNumberError(row)
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
if row > len(xlsx.SheetData.Row) { if row > len(ws.SheetData.Row) {
return f.adjustHelper(sheet, rows, row, -1) return f.adjustHelper(sheet, rows, row, -1)
} }
keep := 0 keep := 0
for rowIdx := 0; rowIdx < len(xlsx.SheetData.Row); rowIdx++ { for rowIdx := 0; rowIdx < len(ws.SheetData.Row); rowIdx++ {
v := &xlsx.SheetData.Row[rowIdx] v := &ws.SheetData.Row[rowIdx]
if v.R != row { if v.R != row {
xlsx.SheetData.Row[keep] = *v ws.SheetData.Row[keep] = *v
keep++ keep++
} }
} }
xlsx.SheetData.Row = xlsx.SheetData.Row[:keep] ws.SheetData.Row = ws.SheetData.Row[:keep]
return f.adjustHelper(sheet, rows, row, -1) return f.adjustHelper(sheet, rows, row, -1)
} }
@ -526,20 +525,20 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) error {
return newInvalidRowNumberError(row) return newInvalidRowNumberError(row)
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
if row > len(xlsx.SheetData.Row) || row2 < 1 || row == row2 { if row > len(ws.SheetData.Row) || row2 < 1 || row == row2 {
return nil return nil
} }
var ok bool var ok bool
var rowCopy xlsxRow var rowCopy xlsxRow
for i, r := range xlsx.SheetData.Row { for i, r := range ws.SheetData.Row {
if r.R == row { if r.R == row {
rowCopy = xlsx.SheetData.Row[i] rowCopy = ws.SheetData.Row[i]
ok = true ok = true
break break
} }
@ -553,13 +552,13 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) error {
} }
idx2 := -1 idx2 := -1
for i, r := range xlsx.SheetData.Row { for i, r := range ws.SheetData.Row {
if r.R == row2 { if r.R == row2 {
idx2 = i idx2 = i
break break
} }
} }
if idx2 == -1 && len(xlsx.SheetData.Row) >= row2 { if idx2 == -1 && len(ws.SheetData.Row) >= row2 {
return nil return nil
} }
@ -567,23 +566,23 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) error {
f.ajustSingleRowDimensions(&rowCopy, row2) f.ajustSingleRowDimensions(&rowCopy, row2)
if idx2 != -1 { if idx2 != -1 {
xlsx.SheetData.Row[idx2] = rowCopy ws.SheetData.Row[idx2] = rowCopy
} else { } else {
xlsx.SheetData.Row = append(xlsx.SheetData.Row, rowCopy) ws.SheetData.Row = append(ws.SheetData.Row, rowCopy)
} }
return f.duplicateMergeCells(sheet, xlsx, row, row2) return f.duplicateMergeCells(sheet, ws, row, row2)
} }
// duplicateMergeCells merge cells in the destination row if there are single // duplicateMergeCells merge cells in the destination row if there are single
// row merged cells in the copied row. // row merged cells in the copied row.
func (f *File) duplicateMergeCells(sheet string, xlsx *xlsxWorksheet, row, row2 int) error { func (f *File) duplicateMergeCells(sheet string, ws *xlsxWorksheet, row, row2 int) error {
if xlsx.MergeCells == nil { if ws.MergeCells == nil {
return nil return nil
} }
if row > row2 { if row > row2 {
row++ row++
} }
for _, rng := range xlsx.MergeCells.Cells { for _, rng := range ws.MergeCells.Cells {
coordinates, err := f.areaRefToCoordinates(rng.Ref) coordinates, err := f.areaRefToCoordinates(rng.Ref)
if err != nil { if err != nil {
return err return err
@ -592,8 +591,8 @@ func (f *File) duplicateMergeCells(sheet string, xlsx *xlsxWorksheet, row, row2
return nil return nil
} }
} }
for i := 0; i < len(xlsx.MergeCells.Cells); i++ { for i := 0; i < len(ws.MergeCells.Cells); i++ {
areaData := xlsx.MergeCells.Cells[i] areaData := ws.MergeCells.Cells[i]
coordinates, _ := f.areaRefToCoordinates(areaData.Ref) coordinates, _ := f.areaRefToCoordinates(areaData.Ref)
x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3] x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3]
if y1 == y2 && y1 == row { if y1 == y2 && y1 == row {
@ -632,9 +631,9 @@ func (f *File) duplicateMergeCells(sheet string, xlsx *xlsxWorksheet, row, row2
// //
// Noteice: this method could be very slow for large spreadsheets (more than // Noteice: this method could be very slow for large spreadsheets (more than
// 3000 rows one sheet). // 3000 rows one sheet).
func checkRow(xlsx *xlsxWorksheet) error { func checkRow(ws *xlsxWorksheet) error {
for rowIdx := range xlsx.SheetData.Row { for rowIdx := range ws.SheetData.Row {
rowData := &xlsx.SheetData.Row[rowIdx] rowData := &ws.SheetData.Row[rowIdx]
colCount := len(rowData.C) colCount := len(rowData.C)
if colCount == 0 { if colCount == 0 {
@ -665,7 +664,7 @@ func checkRow(xlsx *xlsxWorksheet) error {
oldList := rowData.C oldList := rowData.C
newlist := make([]xlsxC, 0, lastCol) newlist := make([]xlsxC, 0, lastCol)
rowData.C = xlsx.SheetData.Row[rowIdx].C[:0] rowData.C = ws.SheetData.Row[rowIdx].C[:0]
for colIdx := 0; colIdx < lastCol; colIdx++ { for colIdx := 0; colIdx < lastCol; colIdx++ {
cellName, err := CoordinatesToCellName(colIdx+1, rowIdx+1) cellName, err := CoordinatesToCellName(colIdx+1, rowIdx+1)
@ -683,7 +682,7 @@ func checkRow(xlsx *xlsxWorksheet) error {
if err != nil { if err != nil {
return err return err
} }
xlsx.SheetData.Row[rowIdx].C[colNum-1] = *colData ws.SheetData.Row[rowIdx].C[colNum-1] = *colData
} }
} }
} }

View File

@ -82,11 +82,11 @@ func TestRowsIterator(t *testing.T) {
} }
func TestRowsError(t *testing.T) { func TestRowsError(t *testing.T) {
xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx")) f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) { if !assert.NoError(t, err) {
t.FailNow() t.FailNow()
} }
_, err = xlsx.Rows("SheetN") _, err = f.Rows("SheetN")
assert.EqualError(t, err, "sheet SheetN is not exist") assert.EqualError(t, err, "sheet SheetN is not exist")
} }
@ -259,49 +259,49 @@ func TestRemoveRow(t *testing.T) {
} }
func TestInsertRow(t *testing.T) { func TestInsertRow(t *testing.T) {
xlsx := NewFile() f := NewFile()
sheet1 := xlsx.GetSheetName(0) sheet1 := f.GetSheetName(0)
r, err := xlsx.workSheetReader(sheet1) r, err := f.workSheetReader(sheet1)
assert.NoError(t, err) assert.NoError(t, err)
const ( const (
colCount = 10 colCount = 10
rowCount = 10 rowCount = 10
) )
fillCells(xlsx, sheet1, colCount, rowCount) fillCells(f, sheet1, colCount, rowCount)
assert.NoError(t, xlsx.SetCellHyperLink(sheet1, "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")) assert.NoError(t, f.SetCellHyperLink(sheet1, "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External"))
assert.EqualError(t, xlsx.InsertRow(sheet1, -1), "invalid row number -1") assert.EqualError(t, f.InsertRow(sheet1, -1), "invalid row number -1")
assert.EqualError(t, xlsx.InsertRow(sheet1, 0), "invalid row number 0") assert.EqualError(t, f.InsertRow(sheet1, 0), "invalid row number 0")
assert.NoError(t, xlsx.InsertRow(sheet1, 1)) assert.NoError(t, f.InsertRow(sheet1, 1))
if !assert.Len(t, r.SheetData.Row, rowCount+1) { if !assert.Len(t, r.SheetData.Row, rowCount+1) {
t.FailNow() t.FailNow()
} }
assert.NoError(t, xlsx.InsertRow(sheet1, 4)) assert.NoError(t, f.InsertRow(sheet1, 4))
if !assert.Len(t, r.SheetData.Row, rowCount+2) { if !assert.Len(t, r.SheetData.Row, rowCount+2) {
t.FailNow() t.FailNow()
} }
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertRow.xlsx"))) assert.NoError(t, f.SaveAs(filepath.Join("test", "TestInsertRow.xlsx")))
} }
// Testing internal sructure state after insert operations. // Testing internal sructure state after insert operations.
// It is important for insert workflow to be constant to avoid side effect with functions related to internal structure. // It is important for insert workflow to be constant to avoid side effect with functions related to internal structure.
func TestInsertRowInEmptyFile(t *testing.T) { func TestInsertRowInEmptyFile(t *testing.T) {
xlsx := NewFile() f := NewFile()
sheet1 := xlsx.GetSheetName(0) sheet1 := f.GetSheetName(0)
r, err := xlsx.workSheetReader(sheet1) r, err := f.workSheetReader(sheet1)
assert.NoError(t, err) assert.NoError(t, err)
assert.NoError(t, xlsx.InsertRow(sheet1, 1)) assert.NoError(t, f.InsertRow(sheet1, 1))
assert.Len(t, r.SheetData.Row, 0) assert.Len(t, r.SheetData.Row, 0)
assert.NoError(t, xlsx.InsertRow(sheet1, 2)) assert.NoError(t, f.InsertRow(sheet1, 2))
assert.Len(t, r.SheetData.Row, 0) assert.Len(t, r.SheetData.Row, 0)
assert.NoError(t, xlsx.InsertRow(sheet1, 99)) assert.NoError(t, f.InsertRow(sheet1, 99))
assert.Len(t, r.SheetData.Row, 0) assert.Len(t, r.SheetData.Row, 0)
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertRowInEmptyFile.xlsx"))) assert.NoError(t, f.SaveAs(filepath.Join("test", "TestInsertRowInEmptyFile.xlsx")))
} }
func TestDuplicateRowFromSingleRow(t *testing.T) { func TestDuplicateRowFromSingleRow(t *testing.T) {
@ -318,12 +318,12 @@ func TestDuplicateRowFromSingleRow(t *testing.T) {
} }
t.Run("FromSingleRow", func(t *testing.T) { t.Run("FromSingleRow", func(t *testing.T) {
xlsx := NewFile() f := NewFile()
assert.NoError(t, xlsx.SetCellStr(sheet, "A1", cells["A1"])) assert.NoError(t, f.SetCellStr(sheet, "A1", cells["A1"]))
assert.NoError(t, xlsx.SetCellStr(sheet, "B1", cells["B1"])) assert.NoError(t, f.SetCellStr(sheet, "B1", cells["B1"]))
assert.NoError(t, xlsx.DuplicateRow(sheet, 1)) assert.NoError(t, f.DuplicateRow(sheet, 1))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_1"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_1"))) {
t.FailNow() t.FailNow()
} }
expect := map[string]string{ expect := map[string]string{
@ -331,15 +331,15 @@ func TestDuplicateRowFromSingleRow(t *testing.T) {
"A2": cells["A1"], "B2": cells["B1"], "A2": cells["A1"], "B2": cells["B1"],
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
} }
} }
assert.NoError(t, xlsx.DuplicateRow(sheet, 2)) assert.NoError(t, f.DuplicateRow(sheet, 2))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_2"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_2"))) {
t.FailNow() t.FailNow()
} }
expect = map[string]string{ expect = map[string]string{
@ -348,7 +348,7 @@ func TestDuplicateRowFromSingleRow(t *testing.T) {
"A3": cells["A1"], "B3": cells["B1"], "A3": cells["A1"], "B3": cells["B1"],
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
@ -371,16 +371,16 @@ func TestDuplicateRowUpdateDuplicatedRows(t *testing.T) {
} }
t.Run("UpdateDuplicatedRows", func(t *testing.T) { t.Run("UpdateDuplicatedRows", func(t *testing.T) {
xlsx := NewFile() f := NewFile()
assert.NoError(t, xlsx.SetCellStr(sheet, "A1", cells["A1"])) assert.NoError(t, f.SetCellStr(sheet, "A1", cells["A1"]))
assert.NoError(t, xlsx.SetCellStr(sheet, "B1", cells["B1"])) assert.NoError(t, f.SetCellStr(sheet, "B1", cells["B1"]))
assert.NoError(t, xlsx.DuplicateRow(sheet, 1)) assert.NoError(t, f.DuplicateRow(sheet, 1))
assert.NoError(t, xlsx.SetCellStr(sheet, "A2", cells["A2"])) assert.NoError(t, f.SetCellStr(sheet, "A2", cells["A2"]))
assert.NoError(t, xlsx.SetCellStr(sheet, "B2", cells["B2"])) assert.NoError(t, f.SetCellStr(sheet, "B2", cells["B2"]))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.UpdateDuplicatedRows"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.UpdateDuplicatedRows"))) {
t.FailNow() t.FailNow()
} }
expect := map[string]string{ expect := map[string]string{
@ -388,7 +388,7 @@ func TestDuplicateRowUpdateDuplicatedRows(t *testing.T) {
"A2": cells["A2"], "B2": cells["B2"], "A2": cells["A2"], "B2": cells["B2"],
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
@ -419,11 +419,11 @@ func TestDuplicateRowFirstOfMultipleRows(t *testing.T) {
} }
t.Run("FirstOfMultipleRows", func(t *testing.T) { t.Run("FirstOfMultipleRows", func(t *testing.T) {
xlsx := newFileWithDefaults() f := newFileWithDefaults()
assert.NoError(t, xlsx.DuplicateRow(sheet, 1)) assert.NoError(t, f.DuplicateRow(sheet, 1))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FirstOfMultipleRows"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FirstOfMultipleRows"))) {
t.FailNow() t.FailNow()
} }
expect := map[string]string{ expect := map[string]string{
@ -433,7 +433,7 @@ func TestDuplicateRowFirstOfMultipleRows(t *testing.T) {
"A4": cells["A3"], "B4": cells["B3"], "A4": cells["A3"], "B4": cells["B3"],
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
@ -447,24 +447,24 @@ func TestDuplicateRowZeroWithNoRows(t *testing.T) {
outFile := filepath.Join("test", "TestDuplicateRow.%s.xlsx") outFile := filepath.Join("test", "TestDuplicateRow.%s.xlsx")
t.Run("ZeroWithNoRows", func(t *testing.T) { t.Run("ZeroWithNoRows", func(t *testing.T) {
xlsx := NewFile() f := NewFile()
assert.EqualError(t, xlsx.DuplicateRow(sheet, 0), "invalid row number 0") assert.EqualError(t, f.DuplicateRow(sheet, 0), "invalid row number 0")
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.ZeroWithNoRows"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.ZeroWithNoRows"))) {
t.FailNow() t.FailNow()
} }
val, err := xlsx.GetCellValue(sheet, "A1") val, err := f.GetCellValue(sheet, "A1")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "", val) assert.Equal(t, "", val)
val, err = xlsx.GetCellValue(sheet, "B1") val, err = f.GetCellValue(sheet, "B1")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "", val) assert.Equal(t, "", val)
val, err = xlsx.GetCellValue(sheet, "A2") val, err = f.GetCellValue(sheet, "A2")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "", val) assert.Equal(t, "", val)
val, err = xlsx.GetCellValue(sheet, "B2") val, err = f.GetCellValue(sheet, "B2")
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, "", val) assert.Equal(t, "", val)
@ -475,7 +475,7 @@ func TestDuplicateRowZeroWithNoRows(t *testing.T) {
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
@ -489,11 +489,11 @@ func TestDuplicateRowMiddleRowOfEmptyFile(t *testing.T) {
outFile := filepath.Join("test", "TestDuplicateRow.%s.xlsx") outFile := filepath.Join("test", "TestDuplicateRow.%s.xlsx")
t.Run("MiddleRowOfEmptyFile", func(t *testing.T) { t.Run("MiddleRowOfEmptyFile", func(t *testing.T) {
xlsx := NewFile() f := NewFile()
assert.NoError(t, xlsx.DuplicateRow(sheet, 99)) assert.NoError(t, f.DuplicateRow(sheet, 99))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.MiddleRowOfEmptyFile"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.MiddleRowOfEmptyFile"))) {
t.FailNow() t.FailNow()
} }
expect := map[string]string{ expect := map[string]string{
@ -502,7 +502,7 @@ func TestDuplicateRowMiddleRowOfEmptyFile(t *testing.T) {
"A100": "", "A100": "",
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
@ -533,11 +533,11 @@ func TestDuplicateRowWithLargeOffsetToMiddleOfData(t *testing.T) {
} }
t.Run("WithLargeOffsetToMiddleOfData", func(t *testing.T) { t.Run("WithLargeOffsetToMiddleOfData", func(t *testing.T) {
xlsx := newFileWithDefaults() f := newFileWithDefaults()
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 1, 3)) assert.NoError(t, f.DuplicateRowTo(sheet, 1, 3))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToMiddleOfData"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToMiddleOfData"))) {
t.FailNow() t.FailNow()
} }
expect := map[string]string{ expect := map[string]string{
@ -547,7 +547,7 @@ func TestDuplicateRowWithLargeOffsetToMiddleOfData(t *testing.T) {
"A4": cells["A3"], "B4": cells["B3"], "A4": cells["A3"], "B4": cells["B3"],
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
@ -578,11 +578,11 @@ func TestDuplicateRowWithLargeOffsetToEmptyRows(t *testing.T) {
} }
t.Run("WithLargeOffsetToEmptyRows", func(t *testing.T) { t.Run("WithLargeOffsetToEmptyRows", func(t *testing.T) {
xlsx := newFileWithDefaults() f := newFileWithDefaults()
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 1, 7)) assert.NoError(t, f.DuplicateRowTo(sheet, 1, 7))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToEmptyRows"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToEmptyRows"))) {
t.FailNow() t.FailNow()
} }
expect := map[string]string{ expect := map[string]string{
@ -592,7 +592,7 @@ func TestDuplicateRowWithLargeOffsetToEmptyRows(t *testing.T) {
"A7": cells["A1"], "B7": cells["B1"], "A7": cells["A1"], "B7": cells["B1"],
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
@ -623,11 +623,11 @@ func TestDuplicateRowInsertBefore(t *testing.T) {
} }
t.Run("InsertBefore", func(t *testing.T) { t.Run("InsertBefore", func(t *testing.T) {
xlsx := newFileWithDefaults() f := newFileWithDefaults()
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 2, 1)) assert.NoError(t, f.DuplicateRowTo(sheet, 2, 1))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBefore"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBefore"))) {
t.FailNow() t.FailNow()
} }
@ -638,7 +638,7 @@ func TestDuplicateRowInsertBefore(t *testing.T) {
"A4": cells["A3"], "B4": cells["B3"], "A4": cells["A3"], "B4": cells["B3"],
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v, cell) { if !assert.Equal(t, val, v, cell) {
t.FailNow() t.FailNow()
@ -669,11 +669,11 @@ func TestDuplicateRowInsertBeforeWithLargeOffset(t *testing.T) {
} }
t.Run("InsertBeforeWithLargeOffset", func(t *testing.T) { t.Run("InsertBeforeWithLargeOffset", func(t *testing.T) {
xlsx := newFileWithDefaults() f := newFileWithDefaults()
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 3, 1)) assert.NoError(t, f.DuplicateRowTo(sheet, 3, 1))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBeforeWithLargeOffset"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBeforeWithLargeOffset"))) {
t.FailNow() t.FailNow()
} }
@ -684,7 +684,7 @@ func TestDuplicateRowInsertBeforeWithLargeOffset(t *testing.T) {
"A4": cells["A3"], "B4": cells["B3"], "A4": cells["A3"], "B4": cells["B3"],
} }
for cell, val := range expect { for cell, val := range expect {
v, err := xlsx.GetCellValue(sheet, cell) v, err := f.GetCellValue(sheet, cell)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v) { if !assert.Equal(t, val, v) {
t.FailNow() t.FailNow()
@ -717,12 +717,12 @@ func TestDuplicateRowInsertBeforeWithMergeCells(t *testing.T) {
} }
t.Run("InsertBeforeWithLargeOffset", func(t *testing.T) { t.Run("InsertBeforeWithLargeOffset", func(t *testing.T) {
xlsx := newFileWithDefaults() f := newFileWithDefaults()
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 2, 1)) assert.NoError(t, f.DuplicateRowTo(sheet, 2, 1))
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 1, 8)) assert.NoError(t, f.DuplicateRowTo(sheet, 1, 8))
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBeforeWithMergeCells"))) { if !assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBeforeWithMergeCells"))) {
t.FailNow() t.FailNow()
} }
@ -732,7 +732,7 @@ func TestDuplicateRowInsertBeforeWithMergeCells(t *testing.T) {
{"B1:C1", "B2 Value"}, {"B1:C1", "B2 Value"},
} }
mergeCells, err := xlsx.GetMergeCells(sheet) mergeCells, err := f.GetMergeCells(sheet)
assert.NoError(t, err) assert.NoError(t, err)
for idx, val := range expect { for idx, val := range expect {
if !assert.Equal(t, val, mergeCells[idx]) { if !assert.Equal(t, val, mergeCells[idx]) {
@ -760,21 +760,21 @@ func TestDuplicateRowInvalidRownum(t *testing.T) {
for _, row := range invalidIndexes { for _, row := range invalidIndexes {
name := fmt.Sprintf("%d", row) name := fmt.Sprintf("%d", row)
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
xlsx := NewFile() f := NewFile()
for col, val := range cells { for col, val := range cells {
assert.NoError(t, xlsx.SetCellStr(sheet, col, val)) assert.NoError(t, f.SetCellStr(sheet, col, val))
} }
assert.EqualError(t, xlsx.DuplicateRow(sheet, row), fmt.Sprintf("invalid row number %d", row)) assert.EqualError(t, f.DuplicateRow(sheet, row), fmt.Sprintf("invalid row number %d", row))
for col, val := range cells { for col, val := range cells {
v, err := xlsx.GetCellValue(sheet, col) v, err := f.GetCellValue(sheet, col)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v) { if !assert.Equal(t, val, v) {
t.FailNow() t.FailNow()
} }
} }
assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, name))) assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, name)))
}) })
} }
@ -782,21 +782,21 @@ func TestDuplicateRowInvalidRownum(t *testing.T) {
for _, row2 := range invalidIndexes { for _, row2 := range invalidIndexes {
name := fmt.Sprintf("[%d,%d]", row1, row2) name := fmt.Sprintf("[%d,%d]", row1, row2)
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
xlsx := NewFile() f := NewFile()
for col, val := range cells { for col, val := range cells {
assert.NoError(t, xlsx.SetCellStr(sheet, col, val)) assert.NoError(t, f.SetCellStr(sheet, col, val))
} }
assert.EqualError(t, xlsx.DuplicateRowTo(sheet, row1, row2), fmt.Sprintf("invalid row number %d", row1)) assert.EqualError(t, f.DuplicateRowTo(sheet, row1, row2), fmt.Sprintf("invalid row number %d", row1))
for col, val := range cells { for col, val := range cells {
v, err := xlsx.GetCellValue(sheet, col) v, err := f.GetCellValue(sheet, col)
assert.NoError(t, err) assert.NoError(t, err)
if !assert.Equal(t, val, v) { if !assert.Equal(t, val, v) {
t.FailNow() t.FailNow()
} }
} }
assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, name))) assert.NoError(t, f.SaveAs(fmt.Sprintf(outFile, name)))
}) })
} }
} }
@ -809,12 +809,12 @@ func TestDuplicateRowTo(t *testing.T) {
func TestDuplicateMergeCells(t *testing.T) { func TestDuplicateMergeCells(t *testing.T) {
f := File{} f := File{}
xlsx := &xlsxWorksheet{MergeCells: &xlsxMergeCells{ ws := &xlsxWorksheet{MergeCells: &xlsxMergeCells{
Cells: []*xlsxMergeCell{{Ref: "A1:-"}}, Cells: []*xlsxMergeCell{{Ref: "A1:-"}},
}} }}
assert.EqualError(t, f.duplicateMergeCells("Sheet1", xlsx, 0, 0), `cannot convert cell "-" to coordinates: invalid cell name "-"`) assert.EqualError(t, f.duplicateMergeCells("Sheet1", ws, 0, 0), `cannot convert cell "-" to coordinates: invalid cell name "-"`)
xlsx.MergeCells.Cells[0].Ref = "A1:B1" ws.MergeCells.Cells[0].Ref = "A1:B1"
assert.EqualError(t, f.duplicateMergeCells("SheetN", xlsx, 1, 2), "sheet SheetN is not exist") assert.EqualError(t, f.duplicateMergeCells("SheetN", ws, 1, 2), "sheet SheetN is not exist")
} }
func TestGetValueFromInlineStr(t *testing.T) { func TestGetValueFromInlineStr(t *testing.T) {

View File

@ -261,7 +261,7 @@ func (f *File) AddShape(sheet, cell, format string) error {
return err return err
} }
// Read sheet data. // Read sheet data.
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -270,9 +270,9 @@ func (f *File) AddShape(sheet, cell, format string) error {
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml" drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml" sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
if xlsx.Drawing != nil { if ws.Drawing != nil {
// The worksheet already has a shape or chart relationships, use the relationships drawing ../drawings/drawing%d.xml. // The worksheet already has a shape or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID) sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID)
drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml")) drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1) drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
} else { } else {

View File

@ -202,7 +202,7 @@ func (f *File) setContentTypes(partName, contentType string) {
// setSheet provides a function to update sheet property by given index. // setSheet provides a function to update sheet property by given index.
func (f *File) setSheet(index int, name string) { func (f *File) setSheet(index int, name string) {
xlsx := xlsxWorksheet{ ws := xlsxWorksheet{
Dimension: &xlsxDimension{Ref: "A1"}, Dimension: &xlsxDimension{Ref: "A1"},
SheetViews: &xlsxSheetViews{ SheetViews: &xlsxSheetViews{
SheetView: []xlsxSheetView{{WorkbookViewID: 0}}, SheetView: []xlsxSheetView{{WorkbookViewID: 0}},
@ -210,7 +210,7 @@ func (f *File) setSheet(index int, name string) {
} }
path := "xl/worksheets/sheet" + strconv.Itoa(index) + ".xml" path := "xl/worksheets/sheet" + strconv.Itoa(index) + ".xml"
f.sheetMap[trimSheetName(name)] = path f.sheetMap[trimSheetName(name)] = path
f.Sheet[path] = &xlsx f.Sheet[path] = &ws
f.xmlAttr[path] = append(f.xmlAttr[path], NameSpaceSpreadSheet) f.xmlAttr[path] = append(f.xmlAttr[path], NameSpaceSpreadSheet)
} }
@ -277,24 +277,24 @@ func (f *File) SetActiveSheet(index int) {
} }
} }
for idx, name := range f.GetSheetList() { for idx, name := range f.GetSheetList() {
xlsx, err := f.workSheetReader(name) ws, err := f.workSheetReader(name)
if err != nil { if err != nil {
// Chartsheet or dialogsheet // Chartsheet or dialogsheet
return return
} }
if xlsx.SheetViews == nil { if ws.SheetViews == nil {
xlsx.SheetViews = &xlsxSheetViews{ ws.SheetViews = &xlsxSheetViews{
SheetView: []xlsxSheetView{{WorkbookViewID: 0}}, SheetView: []xlsxSheetView{{WorkbookViewID: 0}},
} }
} }
if len(xlsx.SheetViews.SheetView) > 0 { if len(ws.SheetViews.SheetView) > 0 {
xlsx.SheetViews.SheetView[0].TabSelected = false ws.SheetViews.SheetView[0].TabSelected = false
} }
if index == idx { if index == idx {
if len(xlsx.SheetViews.SheetView) > 0 { if len(ws.SheetViews.SheetView) > 0 {
xlsx.SheetViews.SheetView[0].TabSelected = true ws.SheetViews.SheetView[0].TabSelected = true
} else { } else {
xlsx.SheetViews.SheetView = append(xlsx.SheetViews.SheetView, xlsxSheetView{ ws.SheetViews.SheetView = append(ws.SheetViews.SheetView, xlsxSheetView{
TabSelected: true, TabSelected: true,
}) })
} }
@ -746,7 +746,7 @@ func parseFormatPanesSet(formatSet string) (*formatPanes, error) {
// //
func (f *File) SetPanes(sheet, panes string) error { func (f *File) SetPanes(sheet, panes string) error {
fs, _ := parseFormatPanesSet(panes) fs, _ := parseFormatPanesSet(panes)
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -759,10 +759,10 @@ func (f *File) SetPanes(sheet, panes string) error {
if fs.Freeze { if fs.Freeze {
p.State = "frozen" p.State = "frozen"
} }
xlsx.SheetViews.SheetView[len(xlsx.SheetViews.SheetView)-1].Pane = p ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Pane = p
if !(fs.Freeze) && !(fs.Split) { if !(fs.Freeze) && !(fs.Split) {
if len(xlsx.SheetViews.SheetView) > 0 { if len(ws.SheetViews.SheetView) > 0 {
xlsx.SheetViews.SheetView[len(xlsx.SheetViews.SheetView)-1].Pane = nil ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Pane = nil
} }
} }
s := []*xlsxSelection{} s := []*xlsxSelection{}
@ -773,7 +773,7 @@ func (f *File) SetPanes(sheet, panes string) error {
SQRef: p.SQRef, SQRef: p.SQRef,
}) })
} }
xlsx.SheetViews.SheetView[len(xlsx.SheetViews.SheetView)-1].Selection = s ws.SheetViews.SheetView[len(ws.SheetViews.SheetView)-1].Selection = s
return err return err
} }
@ -1020,12 +1020,12 @@ func attrValToInt(name string, attrs []xml.Attr) (val int, err error) {
// - No footer on the first page // - No footer on the first page
// //
func (f *File) SetHeaderFooter(sheet string, settings *FormatHeaderFooter) error { func (f *File) SetHeaderFooter(sheet string, settings *FormatHeaderFooter) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
if settings == nil { if settings == nil {
xlsx.HeaderFooter = nil ws.HeaderFooter = nil
return err return err
} }
@ -1037,7 +1037,7 @@ func (f *File) SetHeaderFooter(sheet string, settings *FormatHeaderFooter) error
return fmt.Errorf("field %s must be less than 255 characters", v.Type().Field(i).Name) return fmt.Errorf("field %s must be less than 255 characters", v.Type().Field(i).Name)
} }
} }
xlsx.HeaderFooter = &xlsxHeaderFooter{ ws.HeaderFooter = &xlsxHeaderFooter{
AlignWithMargins: settings.AlignWithMargins, AlignWithMargins: settings.AlignWithMargins,
DifferentFirst: settings.DifferentFirst, DifferentFirst: settings.DifferentFirst,
DifferentOddEven: settings.DifferentOddEven, DifferentOddEven: settings.DifferentOddEven,
@ -1062,7 +1062,7 @@ func (f *File) SetHeaderFooter(sheet string, settings *FormatHeaderFooter) error
// }) // })
// //
func (f *File) ProtectSheet(sheet string, settings *FormatSheetProtection) error { func (f *File) ProtectSheet(sheet string, settings *FormatSheetProtection) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -1073,7 +1073,7 @@ func (f *File) ProtectSheet(sheet string, settings *FormatSheetProtection) error
SelectLockedCells: true, SelectLockedCells: true,
} }
} }
xlsx.SheetProtection = &xlsxSheetProtection{ ws.SheetProtection = &xlsxSheetProtection{
AutoFilter: settings.AutoFilter, AutoFilter: settings.AutoFilter,
DeleteColumns: settings.DeleteColumns, DeleteColumns: settings.DeleteColumns,
DeleteRows: settings.DeleteRows, DeleteRows: settings.DeleteRows,
@ -1092,18 +1092,18 @@ func (f *File) ProtectSheet(sheet string, settings *FormatSheetProtection) error
Sort: settings.Sort, Sort: settings.Sort,
} }
if settings.Password != "" { if settings.Password != "" {
xlsx.SheetProtection.Password = genSheetPasswd(settings.Password) ws.SheetProtection.Password = genSheetPasswd(settings.Password)
} }
return err return err
} }
// UnprotectSheet provides a function to unprotect an Excel worksheet. // UnprotectSheet provides a function to unprotect an Excel worksheet.
func (f *File) UnprotectSheet(sheet string) error { func (f *File) UnprotectSheet(sheet string) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
xlsx.SheetProtection = nil ws.SheetProtection = nil
return err return err
} }
@ -1494,19 +1494,19 @@ func (f *File) GroupSheets(sheets []string) error {
return errors.New("group worksheet must contain an active worksheet") return errors.New("group worksheet must contain an active worksheet")
} }
// check worksheet exists // check worksheet exists
ws := []*xlsxWorksheet{} wss := []*xlsxWorksheet{}
for _, sheet := range sheets { for _, sheet := range sheets {
xlsx, err := f.workSheetReader(sheet) worksheet, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
ws = append(ws, xlsx) wss = append(wss, worksheet)
} }
for _, s := range ws { for _, ws := range wss {
sheetViews := s.SheetViews.SheetView sheetViews := ws.SheetViews.SheetView
if len(sheetViews) > 0 { if len(sheetViews) > 0 {
for idx := range sheetViews { for idx := range sheetViews {
s.SheetViews.SheetView[idx].TabSelected = true ws.SheetViews.SheetView[idx].TabSelected = true
} }
continue continue
} }
@ -1664,25 +1664,25 @@ func (f *File) relsReader(path string) *xlsxRelationships {
// fillSheetData ensures there are enough rows, and columns in the chosen // fillSheetData ensures there are enough rows, and columns in the chosen
// row to accept data. Missing rows are backfilled and given their row number // row to accept data. Missing rows are backfilled and given their row number
// Uses the last populated row as a hint for the size of the next row to add // Uses the last populated row as a hint for the size of the next row to add
func prepareSheetXML(xlsx *xlsxWorksheet, col int, row int) { func prepareSheetXML(ws *xlsxWorksheet, col int, row int) {
rowCount := len(xlsx.SheetData.Row) rowCount := len(ws.SheetData.Row)
sizeHint := 0 sizeHint := 0
var ht float64 var ht float64
var customHeight bool var customHeight bool
if xlsx.SheetFormatPr != nil { if ws.SheetFormatPr != nil {
ht = xlsx.SheetFormatPr.DefaultRowHeight ht = ws.SheetFormatPr.DefaultRowHeight
customHeight = true customHeight = true
} }
if rowCount > 0 { if rowCount > 0 {
sizeHint = len(xlsx.SheetData.Row[rowCount-1].C) sizeHint = len(ws.SheetData.Row[rowCount-1].C)
} }
if rowCount < row { if rowCount < row {
// append missing rows // append missing rows
for rowIdx := rowCount; rowIdx < row; rowIdx++ { for rowIdx := rowCount; rowIdx < row; rowIdx++ {
xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{R: rowIdx + 1, CustomHeight: customHeight, Ht: ht, C: make([]xlsxC, 0, sizeHint)}) ws.SheetData.Row = append(ws.SheetData.Row, xlsxRow{R: rowIdx + 1, CustomHeight: customHeight, Ht: ht, C: make([]xlsxC, 0, sizeHint)})
} }
} }
rowData := &xlsx.SheetData.Row[row-1] rowData := &ws.SheetData.Row[row-1]
fillColumns(rowData, col, row) fillColumns(rowData, col, row)
} }
@ -1696,9 +1696,9 @@ func fillColumns(rowData *xlsxRow, col, row int) {
} }
} }
func makeContiguousColumns(xlsx *xlsxWorksheet, fromRow, toRow, colCount int) { func makeContiguousColumns(ws *xlsxWorksheet, fromRow, toRow, colCount int) {
for ; fromRow < toRow; fromRow++ { for ; fromRow < toRow; fromRow++ {
rowData := &xlsx.SheetData.Row[fromRow-1] rowData := &ws.SheetData.Row[fromRow-1]
fillColumns(rowData, colCount, fromRow) fillColumns(rowData, colCount, fromRow)
} }
} }

View File

@ -140,21 +140,21 @@ func (o *ZoomScale) getSheetViewOption(view *xlsxSheetView) {
} }
// getSheetView returns the SheetView object // getSheetView returns the SheetView object
func (f *File) getSheetView(sheetName string, viewIndex int) (*xlsxSheetView, error) { func (f *File) getSheetView(sheet string, viewIndex int) (*xlsxSheetView, error) {
xlsx, err := f.workSheetReader(sheetName) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if viewIndex < 0 { if viewIndex < 0 {
if viewIndex < -len(xlsx.SheetViews.SheetView) { if viewIndex < -len(ws.SheetViews.SheetView) {
return nil, fmt.Errorf("view index %d out of range", viewIndex) return nil, fmt.Errorf("view index %d out of range", viewIndex)
} }
viewIndex = len(xlsx.SheetViews.SheetView) + viewIndex viewIndex = len(ws.SheetViews.SheetView) + viewIndex
} else if viewIndex >= len(xlsx.SheetViews.SheetView) { } else if viewIndex >= len(ws.SheetViews.SheetView) {
return nil, fmt.Errorf("view index %d out of range", viewIndex) return nil, fmt.Errorf("view index %d out of range", viewIndex)
} }
return &(xlsx.SheetViews.SheetView[viewIndex]), err return &(ws.SheetViews.SheetView[viewIndex]), err
} }
// SetSheetViewOptions sets sheet view options. The viewIndex may be negative // SetSheetViewOptions sets sheet view options. The viewIndex may be negative

View File

@ -211,7 +211,7 @@ func TestAddSparkline(t *testing.T) {
Negative: true, Negative: true,
})) }))
// Save xlsx file by the given path. // Save spreadsheet by the given path.
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddSparkline.xlsx"))) assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddSparkline.xlsx")))
// Test error exceptions // Test error exceptions

View File

@ -69,7 +69,7 @@ func TestStreamWriter(t *testing.T) {
} }
assert.NoError(t, streamWriter.Flush()) assert.NoError(t, streamWriter.Flush())
// Save xlsx file by the given path. // Save spreadsheet by the given path.
assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx"))) assert.NoError(t, file.SaveAs(filepath.Join("test", "TestStreamWriter.xlsx")))
// Test close temporary file error. // Test close temporary file error.

View File

@ -27,8 +27,8 @@ import (
) )
// Excel styles can reference number formats that are built-in, all of which // Excel styles can reference number formats that are built-in, all of which
// have an id less than 164. This is a possibly incomplete list comprised of // have an id less than 164. Note that this number format code list is under
// as many of them as I could find. // English localization.
var builtInNumFmt = map[int]string{ var builtInNumFmt = map[int]string{
0: "general", 0: "general",
1: "0", 1: "0",
@ -2580,15 +2580,15 @@ func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, a
// GetCellStyle provides a function to get cell style index by given worksheet // GetCellStyle provides a function to get cell style index by given worksheet
// name and cell coordinates. // name and cell coordinates.
func (f *File) GetCellStyle(sheet, axis string) (int, error) { func (f *File) GetCellStyle(sheet, axis string) (int, error) {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return 0, err return 0, err
} }
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis) cellData, col, _, err := f.prepareCell(ws, sheet, axis)
if err != nil { if err != nil {
return 0, err return 0, err
} }
return f.prepareCellStyle(xlsx, col, cellData.S), err return f.prepareCellStyle(ws, col, cellData.S), err
} }
// SetCellStyle provides a function to add style attribute for cells by given // SetCellStyle provides a function to add style attribute for cells by given
@ -2682,16 +2682,16 @@ func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) error {
vcolIdx := vcol - 1 vcolIdx := vcol - 1
vrowIdx := vrow - 1 vrowIdx := vrow - 1
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
prepareSheetXML(xlsx, vcol, vrow) prepareSheetXML(ws, vcol, vrow)
makeContiguousColumns(xlsx, hrow, vrow, vcol) makeContiguousColumns(ws, hrow, vrow, vcol)
for r := hrowIdx; r <= vrowIdx; r++ { for r := hrowIdx; r <= vrowIdx; r++ {
for k := hcolIdx; k <= vcolIdx; k++ { for k := hcolIdx; k <= vcolIdx; k++ {
xlsx.SheetData.Row[r].C[k].S = styleID ws.SheetData.Row[r].C[k].S = styleID
} }
} }
return err return err
@ -2926,7 +2926,7 @@ func (f *File) SetConditionalFormat(sheet, area, formatSet string) error {
"expression": drawConfFmtExp, "expression": drawConfFmtExp,
} }
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
@ -2948,7 +2948,7 @@ func (f *File) SetConditionalFormat(sheet, area, formatSet string) error {
} }
} }
xlsx.ConditionalFormatting = append(xlsx.ConditionalFormatting, &xlsxConditionalFormatting{ ws.ConditionalFormatting = append(ws.ConditionalFormatting, &xlsxConditionalFormatting{
SQRef: area, SQRef: area,
CfRule: cfRule, CfRule: cfRule,
}) })

View File

@ -156,18 +156,18 @@ func TestSetConditionalFormat(t *testing.T) {
}} }}
for _, testCase := range cases { for _, testCase := range cases {
xl := NewFile() f := NewFile()
const sheet = "Sheet1" const sheet = "Sheet1"
const cellRange = "A1:A1" const cellRange = "A1:A1"
err := xl.SetConditionalFormat(sheet, cellRange, testCase.format) err := f.SetConditionalFormat(sheet, cellRange, testCase.format)
if err != nil { if err != nil {
t.Fatalf("%s", err) t.Fatalf("%s", err)
} }
xlsx, err := xl.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
assert.NoError(t, err) assert.NoError(t, err)
cf := xlsx.ConditionalFormatting cf := ws.ConditionalFormatting
assert.Len(t, cf, 1, testCase.label) assert.Len(t, cf, 1, testCase.label)
assert.Len(t, cf[0].CfRule, 1, testCase.label) assert.Len(t, cf[0].CfRule, 1, testCase.label)
assert.Equal(t, cellRange, cf[0].SQRef, testCase.label) assert.Equal(t, cellRange, cf[0].SQRef, testCase.label)
@ -185,7 +185,7 @@ func TestUnsetConditionalFormat(t *testing.T) {
assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10")) assert.NoError(t, f.UnsetConditionalFormat("Sheet1", "A1:A10"))
// Test unset conditional format on not exists worksheet. // Test unset conditional format on not exists worksheet.
assert.EqualError(t, f.UnsetConditionalFormat("SheetN", "A1:A10"), "sheet SheetN is not exist") assert.EqualError(t, f.UnsetConditionalFormat("SheetN", "A1:A10"), "sheet SheetN is not exist")
// Save xlsx file by the given path. // Save spreadsheet by the given path.
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestUnsetConditionalFormat.xlsx"))) assert.NoError(t, f.SaveAs(filepath.Join("test", "TestUnsetConditionalFormat.xlsx")))
} }

View File

@ -323,18 +323,18 @@ func (f *File) AutoFilter(sheet, hcell, vcell, format string) error {
// autoFilter provides a function to extract the tokens from the filter // autoFilter provides a function to extract the tokens from the filter
// expression. The tokens are mainly non-whitespace groups. // expression. The tokens are mainly non-whitespace groups.
func (f *File) autoFilter(sheet, ref string, refRange, col int, formatSet *formatAutoFilter) error { func (f *File) autoFilter(sheet, ref string, refRange, col int, formatSet *formatAutoFilter) error {
xlsx, err := f.workSheetReader(sheet) ws, err := f.workSheetReader(sheet)
if err != nil { if err != nil {
return err return err
} }
if xlsx.SheetPr != nil { if ws.SheetPr != nil {
xlsx.SheetPr.FilterMode = true ws.SheetPr.FilterMode = true
} }
xlsx.SheetPr = &xlsxSheetPr{FilterMode: true} ws.SheetPr = &xlsxSheetPr{FilterMode: true}
filter := &xlsxAutoFilter{ filter := &xlsxAutoFilter{
Ref: ref, Ref: ref,
} }
xlsx.AutoFilter = filter ws.AutoFilter = filter
if formatSet.Column == "" || formatSet.Expression == "" { if formatSet.Column == "" || formatSet.Expression == "" {
return nil return nil
} }
@ -361,7 +361,7 @@ func (f *File) autoFilter(sheet, ref string, refRange, col int, formatSet *forma
return err return err
} }
f.writeAutoFilter(filter, expressions, tokens) f.writeAutoFilter(filter, expressions, tokens)
xlsx.AutoFilter = filter ws.AutoFilter = filter
return nil return nil
} }