forked from p30928647/excelize
Using the specialized name in a variable and making comments clear
- Add JSON tags for `AppProperties`, `PivotTableOption` and `PivotTableField` structure
This commit is contained in:
parent
73cc4bd449
commit
3f702999e6
|
@ -248,8 +248,8 @@ func (f *File) adjustAutoFilter(ws *xlsxWorksheet, dir adjustDirection, num, off
|
|||
}
|
||||
|
||||
// adjustAutoFilterHelper provides a function for adjusting auto filter to
|
||||
// compare and calculate cell axis by the given adjust direction, operation
|
||||
// axis and offset.
|
||||
// compare and calculate cell reference by the given adjust direction, operation
|
||||
// reference and offset.
|
||||
func (f *File) adjustAutoFilterHelper(dir adjustDirection, coordinates []int, num, offset int) []int {
|
||||
if dir == rows {
|
||||
if coordinates[1] >= num {
|
||||
|
@ -314,7 +314,7 @@ func (f *File) adjustMergeCells(ws *xlsxWorksheet, dir adjustDirection, num, off
|
|||
}
|
||||
|
||||
// adjustMergeCellsHelper provides a function for adjusting merge cells to
|
||||
// compare and calculate cell axis by the given pivot, operation axis and
|
||||
// compare and calculate cell reference by the given pivot, operation reference and
|
||||
// offset.
|
||||
func (f *File) adjustMergeCellsHelper(p1, p2, num, offset int) (int, int) {
|
||||
if p2 < p1 {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
func TestAdjustMergeCells(t *testing.T) {
|
||||
f := NewFile()
|
||||
// testing adjustAutoFilter with illegal cell coordinates.
|
||||
// testing adjustAutoFilter with illegal cell reference.
|
||||
assert.EqualError(t, f.adjustMergeCells(&xlsxWorksheet{
|
||||
MergeCells: &xlsxMergeCells{
|
||||
Cells: []*xlsxMergeCell{
|
||||
|
@ -283,7 +283,7 @@ func TestAdjustAutoFilter(t *testing.T) {
|
|||
Ref: "A1:A3",
|
||||
},
|
||||
}, rows, 1, -1))
|
||||
// Test adjustAutoFilter with illegal cell coordinates.
|
||||
// Test adjustAutoFilter with illegal cell reference.
|
||||
assert.EqualError(t, f.adjustAutoFilter(&xlsxWorksheet{
|
||||
AutoFilter: &xlsxAutoFilter{
|
||||
Ref: "A:B1",
|
||||
|
@ -335,7 +335,7 @@ func TestAdjustHelper(t *testing.T) {
|
|||
f.Sheet.Store("xl/worksheets/sheet2.xml", &xlsxWorksheet{
|
||||
AutoFilter: &xlsxAutoFilter{Ref: "A1:B"},
|
||||
})
|
||||
// Test adjustHelper with illegal cell coordinates.
|
||||
// Test adjustHelper with illegal cell reference.
|
||||
assert.EqualError(t, f.adjustHelper("Sheet1", rows, 0, 0), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
assert.EqualError(t, f.adjustHelper("Sheet2", rows, 0, 0), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
|
||||
// Test adjustHelper on not exists worksheet.
|
||||
|
|
4
calc.go
4
calc.go
|
@ -1408,7 +1408,7 @@ func (f *File) parseReference(ctx *calcContext, sheet, reference string) (arg fo
|
|||
cr := cellRef{}
|
||||
if len(tokens) == 2 { // have a worksheet name
|
||||
cr.Sheet = tokens[0]
|
||||
// cast to cell coordinates
|
||||
// cast to cell reference
|
||||
if cr.Col, cr.Row, err = CellNameToCoordinates(tokens[1]); err != nil {
|
||||
// cast to column
|
||||
if cr.Col, err = ColumnNameToNumber(tokens[1]); err != nil {
|
||||
|
@ -1428,7 +1428,7 @@ func (f *File) parseReference(ctx *calcContext, sheet, reference string) (arg fo
|
|||
refs.PushBack(cr)
|
||||
continue
|
||||
}
|
||||
// cast to cell coordinates
|
||||
// cast to cell reference
|
||||
if cr.Col, cr.Row, err = CellNameToCoordinates(tokens[0]); err != nil {
|
||||
// cast to column
|
||||
if cr.Col, err = ColumnNameToNumber(tokens[0]); err != nil {
|
||||
|
|
|
@ -45,11 +45,11 @@ func (f *File) calcChainWriter() {
|
|||
|
||||
// deleteCalcChain provides a function to remove cell reference on the
|
||||
// calculation chain.
|
||||
func (f *File) deleteCalcChain(index int, axis string) {
|
||||
func (f *File) deleteCalcChain(index int, cell string) {
|
||||
calc := f.calcChainReader()
|
||||
if calc != nil {
|
||||
calc.C = xlsxCalcChainCollection(calc.C).Filter(func(c xlsxCalcChainC) bool {
|
||||
return !((c.I == index && c.R == axis) || (c.I == index && axis == "") || (c.I == 0 && c.R == axis))
|
||||
return !((c.I == index && c.R == cell) || (c.I == index && cell == "") || (c.I == 0 && c.R == cell))
|
||||
})
|
||||
}
|
||||
if len(calc.C) == 0 {
|
||||
|
|
271
cell.go
271
cell.go
|
@ -57,26 +57,27 @@ var cellTypes = map[string]CellType{
|
|||
}
|
||||
|
||||
// GetCellValue provides a function to get formatted value from cell by given
|
||||
// worksheet name and axis in spreadsheet file. If it is possible to apply a
|
||||
// format to the cell value, it will do so, if not then an error will be
|
||||
// returned, along with the raw value of the cell. All cells' values will be
|
||||
// the same in a merged range. This function is concurrency safe.
|
||||
func (f *File) GetCellValue(sheet, axis string, opts ...Options) (string, error) {
|
||||
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
|
||||
// worksheet name and cell reference in spreadsheet. The return value is
|
||||
// converted to the 'string' data type. This function is concurrency safe. If
|
||||
// the cell format can be applied to the value of a cell, the applied value
|
||||
// will be returned, otherwise the original value will be returned. All cells'
|
||||
// values will be the same in a merged range.
|
||||
func (f *File) GetCellValue(sheet, cell string, opts ...Options) (string, error) {
|
||||
return f.getCellStringFunc(sheet, cell, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
|
||||
val, err := c.getValueFrom(f, f.sharedStringsReader(), parseOptions(opts...).RawCellValue)
|
||||
return val, true, err
|
||||
})
|
||||
}
|
||||
|
||||
// GetCellType provides a function to get the cell's data type by given
|
||||
// worksheet name and axis in spreadsheet file.
|
||||
func (f *File) GetCellType(sheet, axis string) (CellType, error) {
|
||||
// worksheet name and cell reference in spreadsheet file.
|
||||
func (f *File) GetCellType(sheet, cell string) (CellType, error) {
|
||||
var (
|
||||
err error
|
||||
cellTypeStr string
|
||||
cellType CellType
|
||||
)
|
||||
if cellTypeStr, err = f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
|
||||
if cellTypeStr, err = f.getCellStringFunc(sheet, cell, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
|
||||
return c.T, true, nil
|
||||
}); err != nil {
|
||||
return CellTypeUnset, err
|
||||
|
@ -110,39 +111,39 @@ func (f *File) GetCellType(sheet, axis string) (CellType, error) {
|
|||
// nil
|
||||
//
|
||||
// Note that default date format is m/d/yy h:mm of time.Time type value. You
|
||||
// can set numbers format by SetCellStyle() method. If you need to set the
|
||||
// can set numbers format by the SetCellStyle function. If you need to set the
|
||||
// specialized date in Excel like January 0, 1900 or February 29, 1900, these
|
||||
// times can not representation in Go language time.Time data type. Please set
|
||||
// the cell value as number 0 or 60, then create and bind the date-time number
|
||||
// format style for the cell.
|
||||
func (f *File) SetCellValue(sheet, axis string, value interface{}) error {
|
||||
func (f *File) SetCellValue(sheet, cell string, value interface{}) error {
|
||||
var err error
|
||||
switch v := value.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
err = f.setCellIntFunc(sheet, axis, v)
|
||||
err = f.setCellIntFunc(sheet, cell, v)
|
||||
case float32:
|
||||
err = f.SetCellFloat(sheet, axis, float64(v), -1, 32)
|
||||
err = f.SetCellFloat(sheet, cell, float64(v), -1, 32)
|
||||
case float64:
|
||||
err = f.SetCellFloat(sheet, axis, v, -1, 64)
|
||||
err = f.SetCellFloat(sheet, cell, v, -1, 64)
|
||||
case string:
|
||||
err = f.SetCellStr(sheet, axis, v)
|
||||
err = f.SetCellStr(sheet, cell, v)
|
||||
case []byte:
|
||||
err = f.SetCellStr(sheet, axis, string(v))
|
||||
err = f.SetCellStr(sheet, cell, string(v))
|
||||
case time.Duration:
|
||||
_, d := setCellDuration(v)
|
||||
err = f.SetCellDefault(sheet, axis, d)
|
||||
err = f.SetCellDefault(sheet, cell, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = f.setDefaultTimeStyle(sheet, axis, 21)
|
||||
err = f.setDefaultTimeStyle(sheet, cell, 21)
|
||||
case time.Time:
|
||||
err = f.setCellTimeFunc(sheet, axis, v)
|
||||
err = f.setCellTimeFunc(sheet, cell, v)
|
||||
case bool:
|
||||
err = f.SetCellBool(sheet, axis, v)
|
||||
err = f.SetCellBool(sheet, cell, v)
|
||||
case nil:
|
||||
err = f.SetCellDefault(sheet, axis, "")
|
||||
err = f.SetCellDefault(sheet, cell, "")
|
||||
default:
|
||||
err = f.SetCellStr(sheet, axis, fmt.Sprint(value))
|
||||
err = f.SetCellStr(sheet, cell, fmt.Sprint(value))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -188,58 +189,58 @@ func (f *File) removeFormula(c *xlsxC, ws *xlsxWorksheet, sheet string) {
|
|||
}
|
||||
|
||||
// setCellIntFunc is a wrapper of SetCellInt.
|
||||
func (f *File) setCellIntFunc(sheet, axis string, value interface{}) error {
|
||||
func (f *File) setCellIntFunc(sheet, cell string, value interface{}) error {
|
||||
var err error
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
err = f.SetCellInt(sheet, axis, v)
|
||||
err = f.SetCellInt(sheet, cell, v)
|
||||
case int8:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
case int16:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
case int32:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
case int64:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
case uint:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
case uint8:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
case uint16:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
case uint32:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
case uint64:
|
||||
err = f.SetCellInt(sheet, axis, int(v))
|
||||
err = f.SetCellInt(sheet, cell, int(v))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// setCellTimeFunc provides a method to process time type of value for
|
||||
// SetCellValue.
|
||||
func (f *File) setCellTimeFunc(sheet, axis string, value time.Time) error {
|
||||
func (f *File) setCellTimeFunc(sheet, cell string, value time.Time) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cellData, col, row, err := f.prepareCell(ws, axis)
|
||||
c, col, row, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ws.Lock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
ws.Unlock()
|
||||
date1904, wb := false, f.workbookReader()
|
||||
if wb != nil && wb.WorkbookPr != nil {
|
||||
date1904 = wb.WorkbookPr.Date1904
|
||||
}
|
||||
var isNum bool
|
||||
cellData.T, cellData.V, isNum, err = setCellTime(value, date1904)
|
||||
c.T, c.V, isNum, err = setCellTime(value, date1904)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isNum {
|
||||
_ = f.setDefaultTimeStyle(sheet, axis, 22)
|
||||
_ = f.setDefaultTimeStyle(sheet, cell, 22)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
@ -270,22 +271,22 @@ func setCellDuration(value time.Duration) (t string, v string) {
|
|||
}
|
||||
|
||||
// SetCellInt provides a function to set int type value of a cell by given
|
||||
// worksheet name, cell coordinates and cell value.
|
||||
func (f *File) SetCellInt(sheet, axis string, value int) error {
|
||||
// worksheet name, cell reference and cell value.
|
||||
func (f *File) SetCellInt(sheet, cell string, value int) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cellData, col, row, err := f.prepareCell(ws, axis)
|
||||
c, col, row, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ws.Lock()
|
||||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V = setCellInt(value)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
c.T, c.V = setCellInt(value)
|
||||
c.IS = nil
|
||||
f.removeFormula(c, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -297,22 +298,22 @@ func setCellInt(value int) (t string, v string) {
|
|||
}
|
||||
|
||||
// SetCellBool provides a function to set bool type value of a cell by given
|
||||
// worksheet name, cell name and cell value.
|
||||
func (f *File) SetCellBool(sheet, axis string, value bool) error {
|
||||
// worksheet name, cell reference and cell value.
|
||||
func (f *File) SetCellBool(sheet, cell string, value bool) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cellData, col, row, err := f.prepareCell(ws, axis)
|
||||
c, col, row, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ws.Lock()
|
||||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V = setCellBool(value)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
c.T, c.V = setCellBool(value)
|
||||
c.IS = nil
|
||||
f.removeFormula(c, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -328,29 +329,29 @@ func setCellBool(value bool) (t string, v string) {
|
|||
return
|
||||
}
|
||||
|
||||
// SetCellFloat sets a floating point value into a cell. The precision parameter
|
||||
// specifies how many places after the decimal will be shown while -1 is a
|
||||
// special value that will use as many decimal places as necessary to
|
||||
// represent the number. bitSize is 32 or 64 depending on if a float32 or
|
||||
// float64 was originally used for the value. For Example:
|
||||
// SetCellFloat sets a floating point value into a cell. The precision
|
||||
// parameter specifies how many places after the decimal will be shown
|
||||
// while -1 is a special value that will use as many decimal places as
|
||||
// necessary to represent the number. bitSize is 32 or 64 depending on if a
|
||||
// float32 or float64 was originally used for the value. For Example:
|
||||
//
|
||||
// var x float32 = 1.325
|
||||
// f.SetCellFloat("Sheet1", "A1", float64(x), 2, 32)
|
||||
func (f *File) SetCellFloat(sheet, axis string, value float64, precision, bitSize int) error {
|
||||
func (f *File) SetCellFloat(sheet, cell string, value float64, precision, bitSize int) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cellData, col, row, err := f.prepareCell(ws, axis)
|
||||
c, col, row, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ws.Lock()
|
||||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V = setCellFloat(value, precision, bitSize)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
c.T, c.V = setCellFloat(value, precision, bitSize)
|
||||
c.IS = nil
|
||||
f.removeFormula(c, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -363,21 +364,21 @@ func setCellFloat(value float64, precision, bitSize int) (t string, v string) {
|
|||
|
||||
// SetCellStr provides a function to set string type value of a cell. Total
|
||||
// number of characters that a cell can contain 32767 characters.
|
||||
func (f *File) SetCellStr(sheet, axis, value string) error {
|
||||
func (f *File) SetCellStr(sheet, cell, value string) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cellData, col, row, err := f.prepareCell(ws, axis)
|
||||
c, col, row, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ws.Lock()
|
||||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V, err = f.setCellString(value)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
c.T, c.V, err = f.setCellString(value)
|
||||
c.IS = nil
|
||||
f.removeFormula(c, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -463,21 +464,21 @@ func setCellStr(value string) (t string, v string, ns xml.Attr) {
|
|||
|
||||
// SetCellDefault provides a function to set string type value of a cell as
|
||||
// default format without escaping the cell.
|
||||
func (f *File) SetCellDefault(sheet, axis, value string) error {
|
||||
func (f *File) SetCellDefault(sheet, cell, value string) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cellData, col, row, err := f.prepareCell(ws, axis)
|
||||
c, col, row, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ws.Lock()
|
||||
defer ws.Unlock()
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
cellData.T, cellData.V = setCellDefault(value)
|
||||
cellData.IS = nil
|
||||
f.removeFormula(cellData, ws, sheet)
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
c.T, c.V = setCellDefault(value)
|
||||
c.IS = nil
|
||||
f.removeFormula(c, ws, sheet)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -492,9 +493,9 @@ func setCellDefault(value string) (t string, v string) {
|
|||
}
|
||||
|
||||
// GetCellFormula provides a function to get formula from cell by given
|
||||
// worksheet name and axis in XLSX file.
|
||||
func (f *File) GetCellFormula(sheet, axis string) (string, error) {
|
||||
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
|
||||
// worksheet name and cell reference in spreadsheet.
|
||||
func (f *File) GetCellFormula(sheet, cell string) (string, error) {
|
||||
return f.getCellStringFunc(sheet, cell, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
|
||||
if c.F == nil {
|
||||
return "", false, nil
|
||||
}
|
||||
|
@ -587,44 +588,44 @@ type FormulaOpts struct {
|
|||
// fmt.Println(err)
|
||||
// }
|
||||
// }
|
||||
func (f *File) SetCellFormula(sheet, axis, formula string, opts ...FormulaOpts) error {
|
||||
func (f *File) SetCellFormula(sheet, cell, formula string, opts ...FormulaOpts) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cellData, _, _, err := f.prepareCell(ws, axis)
|
||||
c, _, _, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if formula == "" {
|
||||
cellData.F = nil
|
||||
f.deleteCalcChain(f.getSheetID(sheet), axis)
|
||||
c.F = nil
|
||||
f.deleteCalcChain(f.getSheetID(sheet), cell)
|
||||
return err
|
||||
}
|
||||
|
||||
if cellData.F != nil {
|
||||
cellData.F.Content = formula
|
||||
if c.F != nil {
|
||||
c.F.Content = formula
|
||||
} else {
|
||||
cellData.F = &xlsxF{Content: formula}
|
||||
c.F = &xlsxF{Content: formula}
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
if o.Type != nil {
|
||||
if *o.Type == STCellFormulaTypeDataTable {
|
||||
for _, opt := range opts {
|
||||
if opt.Type != nil {
|
||||
if *opt.Type == STCellFormulaTypeDataTable {
|
||||
return err
|
||||
}
|
||||
cellData.F.T = *o.Type
|
||||
if cellData.F.T == STCellFormulaTypeShared {
|
||||
if err = ws.setSharedFormula(*o.Ref); err != nil {
|
||||
c.F.T = *opt.Type
|
||||
if c.F.T == STCellFormulaTypeShared {
|
||||
if err = ws.setSharedFormula(*opt.Ref); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if o.Ref != nil {
|
||||
cellData.F.Ref = *o.Ref
|
||||
if opt.Ref != nil {
|
||||
c.F.Ref = *opt.Ref
|
||||
}
|
||||
}
|
||||
cellData.IS = nil
|
||||
c.IS = nil
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -663,28 +664,28 @@ func (ws *xlsxWorksheet) countSharedFormula() (count int) {
|
|||
}
|
||||
|
||||
// GetCellHyperLink gets a cell hyperlink based on the given worksheet name and
|
||||
// cell coordinates. If the cell has a hyperlink, it will return 'true' and
|
||||
// cell reference. If the cell has a hyperlink, it will return 'true' and
|
||||
// the link address, otherwise it will return 'false' and an empty link
|
||||
// address.
|
||||
//
|
||||
// For example, get a hyperlink to a 'H6' cell on a worksheet named 'Sheet1':
|
||||
//
|
||||
// link, target, err := f.GetCellHyperLink("Sheet1", "H6")
|
||||
func (f *File) GetCellHyperLink(sheet, axis string) (bool, string, error) {
|
||||
func (f *File) GetCellHyperLink(sheet, cell string) (bool, string, error) {
|
||||
// Check for correct cell name
|
||||
if _, _, err := SplitCellName(axis); err != nil {
|
||||
if _, _, err := SplitCellName(cell); err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if axis, err = f.mergeCellsParser(ws, axis); err != nil {
|
||||
if cell, err = f.mergeCellsParser(ws, cell); err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if ws.Hyperlinks != nil {
|
||||
for _, link := range ws.Hyperlinks.Hyperlink {
|
||||
if link.Ref == axis {
|
||||
if link.Ref == cell {
|
||||
if link.RID != "" {
|
||||
return true, f.getSheetRelationshipsTargetByID(sheet, link.RID), err
|
||||
}
|
||||
|
@ -731,9 +732,9 @@ type HyperlinkOpts struct {
|
|||
// This is another example for "Location":
|
||||
//
|
||||
// err := f.SetCellHyperLink("Sheet1", "A3", "Sheet1!A40", "Location")
|
||||
func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...HyperlinkOpts) error {
|
||||
func (f *File) SetCellHyperLink(sheet, cell, link, linkType string, opts ...HyperlinkOpts) error {
|
||||
// Check for correct cell name
|
||||
if _, _, err := SplitCellName(axis); err != nil {
|
||||
if _, _, err := SplitCellName(cell); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -741,7 +742,7 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...Hype
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if axis, err = f.mergeCellsParser(ws, axis); err != nil {
|
||||
if cell, err = f.mergeCellsParser(ws, cell); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -751,7 +752,7 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...Hype
|
|||
ws.Hyperlinks = new(xlsxHyperlinks)
|
||||
}
|
||||
for i, hyperlink := range ws.Hyperlinks.Hyperlink {
|
||||
if hyperlink.Ref == axis {
|
||||
if hyperlink.Ref == cell {
|
||||
idx = i
|
||||
linkData = hyperlink
|
||||
break
|
||||
|
@ -768,13 +769,13 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...Hype
|
|||
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
|
||||
rID := f.setRels(linkData.RID, sheetRels, SourceRelationshipHyperLink, link, linkType)
|
||||
linkData = xlsxHyperlink{
|
||||
Ref: axis,
|
||||
Ref: cell,
|
||||
}
|
||||
linkData.RID = "rId" + strconv.Itoa(rID)
|
||||
f.addSheetNameSpace(sheet, SourceRelationship)
|
||||
case "Location":
|
||||
linkData = xlsxHyperlink{
|
||||
Ref: axis,
|
||||
Ref: cell,
|
||||
Location: link,
|
||||
}
|
||||
default:
|
||||
|
@ -837,12 +838,12 @@ func (f *File) GetCellRichText(sheet, cell string) (runs []RichTextRun, err erro
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
cellData, _, _, err := f.prepareCell(ws, cell)
|
||||
c, _, _, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
siIdx, err := strconv.Atoi(cellData.V)
|
||||
if err != nil || cellData.T != "s" {
|
||||
siIdx, err := strconv.Atoi(c.V)
|
||||
if err != nil || c.T != "s" {
|
||||
return
|
||||
}
|
||||
sst := f.sharedStringsReader()
|
||||
|
@ -1007,14 +1008,14 @@ func (f *File) SetCellRichText(sheet, cell string, runs []RichTextRun) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cellData, col, row, err := f.prepareCell(ws, cell)
|
||||
c, col, row, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.sharedStringsLoader(); err != nil {
|
||||
return err
|
||||
}
|
||||
cellData.S = f.prepareCellStyle(ws, col, row, cellData.S)
|
||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||
si := xlsxSI{}
|
||||
sst := f.sharedStringsReader()
|
||||
var textRuns []xlsxR
|
||||
|
@ -1035,39 +1036,39 @@ func (f *File) SetCellRichText(sheet, cell string, runs []RichTextRun) error {
|
|||
si.R = textRuns
|
||||
for idx, strItem := range sst.SI {
|
||||
if reflect.DeepEqual(strItem, si) {
|
||||
cellData.T, cellData.V = "s", strconv.Itoa(idx)
|
||||
c.T, c.V = "s", strconv.Itoa(idx)
|
||||
return err
|
||||
}
|
||||
}
|
||||
sst.SI = append(sst.SI, si)
|
||||
sst.Count++
|
||||
sst.UniqueCount++
|
||||
cellData.T, cellData.V = "s", strconv.Itoa(len(sst.SI)-1)
|
||||
c.T, c.V = "s", strconv.Itoa(len(sst.SI)-1)
|
||||
return err
|
||||
}
|
||||
|
||||
// SetSheetRow writes an array to row by given worksheet name, starting
|
||||
// coordinate and a pointer to array type 'slice'. This function is
|
||||
// cell reference and a pointer to array type 'slice'. This function is
|
||||
// concurrency safe. For example, writes an array to row 6 start with the cell
|
||||
// B6 on Sheet1:
|
||||
//
|
||||
// err := f.SetSheetRow("Sheet1", "B6", &[]interface{}{"1", nil, 2})
|
||||
func (f *File) SetSheetRow(sheet, axis string, slice interface{}) error {
|
||||
return f.setSheetCells(sheet, axis, slice, rows)
|
||||
func (f *File) SetSheetRow(sheet, cell string, slice interface{}) error {
|
||||
return f.setSheetCells(sheet, cell, slice, rows)
|
||||
}
|
||||
|
||||
// SetSheetCol writes an array to column by given worksheet name, starting
|
||||
// coordinate and a pointer to array type 'slice'. For example, writes an
|
||||
// cell reference and a pointer to array type 'slice'. For example, writes an
|
||||
// array to column B start with the cell B6 on Sheet1:
|
||||
//
|
||||
// err := f.SetSheetCol("Sheet1", "B6", &[]interface{}{"1", nil, 2})
|
||||
func (f *File) SetSheetCol(sheet, axis string, slice interface{}) error {
|
||||
return f.setSheetCells(sheet, axis, slice, columns)
|
||||
func (f *File) SetSheetCol(sheet, cell string, slice interface{}) error {
|
||||
return f.setSheetCells(sheet, cell, slice, columns)
|
||||
}
|
||||
|
||||
// setSheetCells provides a function to set worksheet cells value.
|
||||
func (f *File) setSheetCells(sheet, axis string, slice interface{}, dir adjustDirection) error {
|
||||
col, row, err := CellNameToCoordinates(axis)
|
||||
func (f *File) setSheetCells(sheet, cell string, slice interface{}, dir adjustDirection) error {
|
||||
col, row, err := CellNameToCoordinates(cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1117,16 +1118,16 @@ func (f *File) prepareCell(ws *xlsxWorksheet, cell string) (*xlsxC, int, int, er
|
|||
|
||||
// getCellStringFunc does common value extraction workflow for all GetCell*
|
||||
// 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, cell string, fn func(x *xlsxWorksheet, c *xlsxC) (string, bool, error)) (string, error) {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
axis, err = f.mergeCellsParser(ws, axis)
|
||||
cell, err = f.mergeCellsParser(ws, cell)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, row, err := CellNameToCoordinates(axis)
|
||||
_, row, err := CellNameToCoordinates(cell)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -1151,7 +1152,7 @@ func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c
|
|||
}
|
||||
for colIdx := range rowData.C {
|
||||
colData := &rowData.C[colIdx]
|
||||
if axis != colData.R {
|
||||
if cell != colData.R {
|
||||
continue
|
||||
}
|
||||
val, ok, err := fn(ws, colData)
|
||||
|
@ -1224,9 +1225,9 @@ func (f *File) prepareCellStyle(ws *xlsxWorksheet, col, row, style int) int {
|
|||
}
|
||||
|
||||
// mergeCellsParser provides a function to check merged cells in worksheet by
|
||||
// given axis.
|
||||
func (f *File) mergeCellsParser(ws *xlsxWorksheet, axis string) (string, error) {
|
||||
axis = strings.ToUpper(axis)
|
||||
// given cell reference.
|
||||
func (f *File) mergeCellsParser(ws *xlsxWorksheet, cell string) (string, error) {
|
||||
cell = strings.ToUpper(cell)
|
||||
if ws.MergeCells != nil {
|
||||
for i := 0; i < len(ws.MergeCells.Cells); i++ {
|
||||
if ws.MergeCells.Cells[i] == nil {
|
||||
|
@ -1234,20 +1235,20 @@ func (f *File) mergeCellsParser(ws *xlsxWorksheet, axis string) (string, error)
|
|||
i--
|
||||
continue
|
||||
}
|
||||
ok, err := f.checkCellInArea(axis, ws.MergeCells.Cells[i].Ref)
|
||||
ok, err := f.checkCellInArea(cell, ws.MergeCells.Cells[i].Ref)
|
||||
if err != nil {
|
||||
return axis, err
|
||||
return cell, err
|
||||
}
|
||||
if ok {
|
||||
axis = strings.Split(ws.MergeCells.Cells[i].Ref, ":")[0]
|
||||
cell = strings.Split(ws.MergeCells.Cells[i].Ref, ":")[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
return axis, nil
|
||||
return cell, nil
|
||||
}
|
||||
|
||||
// checkCellInArea provides a function to determine if a given coordinate is
|
||||
// within an area.
|
||||
// checkCellInArea provides a function to determine if a given cell reference
|
||||
// in a range.
|
||||
func (f *File) checkCellInArea(cell, area string) (bool, error) {
|
||||
col, row, err := CellNameToCoordinates(cell)
|
||||
if err != nil {
|
||||
|
@ -1333,11 +1334,11 @@ func parseSharedFormula(dCol, dRow int, orig []byte) (res string, start int) {
|
|||
//
|
||||
// Note that this function not validate ref tag to check the cell whether in
|
||||
// allow area, and always return origin shared formula.
|
||||
func getSharedFormula(ws *xlsxWorksheet, si int, axis string) string {
|
||||
func getSharedFormula(ws *xlsxWorksheet, si int, cell string) string {
|
||||
for _, r := range ws.SheetData.Row {
|
||||
for _, c := range r.C {
|
||||
if c.F != nil && c.F.Ref != "" && c.F.T == STCellFormulaTypeShared && c.F.Si != nil && *c.F.Si == si {
|
||||
col, row, _ := CellNameToCoordinates(axis)
|
||||
col, row, _ := CellNameToCoordinates(cell)
|
||||
sharedCol, sharedRow, _ := CellNameToCoordinates(c.R)
|
||||
dCol := col - sharedCol
|
||||
dRow := row - sharedRow
|
||||
|
|
|
@ -573,7 +573,7 @@ func TestGetCellRichText(t *testing.T) {
|
|||
// Test set cell rich text on not exists worksheet
|
||||
_, err = f.GetCellRichText("SheetN", "A1")
|
||||
assert.EqualError(t, err, "sheet SheetN does not exist")
|
||||
// Test set cell rich text with illegal cell coordinates
|
||||
// Test set cell rich text with illegal cell reference
|
||||
_, err = f.GetCellRichText("Sheet1", "A")
|
||||
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
}
|
||||
|
@ -670,7 +670,7 @@ func TestSetCellRichText(t *testing.T) {
|
|||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellRichText.xlsx")))
|
||||
// Test set cell rich text on not exists worksheet
|
||||
assert.EqualError(t, f.SetCellRichText("SheetN", "A1", richTextRun), "sheet SheetN does not exist")
|
||||
// Test set cell rich text with illegal cell coordinates
|
||||
// Test set cell rich text with illegal cell reference
|
||||
assert.EqualError(t, f.SetCellRichText("Sheet1", "A", richTextRun), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
richTextRun = []RichTextRun{{Text: strings.Repeat("s", TotalCellChars+1)}}
|
||||
// Test set cell rich text with characters over the maximum limit
|
||||
|
|
4
chart.go
4
chart.go
|
@ -984,8 +984,8 @@ func (f *File) getFormatChart(format string, combo []string) (*formatChart, []*f
|
|||
return formatSet, comboCharts, err
|
||||
}
|
||||
|
||||
// DeleteChart provides a function to delete chart in XLSX by given worksheet
|
||||
// and cell name.
|
||||
// DeleteChart provides a function to delete chart in spreadsheet by given
|
||||
// worksheet name and cell reference.
|
||||
func (f *File) DeleteChart(sheet, cell string) (err error) {
|
||||
col, row, err := CellNameToCoordinates(cell)
|
||||
if err != nil {
|
||||
|
|
|
@ -198,7 +198,7 @@ func TestAddChart(t *testing.T) {
|
|||
assert.NoError(t, f.AddChart("Combo Charts", axis, fmt.Sprintf(`{"type":"areaStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"%s"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true}}`, props[1]), fmt.Sprintf(`{"type":"%s","series":[{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true}}`, props[0])))
|
||||
}
|
||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddChart.xlsx")))
|
||||
// Test with illegal cell coordinates
|
||||
// Test with illegal cell reference
|
||||
assert.EqualError(t, f.AddChart("Sheet2", "A", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
// Test with unsupported chart type
|
||||
assert.EqualError(t, f.AddChart("Sheet2", "BD32", `{"type":"unknown","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Bubble 3D Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`), "unsupported chart type unknown")
|
||||
|
|
10
col_test.go
10
col_test.go
|
@ -207,7 +207,7 @@ func TestColumnVisibility(t *testing.T) {
|
|||
_, err = f.GetColVisible("SheetN", "F")
|
||||
assert.EqualError(t, err, "sheet SheetN does not exist")
|
||||
|
||||
// Test get column visible with illegal cell coordinates.
|
||||
// Test get column visible with illegal cell reference.
|
||||
_, err = f.GetColVisible("Sheet1", "*")
|
||||
assert.EqualError(t, err, newInvalidColumnNameError("*").Error())
|
||||
assert.EqualError(t, f.SetColVisible("Sheet1", "*", false), newInvalidColumnNameError("*").Error())
|
||||
|
@ -258,7 +258,7 @@ func TestOutlineLevel(t *testing.T) {
|
|||
_, err = f.GetRowOutlineLevel("SheetN", 1)
|
||||
assert.EqualError(t, err, "sheet SheetN does not exist")
|
||||
|
||||
// Test set and get column outline level with illegal cell coordinates.
|
||||
// Test set and get column outline level with illegal cell reference.
|
||||
assert.EqualError(t, f.SetColOutlineLevel("Sheet1", "*", 1), newInvalidColumnNameError("*").Error())
|
||||
_, err = f.GetColOutlineLevel("Sheet1", "*")
|
||||
assert.EqualError(t, err, newInvalidColumnNameError("*").Error())
|
||||
|
@ -329,7 +329,7 @@ func TestColWidth(t *testing.T) {
|
|||
assert.Equal(t, defaultColWidth, width)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test set and get column width with illegal cell coordinates.
|
||||
// Test set and get column width with illegal cell reference.
|
||||
width, err = f.GetColWidth("Sheet1", "*")
|
||||
assert.Equal(t, defaultColWidth, width)
|
||||
assert.EqualError(t, err, newInvalidColumnNameError("*").Error())
|
||||
|
@ -373,7 +373,7 @@ func TestInsertCols(t *testing.T) {
|
|||
assert.NoError(t, f.AutoFilter(sheet1, "A2", "B2", `{"column":"B","expression":"x != blanks"}`))
|
||||
assert.NoError(t, f.InsertCols(sheet1, "A", 1))
|
||||
|
||||
// Test insert column with illegal cell coordinates.
|
||||
// Test insert column with illegal cell reference.
|
||||
assert.EqualError(t, f.InsertCols(sheet1, "*", 1), newInvalidColumnNameError("*").Error())
|
||||
|
||||
assert.EqualError(t, f.InsertCols(sheet1, "A", 0), ErrColumnNumber.Error())
|
||||
|
@ -398,7 +398,7 @@ func TestRemoveCol(t *testing.T) {
|
|||
assert.NoError(t, f.RemoveCol(sheet1, "A"))
|
||||
assert.NoError(t, f.RemoveCol(sheet1, "A"))
|
||||
|
||||
// Test remove column with illegal cell coordinates.
|
||||
// Test remove column with illegal cell reference.
|
||||
assert.EqualError(t, f.RemoveCol("Sheet1", "*"), newInvalidColumnNameError("*").Error())
|
||||
|
||||
// Test remove column on not exists worksheet.
|
||||
|
|
|
@ -141,7 +141,7 @@ func (f *File) AddComment(sheet, cell, format string) error {
|
|||
}
|
||||
|
||||
// DeleteComment provides the method to delete comment in a sheet by given
|
||||
// worksheet. For example, delete the comment in Sheet1!$A$30:
|
||||
// worksheet name. For example, delete the comment in Sheet1!$A$30:
|
||||
//
|
||||
// err := f.DeleteComment("Sheet1", "A30")
|
||||
func (f *File) DeleteComment(sheet, cell string) (err error) {
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestAddComments(t *testing.T) {
|
|||
|
||||
// Test add comment on not exists worksheet.
|
||||
assert.EqualError(t, f.AddComment("SheetN", "B7", `{"author":"Excelize: ","text":"This is a comment."}`), "sheet SheetN does not exist")
|
||||
// Test add comment on with illegal cell coordinates
|
||||
// Test add comment on with illegal cell reference
|
||||
assert.EqualError(t, f.AddComment("Sheet1", "A", `{"author":"Excelize: ","text":"This is a comment."}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
if assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddComments.xlsx"))) {
|
||||
assert.Len(t, f.GetComments(), 2)
|
||||
|
|
22
crypt.go
22
crypt.go
|
@ -139,7 +139,7 @@ type encryption struct {
|
|||
// Decrypt API decrypts the CFB file format with ECMA-376 agile encryption and
|
||||
// standard encryption. Support cryptographic algorithm: MD4, MD5, RIPEMD-160,
|
||||
// SHA1, SHA256, SHA384 and SHA512 currently.
|
||||
func Decrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
|
||||
func Decrypt(raw []byte, opts *Options) (packageBuf []byte, err error) {
|
||||
doc, err := mscfb.New(bytes.NewReader(raw))
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -150,13 +150,13 @@ func Decrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
|
|||
return
|
||||
}
|
||||
if mechanism == "agile" {
|
||||
return agileDecrypt(encryptionInfoBuf, encryptedPackageBuf, opt)
|
||||
return agileDecrypt(encryptionInfoBuf, encryptedPackageBuf, opts)
|
||||
}
|
||||
return standardDecrypt(encryptionInfoBuf, encryptedPackageBuf, opt)
|
||||
return standardDecrypt(encryptionInfoBuf, encryptedPackageBuf, opts)
|
||||
}
|
||||
|
||||
// Encrypt API encrypt data with the password.
|
||||
func Encrypt(raw []byte, opt *Options) ([]byte, error) {
|
||||
func Encrypt(raw []byte, opts *Options) ([]byte, error) {
|
||||
encryptor := encryption{
|
||||
EncryptedVerifierHashInput: make([]byte, 16),
|
||||
EncryptedVerifierHashValue: make([]byte, 32),
|
||||
|
@ -166,7 +166,7 @@ func Encrypt(raw []byte, opt *Options) ([]byte, error) {
|
|||
SaltSize: 16,
|
||||
}
|
||||
// Key Encryption
|
||||
encryptionInfoBuffer, err := encryptor.standardKeyEncryption(opt.Password)
|
||||
encryptionInfoBuffer, err := encryptor.standardKeyEncryption(opts.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ func encryptionMechanism(buffer []byte) (mechanism string, err error) {
|
|||
// ECMA-376 Standard Encryption
|
||||
|
||||
// standardDecrypt decrypt the CFB file format with ECMA-376 standard encryption.
|
||||
func standardDecrypt(encryptionInfoBuf, encryptedPackageBuf []byte, opt *Options) ([]byte, error) {
|
||||
func standardDecrypt(encryptionInfoBuf, encryptedPackageBuf []byte, opts *Options) ([]byte, error) {
|
||||
encryptionHeaderSize := binary.LittleEndian.Uint32(encryptionInfoBuf[8:12])
|
||||
block := encryptionInfoBuf[12 : 12+encryptionHeaderSize]
|
||||
header := StandardEncryptionHeader{
|
||||
|
@ -254,7 +254,7 @@ func standardDecrypt(encryptionInfoBuf, encryptedPackageBuf []byte, opt *Options
|
|||
algorithm = "RC4"
|
||||
}
|
||||
verifier := standardEncryptionVerifier(algorithm, block)
|
||||
secretKey, err := standardConvertPasswdToKey(header, verifier, opt)
|
||||
secretKey, err := standardConvertPasswdToKey(header, verifier, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -289,9 +289,9 @@ func standardEncryptionVerifier(algorithm string, blob []byte) StandardEncryptio
|
|||
}
|
||||
|
||||
// standardConvertPasswdToKey generate intermediate key from given password.
|
||||
func standardConvertPasswdToKey(header StandardEncryptionHeader, verifier StandardEncryptionVerifier, opt *Options) ([]byte, error) {
|
||||
func standardConvertPasswdToKey(header StandardEncryptionHeader, verifier StandardEncryptionVerifier, opts *Options) ([]byte, error) {
|
||||
encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
|
||||
passwordBuffer, err := encoder.Bytes([]byte(opt.Password))
|
||||
passwordBuffer, err := encoder.Bytes([]byte(opts.Password))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -395,13 +395,13 @@ func (e *encryption) standardKeyEncryption(password string) ([]byte, error) {
|
|||
// agileDecrypt decrypt the CFB file format with ECMA-376 agile encryption.
|
||||
// Support cryptographic algorithm: MD4, MD5, RIPEMD-160, SHA1, SHA256,
|
||||
// SHA384 and SHA512.
|
||||
func agileDecrypt(encryptionInfoBuf, encryptedPackageBuf []byte, opt *Options) (packageBuf []byte, err error) {
|
||||
func agileDecrypt(encryptionInfoBuf, encryptedPackageBuf []byte, opts *Options) (packageBuf []byte, err error) {
|
||||
var encryptionInfo Encryption
|
||||
if encryptionInfo, err = parseEncryptionInfo(encryptionInfoBuf[8:]); err != nil {
|
||||
return
|
||||
}
|
||||
// Convert the password into an encryption key.
|
||||
key, err := convertPasswdToKey(opt.Password, blockKey, encryptionInfo)
|
||||
key, err := convertPasswdToKey(opts.Password, blockKey, encryptionInfo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
20
excelize.go
20
excelize.go
|
@ -98,12 +98,12 @@ type Options struct {
|
|||
// }
|
||||
//
|
||||
// Close the file by Close function after opening the spreadsheet.
|
||||
func OpenFile(filename string, opt ...Options) (*File, error) {
|
||||
func OpenFile(filename string, opts ...Options) (*File, error) {
|
||||
file, err := os.Open(filepath.Clean(filename))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := OpenReader(file, opt...)
|
||||
f, err := OpenReader(file, opts...)
|
||||
if err != nil {
|
||||
closeErr := file.Close()
|
||||
if closeErr == nil {
|
||||
|
@ -188,11 +188,11 @@ func OpenReader(r io.Reader, opts ...Options) (*File, error) {
|
|||
// parseOptions provides a function to parse the optional settings for open
|
||||
// and reading spreadsheet.
|
||||
func parseOptions(opts ...Options) *Options {
|
||||
opt := &Options{}
|
||||
for _, o := range opts {
|
||||
opt = &o
|
||||
options := &Options{}
|
||||
for _, opt := range opts {
|
||||
options = &opt
|
||||
}
|
||||
return opt
|
||||
return options
|
||||
}
|
||||
|
||||
// CharsetTranscoder Set user defined codepage transcoder function for open
|
||||
|
@ -207,16 +207,16 @@ func (f *File) xmlNewDecoder(rdr io.Reader) (ret *xml.Decoder) {
|
|||
}
|
||||
|
||||
// setDefaultTimeStyle provides a function to set default numbers format for
|
||||
// time.Time type cell value by given worksheet name, cell coordinates and
|
||||
// time.Time type cell value by given worksheet name, cell reference and
|
||||
// number format code.
|
||||
func (f *File) setDefaultTimeStyle(sheet, axis string, format int) error {
|
||||
s, err := f.GetCellStyle(sheet, axis)
|
||||
func (f *File) setDefaultTimeStyle(sheet, cell string, format int) error {
|
||||
s, err := f.GetCellStyle(sheet, cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s == 0 {
|
||||
style, _ := f.NewStyle(&Style{NumFmt: format})
|
||||
err = f.SetCellStyle(sheet, axis, axis, style)
|
||||
err = f.SetCellStyle(sheet, cell, cell, style)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ func TestOpenFile(t *testing.T) {
|
|||
assert.NoError(t, f.SetCellValue("Sheet2", "G5", time.Duration(1e13)))
|
||||
// Test completion column.
|
||||
assert.NoError(t, f.SetCellValue("Sheet2", "M2", nil))
|
||||
// Test read cell value with given axis large than exists row.
|
||||
// Test read cell value with given cell reference large than exists row.
|
||||
_, err = f.GetCellValue("Sheet2", "E231")
|
||||
assert.NoError(t, err)
|
||||
// Test get active worksheet of spreadsheet and get worksheet name of spreadsheet by given worksheet index.
|
||||
|
@ -336,7 +336,7 @@ func TestNewFile(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAddDrawingVML(t *testing.T) {
|
||||
// Test addDrawingVML with illegal cell coordinates.
|
||||
// Test addDrawingVML with illegal cell reference.
|
||||
f := NewFile()
|
||||
assert.EqualError(t, f.addDrawingVML(0, "", "*", 0, 0), newCellNameToCoordinatesError("*", newInvalidCellNameError("*")).Error())
|
||||
}
|
||||
|
|
22
lib.go
22
lib.go
|
@ -261,7 +261,7 @@ func CellNameToCoordinates(cell string) (int, int, error) {
|
|||
// excelize.CoordinatesToCellName(1, 1, true) // returns "$A$1", nil
|
||||
func CoordinatesToCellName(col, row int, abs ...bool) (string, error) {
|
||||
if col < 1 || row < 1 {
|
||||
return "", fmt.Errorf("invalid cell coordinates [%d, %d]", col, row)
|
||||
return "", fmt.Errorf("invalid cell reference [%d, %d]", col, row)
|
||||
}
|
||||
sign := ""
|
||||
for _, a := range abs {
|
||||
|
@ -273,7 +273,7 @@ func CoordinatesToCellName(col, row int, abs ...bool) (string, error) {
|
|||
return sign + colName + sign + strconv.Itoa(row), err
|
||||
}
|
||||
|
||||
// areaRefToCoordinates provides a function to convert area reference to a
|
||||
// areaRefToCoordinates provides a function to convert range reference to a
|
||||
// pair of coordinates.
|
||||
func areaRefToCoordinates(ref string) ([]int, error) {
|
||||
rng := strings.Split(strings.ReplaceAll(ref, "$", ""), ":")
|
||||
|
@ -296,7 +296,7 @@ func areaRangeToCoordinates(firstCell, lastCell string) ([]int, error) {
|
|||
return coordinates, err
|
||||
}
|
||||
|
||||
// sortCoordinates provides a function to correct the coordinate area, such
|
||||
// sortCoordinates provides a function to correct the cell range, such
|
||||
// correct C1:B3 to B1:C3.
|
||||
func sortCoordinates(coordinates []int) error {
|
||||
if len(coordinates) != 4 {
|
||||
|
@ -349,7 +349,7 @@ func (f *File) getDefinedNameRefTo(definedNameName string, currentSheet string)
|
|||
return
|
||||
}
|
||||
|
||||
// flatSqref convert reference sequence to cell coordinates list.
|
||||
// flatSqref convert reference sequence to cell reference list.
|
||||
func (f *File) flatSqref(sqref string) (cells map[int][][]int, err error) {
|
||||
var coordinates []int
|
||||
cells = make(map[int][][]int)
|
||||
|
@ -524,14 +524,14 @@ func namespaceStrictToTransitional(content []byte) []byte {
|
|||
return content
|
||||
}
|
||||
|
||||
// bytesReplace replace old bytes with given new.
|
||||
func bytesReplace(s, old, new []byte, n int) []byte {
|
||||
// bytesReplace replace source bytes with given target.
|
||||
func bytesReplace(s, source, target []byte, n int) []byte {
|
||||
if n == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
if len(old) < len(new) {
|
||||
return bytes.Replace(s, old, new, n)
|
||||
if len(source) < len(target) {
|
||||
return bytes.Replace(s, source, target, n)
|
||||
}
|
||||
|
||||
if n < 0 {
|
||||
|
@ -540,14 +540,14 @@ func bytesReplace(s, old, new []byte, n int) []byte {
|
|||
|
||||
var wid, i, j, w int
|
||||
for i, j = 0, 0; i < len(s) && j < n; j++ {
|
||||
wid = bytes.Index(s[i:], old)
|
||||
wid = bytes.Index(s[i:], source)
|
||||
if wid < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
w += copy(s[w:], s[i:i+wid])
|
||||
w += copy(s[w:], new)
|
||||
i += wid + len(old)
|
||||
w += copy(s[w:], target)
|
||||
i += wid + len(source)
|
||||
}
|
||||
|
||||
w += copy(s[w:], s[i:])
|
||||
|
|
|
@ -222,9 +222,9 @@ func TestCoordinatesToAreaRef(t *testing.T) {
|
|||
_, err := f.coordinatesToAreaRef([]int{})
|
||||
assert.EqualError(t, err, ErrCoordinates.Error())
|
||||
_, err = f.coordinatesToAreaRef([]int{1, -1, 1, 1})
|
||||
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
|
||||
assert.EqualError(t, err, "invalid cell reference [1, -1]")
|
||||
_, err = f.coordinatesToAreaRef([]int{1, 1, 1, -1})
|
||||
assert.EqualError(t, err, "invalid cell coordinates [1, -1]")
|
||||
assert.EqualError(t, err, "invalid cell reference [1, -1]")
|
||||
ref, err := f.coordinatesToAreaRef([]int{1, 1, 1, 1})
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, ref, "A1:A1")
|
||||
|
|
26
merge.go
26
merge.go
|
@ -22,7 +22,7 @@ func (mc *xlsxMergeCell) Rect() ([]int, error) {
|
|||
return mc.rect, err
|
||||
}
|
||||
|
||||
// MergeCell provides a function to merge cells by given coordinate area and
|
||||
// MergeCell provides a function to merge cells by given range reference and
|
||||
// sheet name. Merging cells only keeps the upper-left cell value, and
|
||||
// discards the other values. For example create a merged cell of D3:E9 on
|
||||
// Sheet1:
|
||||
|
@ -30,7 +30,7 @@ func (mc *xlsxMergeCell) Rect() ([]int, error) {
|
|||
// err := f.MergeCell("Sheet1", "D3", "E9")
|
||||
//
|
||||
// If you create a merged cell that overlaps with another existing merged cell,
|
||||
// those merged cells that already exist will be removed. The cell coordinates
|
||||
// those merged cells that already exist will be removed. The cell references
|
||||
// tuple after merging in the following range will be: A1(x3,y1) D1(x2,y1)
|
||||
// A8(x3,y4) D8(x2,y4)
|
||||
//
|
||||
|
@ -50,7 +50,7 @@ func (f *File) MergeCell(sheet, hCell, vCell string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Correct the coordinate area, such correct C1:B3 to B1:C3.
|
||||
// Correct the range reference, such correct C1:B3 to B1:C3.
|
||||
_ = sortCoordinates(rect)
|
||||
|
||||
hCell, _ = CoordinatesToCellName(rect[0], rect[1])
|
||||
|
@ -72,13 +72,13 @@ func (f *File) MergeCell(sheet, hCell, vCell string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// UnmergeCell provides a function to unmerge a given coordinate area.
|
||||
// UnmergeCell provides a function to unmerge a given range reference.
|
||||
// For example unmerge area D3:E9 on Sheet1:
|
||||
//
|
||||
// err := f.UnmergeCell("Sheet1", "D3", "E9")
|
||||
//
|
||||
// Attention: overlapped areas will also be unmerged.
|
||||
func (f *File) UnmergeCell(sheet string, hCell, vCell string) error {
|
||||
func (f *File) UnmergeCell(sheet, hCell, vCell string) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -90,7 +90,7 @@ func (f *File) UnmergeCell(sheet string, hCell, vCell string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Correct the coordinate area, such correct C1:B3 to B1:C3.
|
||||
// Correct the range reference, such correct C1:B3 to B1:C3.
|
||||
_ = sortCoordinates(rect1)
|
||||
|
||||
// return nil since no MergeCells in the sheet
|
||||
|
@ -135,8 +135,8 @@ func (f *File) GetMergeCells(sheet string) ([]MergeCell, error) {
|
|||
mergeCells = make([]MergeCell, 0, len(ws.MergeCells.Cells))
|
||||
for i := range ws.MergeCells.Cells {
|
||||
ref := ws.MergeCells.Cells[i].Ref
|
||||
axis := strings.Split(ref, ":")[0]
|
||||
val, _ := f.GetCellValue(sheet, axis)
|
||||
cell := strings.Split(ref, ":")[0]
|
||||
val, _ := f.GetCellValue(sheet, cell)
|
||||
mergeCells = append(mergeCells, []string{ref, val})
|
||||
}
|
||||
}
|
||||
|
@ -272,16 +272,14 @@ func (m *MergeCell) GetCellValue() string {
|
|||
return (*m)[1]
|
||||
}
|
||||
|
||||
// GetStartAxis returns the top left cell coordinates of merged range, for
|
||||
// GetStartAxis returns the top left cell reference of merged range, for
|
||||
// example: "C2".
|
||||
func (m *MergeCell) GetStartAxis() string {
|
||||
axis := strings.Split((*m)[0], ":")
|
||||
return axis[0]
|
||||
return strings.Split((*m)[0], ":")[0]
|
||||
}
|
||||
|
||||
// GetEndAxis returns the bottom right cell coordinates of merged range, for
|
||||
// GetEndAxis returns the bottom right cell reference of merged range, for
|
||||
// example: "D4".
|
||||
func (m *MergeCell) GetEndAxis() string {
|
||||
axis := strings.Split((*m)[0], ":")
|
||||
return axis[1]
|
||||
return strings.Split((*m)[0], ":")[1]
|
||||
}
|
||||
|
|
|
@ -512,8 +512,8 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
|
|||
}
|
||||
|
||||
// DeletePicture provides a function to delete charts in spreadsheet by given
|
||||
// worksheet and cell name. Note that the image file won't be deleted from the
|
||||
// document currently.
|
||||
// worksheet name and cell reference. Note that the image file won't be deleted
|
||||
// from the document currently.
|
||||
func (f *File) DeletePicture(sheet, cell string) (err error) {
|
||||
col, row, err := CellNameToCoordinates(cell)
|
||||
if err != nil {
|
||||
|
|
|
@ -57,7 +57,7 @@ func TestAddPicture(t *testing.T) {
|
|||
|
||||
// Test add picture to worksheet from bytes.
|
||||
assert.NoError(t, f.AddPictureFromBytes("Sheet1", "Q1", "", "Excel Logo", ".png", file))
|
||||
// Test add picture to worksheet from bytes with illegal cell coordinates.
|
||||
// Test add picture to worksheet from bytes with illegal cell reference.
|
||||
assert.EqualError(t, f.AddPictureFromBytes("Sheet1", "A", "", "Excel Logo", ".png", file), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
|
||||
assert.NoError(t, f.AddPicture("Sheet1", "Q8", filepath.Join("test", "images", "excel.gif"), ""))
|
||||
|
@ -118,7 +118,7 @@ func TestGetPicture(t *testing.T) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// Try to get picture from a worksheet with illegal cell coordinates.
|
||||
// Try to get picture from a worksheet with illegal cell reference.
|
||||
_, _, err = f.GetPicture("Sheet1", "A")
|
||||
assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
|
||||
|
@ -173,7 +173,7 @@ func TestGetPicture(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAddDrawingPicture(t *testing.T) {
|
||||
// Test addDrawingPicture with illegal cell coordinates.
|
||||
// Test addDrawingPicture with illegal cell reference.
|
||||
f := NewFile()
|
||||
assert.EqualError(t, f.addDrawingPicture("sheet1", "", "A", "", 0, 0, 0, 0, nil), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
}
|
||||
|
|
198
pivotTable.go
198
pivotTable.go
|
@ -27,26 +27,26 @@ import (
|
|||
// PivotStyleDark1 - PivotStyleDark28
|
||||
type PivotTableOption struct {
|
||||
pivotTableSheetName string
|
||||
DataRange string
|
||||
PivotTableRange string
|
||||
Rows []PivotTableField
|
||||
Columns []PivotTableField
|
||||
Data []PivotTableField
|
||||
Filter []PivotTableField
|
||||
RowGrandTotals bool
|
||||
ColGrandTotals bool
|
||||
ShowDrill bool
|
||||
UseAutoFormatting bool
|
||||
PageOverThenDown bool
|
||||
MergeItem bool
|
||||
CompactData bool
|
||||
ShowError bool
|
||||
ShowRowHeaders bool
|
||||
ShowColHeaders bool
|
||||
ShowRowStripes bool
|
||||
ShowColStripes bool
|
||||
ShowLastColumn bool
|
||||
PivotTableStyleName string
|
||||
DataRange string `json:"data_range"`
|
||||
PivotTableRange string `json:"pivot_table_range"`
|
||||
Rows []PivotTableField `json:"rows"`
|
||||
Columns []PivotTableField `json:"columns"`
|
||||
Data []PivotTableField `json:"data"`
|
||||
Filter []PivotTableField `json:"filter"`
|
||||
RowGrandTotals bool `json:"row_grand_totals"`
|
||||
ColGrandTotals bool `json:"col_grand_totals"`
|
||||
ShowDrill bool `json:"show_drill"`
|
||||
UseAutoFormatting bool `json:"use_auto_formatting"`
|
||||
PageOverThenDown bool `json:"page_over_then_down"`
|
||||
MergeItem bool `json:"merge_item"`
|
||||
CompactData bool `json:"compact_data"`
|
||||
ShowError bool `json:"show_error"`
|
||||
ShowRowHeaders bool `json:"show_row_headers"`
|
||||
ShowColHeaders bool `json:"show_col_headers"`
|
||||
ShowRowStripes bool `json:"show_row_stripes"`
|
||||
ShowColStripes bool `json:"show_col_stripes"`
|
||||
ShowLastColumn bool `json:"show_last_column"`
|
||||
PivotTableStyleName string `json:"pivot_table_style_name"`
|
||||
}
|
||||
|
||||
// PivotTableField directly maps the field settings of the pivot table.
|
||||
|
@ -69,12 +69,12 @@ type PivotTableOption struct {
|
|||
// Name specifies the name of the data field. Maximum 255 characters
|
||||
// are allowed in data field name, excess characters will be truncated.
|
||||
type PivotTableField struct {
|
||||
Compact bool
|
||||
Data string
|
||||
Name string
|
||||
Outline bool
|
||||
Subtotal string
|
||||
DefaultSubtotal bool
|
||||
Compact bool `json:"compact"`
|
||||
Data string `json:"data"`
|
||||
Name string `json:"name"`
|
||||
Outline bool `json:"outline"`
|
||||
Subtotal string `json:"subtotal"`
|
||||
DefaultSubtotal bool `json:"default_subtotal"`
|
||||
}
|
||||
|
||||
// AddPivotTable provides the method to add pivot table by given pivot table
|
||||
|
@ -128,9 +128,9 @@ type PivotTableField struct {
|
|||
// fmt.Println(err)
|
||||
// }
|
||||
// }
|
||||
func (f *File) AddPivotTable(opt *PivotTableOption) error {
|
||||
func (f *File) AddPivotTable(opts *PivotTableOption) error {
|
||||
// parameter validation
|
||||
_, pivotTableSheetPath, err := f.parseFormatPivotTableSet(opt)
|
||||
_, pivotTableSheetPath, err := f.parseFormatPivotTableSet(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ func (f *File) AddPivotTable(opt *PivotTableOption) error {
|
|||
sheetRelationshipsPivotTableXML := "../pivotTables/pivotTable" + strconv.Itoa(pivotTableID) + ".xml"
|
||||
pivotTableXML := strings.ReplaceAll(sheetRelationshipsPivotTableXML, "..", "xl")
|
||||
pivotCacheXML := "xl/pivotCache/pivotCacheDefinition" + strconv.Itoa(pivotCacheID) + ".xml"
|
||||
err = f.addPivotCache(pivotCacheXML, opt)
|
||||
err = f.addPivotCache(pivotCacheXML, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ func (f *File) AddPivotTable(opt *PivotTableOption) error {
|
|||
pivotCacheRels := "xl/pivotTables/_rels/pivotTable" + strconv.Itoa(pivotTableID) + ".xml.rels"
|
||||
// rId not used
|
||||
_ = f.addRels(pivotCacheRels, SourceRelationshipPivotCache, fmt.Sprintf("../pivotCache/pivotCacheDefinition%d.xml", pivotCacheID), "")
|
||||
err = f.addPivotTable(cacheID, pivotTableID, pivotTableXML, opt)
|
||||
err = f.addPivotTable(cacheID, pivotTableID, pivotTableXML, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -167,18 +167,18 @@ func (f *File) AddPivotTable(opt *PivotTableOption) error {
|
|||
|
||||
// parseFormatPivotTableSet provides a function to validate pivot table
|
||||
// properties.
|
||||
func (f *File) parseFormatPivotTableSet(opt *PivotTableOption) (*xlsxWorksheet, string, error) {
|
||||
if opt == nil {
|
||||
func (f *File) parseFormatPivotTableSet(opts *PivotTableOption) (*xlsxWorksheet, string, error) {
|
||||
if opts == nil {
|
||||
return nil, "", ErrParameterRequired
|
||||
}
|
||||
pivotTableSheetName, _, err := f.adjustRange(opt.PivotTableRange)
|
||||
pivotTableSheetName, _, err := f.adjustRange(opts.PivotTableRange)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("parameter 'PivotTableRange' parsing error: %s", err.Error())
|
||||
}
|
||||
opt.pivotTableSheetName = pivotTableSheetName
|
||||
dataRange := f.getDefinedNameRefTo(opt.DataRange, pivotTableSheetName)
|
||||
opts.pivotTableSheetName = pivotTableSheetName
|
||||
dataRange := f.getDefinedNameRefTo(opts.DataRange, pivotTableSheetName)
|
||||
if dataRange == "" {
|
||||
dataRange = opt.DataRange
|
||||
dataRange = opts.DataRange
|
||||
}
|
||||
dataSheetName, _, err := f.adjustRange(dataRange)
|
||||
if err != nil {
|
||||
|
@ -214,7 +214,7 @@ func (f *File) adjustRange(rangeStr string) (string, []int, error) {
|
|||
return rng[0], []int{}, ErrParameterInvalid
|
||||
}
|
||||
|
||||
// Correct the coordinate area, such correct C1:B3 to B1:C3.
|
||||
// Correct the range, such correct C1:B3 to B1:C3.
|
||||
if x2 < x1 {
|
||||
x1, x2 = x2, x1
|
||||
}
|
||||
|
@ -227,11 +227,11 @@ func (f *File) adjustRange(rangeStr string) (string, []int, error) {
|
|||
|
||||
// getPivotFieldsOrder provides a function to get order list of pivot table
|
||||
// fields.
|
||||
func (f *File) getPivotFieldsOrder(opt *PivotTableOption) ([]string, error) {
|
||||
func (f *File) getPivotFieldsOrder(opts *PivotTableOption) ([]string, error) {
|
||||
var order []string
|
||||
dataRange := f.getDefinedNameRefTo(opt.DataRange, opt.pivotTableSheetName)
|
||||
dataRange := f.getDefinedNameRefTo(opts.DataRange, opts.pivotTableSheetName)
|
||||
if dataRange == "" {
|
||||
dataRange = opt.DataRange
|
||||
dataRange = opts.DataRange
|
||||
}
|
||||
dataSheet, coordinates, err := f.adjustRange(dataRange)
|
||||
if err != nil {
|
||||
|
@ -249,20 +249,20 @@ func (f *File) getPivotFieldsOrder(opt *PivotTableOption) ([]string, error) {
|
|||
}
|
||||
|
||||
// addPivotCache provides a function to create a pivot cache by given properties.
|
||||
func (f *File) addPivotCache(pivotCacheXML string, opt *PivotTableOption) error {
|
||||
func (f *File) addPivotCache(pivotCacheXML string, opts *PivotTableOption) error {
|
||||
// validate data range
|
||||
definedNameRef := true
|
||||
dataRange := f.getDefinedNameRefTo(opt.DataRange, opt.pivotTableSheetName)
|
||||
dataRange := f.getDefinedNameRefTo(opts.DataRange, opts.pivotTableSheetName)
|
||||
if dataRange == "" {
|
||||
definedNameRef = false
|
||||
dataRange = opt.DataRange
|
||||
dataRange = opts.DataRange
|
||||
}
|
||||
dataSheet, coordinates, err := f.adjustRange(dataRange)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
||||
}
|
||||
// data range has been checked
|
||||
order, _ := f.getPivotFieldsOrder(opt)
|
||||
order, _ := f.getPivotFieldsOrder(opts)
|
||||
hCell, _ := CoordinatesToCellName(coordinates[0], coordinates[1])
|
||||
vCell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
|
||||
pc := xlsxPivotCacheDefinition{
|
||||
|
@ -281,11 +281,11 @@ func (f *File) addPivotCache(pivotCacheXML string, opt *PivotTableOption) error
|
|||
CacheFields: &xlsxCacheFields{},
|
||||
}
|
||||
if definedNameRef {
|
||||
pc.CacheSource.WorksheetSource = &xlsxWorksheetSource{Name: opt.DataRange}
|
||||
pc.CacheSource.WorksheetSource = &xlsxWorksheetSource{Name: opts.DataRange}
|
||||
}
|
||||
for _, name := range order {
|
||||
rowOptions, rowOk := f.getPivotTableFieldOptions(name, opt.Rows)
|
||||
columnOptions, colOk := f.getPivotTableFieldOptions(name, opt.Columns)
|
||||
rowOptions, rowOk := f.getPivotTableFieldOptions(name, opts.Rows)
|
||||
columnOptions, colOk := f.getPivotTableFieldOptions(name, opts.Columns)
|
||||
sharedItems := xlsxSharedItems{
|
||||
Count: 0,
|
||||
}
|
||||
|
@ -311,9 +311,9 @@ func (f *File) addPivotCache(pivotCacheXML string, opt *PivotTableOption) error
|
|||
|
||||
// addPivotTable provides a function to create a pivot table by given pivot
|
||||
// table ID and properties.
|
||||
func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, opt *PivotTableOption) error {
|
||||
func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, opts *PivotTableOption) error {
|
||||
// validate pivot table range
|
||||
_, coordinates, err := f.adjustRange(opt.PivotTableRange)
|
||||
_, coordinates, err := f.adjustRange(opts.PivotTableRange)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parameter 'PivotTableRange' parsing error: %s", err.Error())
|
||||
}
|
||||
|
@ -322,25 +322,25 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, op
|
|||
vCell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
|
||||
|
||||
pivotTableStyle := func() string {
|
||||
if opt.PivotTableStyleName == "" {
|
||||
if opts.PivotTableStyleName == "" {
|
||||
return "PivotStyleLight16"
|
||||
}
|
||||
return opt.PivotTableStyleName
|
||||
return opts.PivotTableStyleName
|
||||
}
|
||||
pt := xlsxPivotTableDefinition{
|
||||
Name: fmt.Sprintf("Pivot Table%d", pivotTableID),
|
||||
CacheID: cacheID,
|
||||
RowGrandTotals: &opt.RowGrandTotals,
|
||||
ColGrandTotals: &opt.ColGrandTotals,
|
||||
RowGrandTotals: &opts.RowGrandTotals,
|
||||
ColGrandTotals: &opts.ColGrandTotals,
|
||||
UpdatedVersion: pivotTableVersion,
|
||||
MinRefreshableVersion: pivotTableVersion,
|
||||
ShowDrill: &opt.ShowDrill,
|
||||
UseAutoFormatting: &opt.UseAutoFormatting,
|
||||
PageOverThenDown: &opt.PageOverThenDown,
|
||||
MergeItem: &opt.MergeItem,
|
||||
ShowDrill: &opts.ShowDrill,
|
||||
UseAutoFormatting: &opts.UseAutoFormatting,
|
||||
PageOverThenDown: &opts.PageOverThenDown,
|
||||
MergeItem: &opts.MergeItem,
|
||||
CreatedVersion: pivotTableVersion,
|
||||
CompactData: &opt.CompactData,
|
||||
ShowError: &opt.ShowError,
|
||||
CompactData: &opts.CompactData,
|
||||
ShowError: &opts.ShowError,
|
||||
DataCaption: "Values",
|
||||
Location: &xlsxLocation{
|
||||
Ref: hCell + ":" + vCell,
|
||||
|
@ -363,25 +363,25 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, op
|
|||
},
|
||||
PivotTableStyleInfo: &xlsxPivotTableStyleInfo{
|
||||
Name: pivotTableStyle(),
|
||||
ShowRowHeaders: opt.ShowRowHeaders,
|
||||
ShowColHeaders: opt.ShowColHeaders,
|
||||
ShowRowStripes: opt.ShowRowStripes,
|
||||
ShowColStripes: opt.ShowColStripes,
|
||||
ShowLastColumn: opt.ShowLastColumn,
|
||||
ShowRowHeaders: opts.ShowRowHeaders,
|
||||
ShowColHeaders: opts.ShowColHeaders,
|
||||
ShowRowStripes: opts.ShowRowStripes,
|
||||
ShowColStripes: opts.ShowColStripes,
|
||||
ShowLastColumn: opts.ShowLastColumn,
|
||||
},
|
||||
}
|
||||
|
||||
// pivot fields
|
||||
_ = f.addPivotFields(&pt, opt)
|
||||
_ = f.addPivotFields(&pt, opts)
|
||||
|
||||
// count pivot fields
|
||||
pt.PivotFields.Count = len(pt.PivotFields.PivotField)
|
||||
|
||||
// data range has been checked
|
||||
_ = f.addPivotRowFields(&pt, opt)
|
||||
_ = f.addPivotColFields(&pt, opt)
|
||||
_ = f.addPivotPageFields(&pt, opt)
|
||||
_ = f.addPivotDataFields(&pt, opt)
|
||||
_ = f.addPivotRowFields(&pt, opts)
|
||||
_ = f.addPivotColFields(&pt, opts)
|
||||
_ = f.addPivotPageFields(&pt, opts)
|
||||
_ = f.addPivotDataFields(&pt, opts)
|
||||
|
||||
pivotTable, err := xml.Marshal(pt)
|
||||
f.saveFileList(pivotTableXML, pivotTable)
|
||||
|
@ -390,9 +390,9 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, op
|
|||
|
||||
// addPivotRowFields provides a method to add row fields for pivot table by
|
||||
// given pivot table options.
|
||||
func (f *File) addPivotRowFields(pt *xlsxPivotTableDefinition, opt *PivotTableOption) error {
|
||||
func (f *File) addPivotRowFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
|
||||
// row fields
|
||||
rowFieldsIndex, err := f.getPivotFieldsIndex(opt.Rows, opt)
|
||||
rowFieldsIndex, err := f.getPivotFieldsIndex(opts.Rows, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -414,13 +414,13 @@ func (f *File) addPivotRowFields(pt *xlsxPivotTableDefinition, opt *PivotTableOp
|
|||
|
||||
// addPivotPageFields provides a method to add page fields for pivot table by
|
||||
// given pivot table options.
|
||||
func (f *File) addPivotPageFields(pt *xlsxPivotTableDefinition, opt *PivotTableOption) error {
|
||||
func (f *File) addPivotPageFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
|
||||
// page fields
|
||||
pageFieldsIndex, err := f.getPivotFieldsIndex(opt.Filter, opt)
|
||||
pageFieldsIndex, err := f.getPivotFieldsIndex(opts.Filter, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pageFieldsName := f.getPivotTableFieldsName(opt.Filter)
|
||||
pageFieldsName := f.getPivotTableFieldsName(opts.Filter)
|
||||
for idx, pageField := range pageFieldsIndex {
|
||||
if pt.PageFields == nil {
|
||||
pt.PageFields = &xlsxPageFields{}
|
||||
|
@ -440,14 +440,14 @@ func (f *File) addPivotPageFields(pt *xlsxPivotTableDefinition, opt *PivotTableO
|
|||
|
||||
// addPivotDataFields provides a method to add data fields for pivot table by
|
||||
// given pivot table options.
|
||||
func (f *File) addPivotDataFields(pt *xlsxPivotTableDefinition, opt *PivotTableOption) error {
|
||||
func (f *File) addPivotDataFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
|
||||
// data fields
|
||||
dataFieldsIndex, err := f.getPivotFieldsIndex(opt.Data, opt)
|
||||
dataFieldsIndex, err := f.getPivotFieldsIndex(opts.Data, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dataFieldsSubtotals := f.getPivotTableFieldsSubtotal(opt.Data)
|
||||
dataFieldsName := f.getPivotTableFieldsName(opt.Data)
|
||||
dataFieldsSubtotals := f.getPivotTableFieldsSubtotal(opts.Data)
|
||||
dataFieldsName := f.getPivotTableFieldsName(opts.Data)
|
||||
for idx, dataField := range dataFieldsIndex {
|
||||
if pt.DataFields == nil {
|
||||
pt.DataFields = &xlsxDataFields{}
|
||||
|
@ -480,9 +480,9 @@ func inPivotTableField(a []PivotTableField, x string) int {
|
|||
|
||||
// addPivotColFields create pivot column fields by given pivot table
|
||||
// definition and option.
|
||||
func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opt *PivotTableOption) error {
|
||||
if len(opt.Columns) == 0 {
|
||||
if len(opt.Data) <= 1 {
|
||||
func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
|
||||
if len(opts.Columns) == 0 {
|
||||
if len(opts.Data) <= 1 {
|
||||
return nil
|
||||
}
|
||||
pt.ColFields = &xlsxColFields{}
|
||||
|
@ -497,7 +497,7 @@ func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opt *PivotTableOp
|
|||
pt.ColFields = &xlsxColFields{}
|
||||
|
||||
// col fields
|
||||
colFieldsIndex, err := f.getPivotFieldsIndex(opt.Columns, opt)
|
||||
colFieldsIndex, err := f.getPivotFieldsIndex(opts.Columns, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -508,7 +508,7 @@ func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opt *PivotTableOp
|
|||
}
|
||||
|
||||
// in order to create pivot in case there is many Columns and Data
|
||||
if len(opt.Data) > 1 {
|
||||
if len(opts.Data) > 1 {
|
||||
pt.ColFields.Field = append(pt.ColFields.Field, &xlsxField{
|
||||
X: -2,
|
||||
})
|
||||
|
@ -521,15 +521,15 @@ func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opt *PivotTableOp
|
|||
|
||||
// addPivotFields create pivot fields based on the column order of the first
|
||||
// row in the data region by given pivot table definition and option.
|
||||
func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOption) error {
|
||||
order, err := f.getPivotFieldsOrder(opt)
|
||||
func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOption) error {
|
||||
order, err := f.getPivotFieldsOrder(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
x := 0
|
||||
for _, name := range order {
|
||||
if inPivotTableField(opt.Rows, name) != -1 {
|
||||
rowOptions, ok := f.getPivotTableFieldOptions(name, opt.Rows)
|
||||
if inPivotTableField(opts.Rows, name) != -1 {
|
||||
rowOptions, ok := f.getPivotTableFieldOptions(name, opts.Rows)
|
||||
var items []*xlsxItem
|
||||
if !ok || !rowOptions.DefaultSubtotal {
|
||||
items = append(items, &xlsxItem{X: &x})
|
||||
|
@ -538,9 +538,9 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOptio
|
|||
}
|
||||
|
||||
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
|
||||
Name: f.getPivotTableFieldName(name, opt.Rows),
|
||||
Name: f.getPivotTableFieldName(name, opts.Rows),
|
||||
Axis: "axisRow",
|
||||
DataField: inPivotTableField(opt.Data, name) != -1,
|
||||
DataField: inPivotTableField(opts.Data, name) != -1,
|
||||
Compact: &rowOptions.Compact,
|
||||
Outline: &rowOptions.Outline,
|
||||
DefaultSubtotal: &rowOptions.DefaultSubtotal,
|
||||
|
@ -551,11 +551,11 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOptio
|
|||
})
|
||||
continue
|
||||
}
|
||||
if inPivotTableField(opt.Filter, name) != -1 {
|
||||
if inPivotTableField(opts.Filter, name) != -1 {
|
||||
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
|
||||
Axis: "axisPage",
|
||||
DataField: inPivotTableField(opt.Data, name) != -1,
|
||||
Name: f.getPivotTableFieldName(name, opt.Columns),
|
||||
DataField: inPivotTableField(opts.Data, name) != -1,
|
||||
Name: f.getPivotTableFieldName(name, opts.Columns),
|
||||
Items: &xlsxItems{
|
||||
Count: 1,
|
||||
Item: []*xlsxItem{
|
||||
|
@ -565,8 +565,8 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOptio
|
|||
})
|
||||
continue
|
||||
}
|
||||
if inPivotTableField(opt.Columns, name) != -1 {
|
||||
columnOptions, ok := f.getPivotTableFieldOptions(name, opt.Columns)
|
||||
if inPivotTableField(opts.Columns, name) != -1 {
|
||||
columnOptions, ok := f.getPivotTableFieldOptions(name, opts.Columns)
|
||||
var items []*xlsxItem
|
||||
if !ok || !columnOptions.DefaultSubtotal {
|
||||
items = append(items, &xlsxItem{X: &x})
|
||||
|
@ -574,9 +574,9 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOptio
|
|||
items = append(items, &xlsxItem{T: "default"})
|
||||
}
|
||||
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
|
||||
Name: f.getPivotTableFieldName(name, opt.Columns),
|
||||
Name: f.getPivotTableFieldName(name, opts.Columns),
|
||||
Axis: "axisCol",
|
||||
DataField: inPivotTableField(opt.Data, name) != -1,
|
||||
DataField: inPivotTableField(opts.Data, name) != -1,
|
||||
Compact: &columnOptions.Compact,
|
||||
Outline: &columnOptions.Outline,
|
||||
DefaultSubtotal: &columnOptions.DefaultSubtotal,
|
||||
|
@ -587,7 +587,7 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOptio
|
|||
})
|
||||
continue
|
||||
}
|
||||
if inPivotTableField(opt.Data, name) != -1 {
|
||||
if inPivotTableField(opts.Data, name) != -1 {
|
||||
pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
|
||||
DataField: true,
|
||||
})
|
||||
|
@ -626,9 +626,9 @@ func (f *File) countPivotCache() int {
|
|||
|
||||
// getPivotFieldsIndex convert the column of the first row in the data region
|
||||
// to a sequential index by given fields and pivot option.
|
||||
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opt *PivotTableOption) ([]int, error) {
|
||||
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opts *PivotTableOption) ([]int, error) {
|
||||
var pivotFieldsIndex []int
|
||||
orders, err := f.getPivotFieldsOrder(opt)
|
||||
orders, err := f.getPivotFieldsOrder(opts)
|
||||
if err != nil {
|
||||
return pivotFieldsIndex, err
|
||||
}
|
||||
|
|
|
@ -880,7 +880,7 @@ func TestDuplicateRowTo(t *testing.T) {
|
|||
assert.Equal(t, nil, f.DuplicateRowTo(sheetName, 1, 1))
|
||||
// Test duplicate row on the blank worksheet
|
||||
assert.Equal(t, nil, f.DuplicateRowTo(sheetName, 1, 2))
|
||||
// Test duplicate row on the worksheet with illegal cell coordinates
|
||||
// Test duplicate row on the worksheet with illegal cell reference
|
||||
f.Sheet.Store("xl/worksheets/sheet1.xml", &xlsxWorksheet{
|
||||
MergeCells: &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: "A:B1"}}},
|
||||
})
|
||||
|
|
39
sheet.go
39
sheet.go
|
@ -329,23 +329,23 @@ func (f *File) getActiveSheetID() int {
|
|||
return 0
|
||||
}
|
||||
|
||||
// SetSheetName provides a function to set the worksheet name by given old and
|
||||
// new worksheet names. Maximum 31 characters are allowed in sheet title and
|
||||
// SetSheetName provides a function to set the worksheet name by given source and
|
||||
// target worksheet names. Maximum 31 characters are allowed in sheet title and
|
||||
// this function only changes the name of the sheet and will not update the
|
||||
// sheet name in the formula or reference associated with the cell. So there
|
||||
// may be problem formula error or reference missing.
|
||||
func (f *File) SetSheetName(oldName, newName string) {
|
||||
oldName = trimSheetName(oldName)
|
||||
newName = trimSheetName(newName)
|
||||
if strings.EqualFold(newName, oldName) {
|
||||
func (f *File) SetSheetName(source, target string) {
|
||||
source = trimSheetName(source)
|
||||
target = trimSheetName(target)
|
||||
if strings.EqualFold(target, source) {
|
||||
return
|
||||
}
|
||||
content := f.workbookReader()
|
||||
for k, v := range content.Sheets.Sheet {
|
||||
if v.Name == oldName {
|
||||
content.Sheets.Sheet[k].Name = newName
|
||||
f.sheetMap[newName] = f.sheetMap[oldName]
|
||||
delete(f.sheetMap, oldName)
|
||||
if v.Name == source {
|
||||
content.Sheets.Sheet[k].Name = target
|
||||
f.sheetMap[target] = f.sheetMap[source]
|
||||
delete(f.sheetMap, source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -815,17 +815,17 @@ func (f *File) GetSheetVisible(sheet string) bool {
|
|||
return visible
|
||||
}
|
||||
|
||||
// SearchSheet provides a function to get coordinates by given worksheet name,
|
||||
// SearchSheet provides a function to get cell reference by given worksheet name,
|
||||
// cell value, and regular expression. The function doesn't support searching
|
||||
// on the calculated result, formatted numbers and conditional lookup
|
||||
// currently. If it is a merged cell, it will return the coordinates of the
|
||||
// upper left corner of the merged area.
|
||||
// currently. If it is a merged cell, it will return the cell reference of the
|
||||
// upper left cell of the merged range reference.
|
||||
//
|
||||
// An example of search the coordinates of the value of "100" on Sheet1:
|
||||
// An example of search the cell reference of the value of "100" on Sheet1:
|
||||
//
|
||||
// result, err := f.SearchSheet("Sheet1", "100")
|
||||
//
|
||||
// An example of search the coordinates where the numerical value in the range
|
||||
// An example of search the cell reference where the numerical value in the range
|
||||
// of "0-9" of Sheet1 is described:
|
||||
//
|
||||
// result, err := f.SearchSheet("Sheet1", "[0-9]", true)
|
||||
|
@ -849,8 +849,8 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
|
|||
return f.searchSheet(name, value, regSearch)
|
||||
}
|
||||
|
||||
// searchSheet provides a function to get coordinates by given worksheet name,
|
||||
// cell value, and regular expression.
|
||||
// searchSheet provides a function to get cell reference by given worksheet
|
||||
// name, cell value, and regular expression.
|
||||
func (f *File) searchSheet(name, value string, regSearch bool) (result []string, err error) {
|
||||
var (
|
||||
cellName, inElement string
|
||||
|
@ -1684,7 +1684,7 @@ func (f *File) UngroupSheets() error {
|
|||
}
|
||||
|
||||
// InsertPageBreak create a page break to determine where the printed page
|
||||
// ends and where begins the next one by given worksheet name and axis, so the
|
||||
// ends and where begins the next one by given worksheet name and cell reference, so the
|
||||
// content before the page break will be printed on one page and after the
|
||||
// page break on another.
|
||||
func (f *File) InsertPageBreak(sheet, cell string) (err error) {
|
||||
|
@ -1741,7 +1741,8 @@ func (f *File) InsertPageBreak(sheet, cell string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// RemovePageBreak remove a page break by given worksheet name and axis.
|
||||
// RemovePageBreak remove a page break by given worksheet name and cell
|
||||
// reference.
|
||||
func (f *File) RemovePageBreak(sheet, cell string) (err error) {
|
||||
var ws *xlsxWorksheet
|
||||
var row, col int
|
||||
|
|
|
@ -130,8 +130,8 @@ func TestPageLayoutOption(t *testing.T) {
|
|||
|
||||
for i, test := range testData {
|
||||
t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
|
||||
opt := test.nonDefault
|
||||
t.Logf("option %T", opt)
|
||||
opts := test.nonDefault
|
||||
t.Logf("option %T", opts)
|
||||
|
||||
def := deepcopy.Copy(test.container).(PageLayoutOptionPtr)
|
||||
val1 := deepcopy.Copy(def).(PageLayoutOptionPtr)
|
||||
|
@ -139,34 +139,34 @@ func TestPageLayoutOption(t *testing.T) {
|
|||
|
||||
f := NewFile()
|
||||
// Get the default value
|
||||
assert.NoError(t, f.GetPageLayout(sheet, def), opt)
|
||||
assert.NoError(t, f.GetPageLayout(sheet, def), opts)
|
||||
// Get again and check
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val1), opt)
|
||||
if !assert.Equal(t, val1, def, opt) {
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val1), opts)
|
||||
if !assert.Equal(t, val1, def, opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Set the same value
|
||||
assert.NoError(t, f.SetPageLayout(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetPageLayout(sheet, val1), opts)
|
||||
// Get again and check
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val1), opt)
|
||||
if !assert.Equal(t, val1, def, "%T: value should not have changed", opt) {
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val1), opts)
|
||||
if !assert.Equal(t, val1, def, "%T: value should not have changed", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Set a different value
|
||||
assert.NoError(t, f.SetPageLayout(sheet, test.nonDefault), opt)
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetPageLayout(sheet, test.nonDefault), opts)
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val1), opts)
|
||||
// Get again and compare
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val2), opt)
|
||||
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opt) {
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val2), opts)
|
||||
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Value should not be the same as the default
|
||||
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opt) {
|
||||
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Restore the default value
|
||||
assert.NoError(t, f.SetPageLayout(sheet, def), opt)
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetPageLayout(sheet, def), opts)
|
||||
assert.NoError(t, f.GetPageLayout(sheet, val1), opts)
|
||||
if !assert.Equal(t, def, val1) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ func TestSearchSheet(t *testing.T) {
|
|||
|
||||
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="0"><c r="A1" t="str"><v>A</v></c></row></sheetData></worksheet>`))
|
||||
result, err = f.SearchSheet("Sheet1", "A")
|
||||
assert.EqualError(t, err, "invalid cell coordinates [1, 0]")
|
||||
assert.EqualError(t, err, "invalid cell reference [1, 0]")
|
||||
assert.Equal(t, []string(nil), result)
|
||||
}
|
||||
|
||||
|
|
|
@ -132,8 +132,8 @@ func TestSheetPrOptions(t *testing.T) {
|
|||
|
||||
for i, test := range testData {
|
||||
t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
|
||||
opt := test.nonDefault
|
||||
t.Logf("option %T", opt)
|
||||
opts := test.nonDefault
|
||||
t.Logf("option %T", opts)
|
||||
|
||||
def := deepcopy.Copy(test.container).(SheetPrOptionPtr)
|
||||
val1 := deepcopy.Copy(def).(SheetPrOptionPtr)
|
||||
|
@ -141,34 +141,34 @@ func TestSheetPrOptions(t *testing.T) {
|
|||
|
||||
f := NewFile()
|
||||
// Get the default value
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, def), opt)
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, def), opts)
|
||||
// Get again and check
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opt)
|
||||
if !assert.Equal(t, val1, def, opt) {
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opts)
|
||||
if !assert.Equal(t, val1, def, opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Set the same value
|
||||
assert.NoError(t, f.SetSheetPrOptions(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetSheetPrOptions(sheet, val1), opts)
|
||||
// Get again and check
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opt)
|
||||
if !assert.Equal(t, val1, def, "%T: value should not have changed", opt) {
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opts)
|
||||
if !assert.Equal(t, val1, def, "%T: value should not have changed", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Set a different value
|
||||
assert.NoError(t, f.SetSheetPrOptions(sheet, test.nonDefault), opt)
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetSheetPrOptions(sheet, test.nonDefault), opts)
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opts)
|
||||
// Get again and compare
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val2), opt)
|
||||
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opt) {
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val2), opts)
|
||||
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Value should not be the same as the default
|
||||
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opt) {
|
||||
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Restore the default value
|
||||
assert.NoError(t, f.SetSheetPrOptions(sheet, def), opt)
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetSheetPrOptions(sheet, def), opts)
|
||||
assert.NoError(t, f.GetSheetPrOptions(sheet, val1), opts)
|
||||
if !assert.Equal(t, def, val1) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
@ -281,8 +281,8 @@ func TestPageMarginsOption(t *testing.T) {
|
|||
|
||||
for i, test := range testData {
|
||||
t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
|
||||
opt := test.nonDefault
|
||||
t.Logf("option %T", opt)
|
||||
opts := test.nonDefault
|
||||
t.Logf("option %T", opts)
|
||||
|
||||
def := deepcopy.Copy(test.container).(PageMarginsOptionsPtr)
|
||||
val1 := deepcopy.Copy(def).(PageMarginsOptionsPtr)
|
||||
|
@ -290,34 +290,34 @@ func TestPageMarginsOption(t *testing.T) {
|
|||
|
||||
f := NewFile()
|
||||
// Get the default value
|
||||
assert.NoError(t, f.GetPageMargins(sheet, def), opt)
|
||||
assert.NoError(t, f.GetPageMargins(sheet, def), opts)
|
||||
// Get again and check
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val1), opt)
|
||||
if !assert.Equal(t, val1, def, opt) {
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val1), opts)
|
||||
if !assert.Equal(t, val1, def, opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Set the same value
|
||||
assert.NoError(t, f.SetPageMargins(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetPageMargins(sheet, val1), opts)
|
||||
// Get again and check
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val1), opt)
|
||||
if !assert.Equal(t, val1, def, "%T: value should not have changed", opt) {
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val1), opts)
|
||||
if !assert.Equal(t, val1, def, "%T: value should not have changed", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Set a different value
|
||||
assert.NoError(t, f.SetPageMargins(sheet, test.nonDefault), opt)
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetPageMargins(sheet, test.nonDefault), opts)
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val1), opts)
|
||||
// Get again and compare
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val2), opt)
|
||||
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opt) {
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val2), opts)
|
||||
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Value should not be the same as the default
|
||||
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opt) {
|
||||
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Restore the default value
|
||||
assert.NoError(t, f.SetPageMargins(sheet, def), opt)
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetPageMargins(sheet, def), opts)
|
||||
assert.NoError(t, f.GetPageMargins(sheet, val1), opts)
|
||||
if !assert.Equal(t, def, val1) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
@ -417,8 +417,8 @@ func TestSheetFormatPrOptions(t *testing.T) {
|
|||
|
||||
for i, test := range testData {
|
||||
t.Run(fmt.Sprintf("TestData%d", i), func(t *testing.T) {
|
||||
opt := test.nonDefault
|
||||
t.Logf("option %T", opt)
|
||||
opts := test.nonDefault
|
||||
t.Logf("option %T", opts)
|
||||
|
||||
def := deepcopy.Copy(test.container).(SheetFormatPrOptionsPtr)
|
||||
val1 := deepcopy.Copy(def).(SheetFormatPrOptionsPtr)
|
||||
|
@ -426,34 +426,34 @@ func TestSheetFormatPrOptions(t *testing.T) {
|
|||
|
||||
f := NewFile()
|
||||
// Get the default value
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, def), opt)
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, def), opts)
|
||||
// Get again and check
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opt)
|
||||
if !assert.Equal(t, val1, def, opt) {
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opts)
|
||||
if !assert.Equal(t, val1, def, opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Set the same value
|
||||
assert.NoError(t, f.SetSheetFormatPr(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetSheetFormatPr(sheet, val1), opts)
|
||||
// Get again and check
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opt)
|
||||
if !assert.Equal(t, val1, def, "%T: value should not have changed", opt) {
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opts)
|
||||
if !assert.Equal(t, val1, def, "%T: value should not have changed", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Set a different value
|
||||
assert.NoError(t, f.SetSheetFormatPr(sheet, test.nonDefault), opt)
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetSheetFormatPr(sheet, test.nonDefault), opts)
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opts)
|
||||
// Get again and compare
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val2), opt)
|
||||
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opt) {
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val2), opts)
|
||||
if !assert.Equal(t, val1, val2, "%T: value should not have changed", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Value should not be the same as the default
|
||||
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opt) {
|
||||
if !assert.NotEqual(t, def, val1, "%T: value should have changed from default", opts) {
|
||||
t.FailNow()
|
||||
}
|
||||
// Restore the default value
|
||||
assert.NoError(t, f.SetSheetFormatPr(sheet, def), opt)
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opt)
|
||||
assert.NoError(t, f.SetSheetFormatPr(sheet, def), opts)
|
||||
assert.NoError(t, f.GetSheetFormatPr(sheet, val1), opts)
|
||||
if !assert.Equal(t, def, val1) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
|
54
sparkline.go
54
sparkline.go
|
@ -387,7 +387,7 @@ func (f *File) addSparklineGroupByStyle(ID int) *xlsxX14SparklineGroup {
|
|||
// Markers | Toggle sparkline markers
|
||||
// ColorAxis | An RGB Color is specified as RRGGBB
|
||||
// Axis | Show sparkline axis
|
||||
func (f *File) AddSparkline(sheet string, opt *SparklineOption) (err error) {
|
||||
func (f *File) AddSparkline(sheet string, opts *SparklineOption) (err error) {
|
||||
var (
|
||||
ws *xlsxWorksheet
|
||||
sparkType string
|
||||
|
@ -400,39 +400,39 @@ func (f *File) AddSparkline(sheet string, opt *SparklineOption) (err error) {
|
|||
)
|
||||
|
||||
// parameter validation
|
||||
if ws, err = f.parseFormatAddSparklineSet(sheet, opt); err != nil {
|
||||
if ws, err = f.parseFormatAddSparklineSet(sheet, opts); err != nil {
|
||||
return
|
||||
}
|
||||
// Handle the sparkline type
|
||||
sparkType = "line"
|
||||
sparkTypes = map[string]string{"line": "line", "column": "column", "win_loss": "stacked"}
|
||||
if opt.Type != "" {
|
||||
if specifiedSparkTypes, ok = sparkTypes[opt.Type]; !ok {
|
||||
if opts.Type != "" {
|
||||
if specifiedSparkTypes, ok = sparkTypes[opts.Type]; !ok {
|
||||
err = ErrSparklineType
|
||||
return
|
||||
}
|
||||
sparkType = specifiedSparkTypes
|
||||
}
|
||||
group = f.addSparklineGroupByStyle(opt.Style)
|
||||
group = f.addSparklineGroupByStyle(opts.Style)
|
||||
group.Type = sparkType
|
||||
group.ColorAxis = &xlsxColor{RGB: "FF000000"}
|
||||
group.DisplayEmptyCellsAs = "gap"
|
||||
group.High = opt.High
|
||||
group.Low = opt.Low
|
||||
group.First = opt.First
|
||||
group.Last = opt.Last
|
||||
group.Negative = opt.Negative
|
||||
group.DisplayXAxis = opt.Axis
|
||||
group.Markers = opt.Markers
|
||||
if opt.SeriesColor != "" {
|
||||
group.High = opts.High
|
||||
group.Low = opts.Low
|
||||
group.First = opts.First
|
||||
group.Last = opts.Last
|
||||
group.Negative = opts.Negative
|
||||
group.DisplayXAxis = opts.Axis
|
||||
group.Markers = opts.Markers
|
||||
if opts.SeriesColor != "" {
|
||||
group.ColorSeries = &xlsxTabColor{
|
||||
RGB: getPaletteColor(opt.SeriesColor),
|
||||
RGB: getPaletteColor(opts.SeriesColor),
|
||||
}
|
||||
}
|
||||
if opt.Reverse {
|
||||
group.RightToLeft = opt.Reverse
|
||||
if opts.Reverse {
|
||||
group.RightToLeft = opts.Reverse
|
||||
}
|
||||
f.addSparkline(opt, group)
|
||||
f.addSparkline(opts, group)
|
||||
if ws.ExtLst.Ext != "" { // append mode ext
|
||||
if err = f.appendSparkline(ws, group, groups); err != nil {
|
||||
return
|
||||
|
@ -459,25 +459,25 @@ func (f *File) AddSparkline(sheet string, opt *SparklineOption) (err error) {
|
|||
|
||||
// parseFormatAddSparklineSet provides a function to validate sparkline
|
||||
// properties.
|
||||
func (f *File) parseFormatAddSparklineSet(sheet string, opt *SparklineOption) (*xlsxWorksheet, error) {
|
||||
func (f *File) parseFormatAddSparklineSet(sheet string, opts *SparklineOption) (*xlsxWorksheet, error) {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return ws, err
|
||||
}
|
||||
if opt == nil {
|
||||
if opts == nil {
|
||||
return ws, ErrParameterRequired
|
||||
}
|
||||
if len(opt.Location) < 1 {
|
||||
if len(opts.Location) < 1 {
|
||||
return ws, ErrSparklineLocation
|
||||
}
|
||||
if len(opt.Range) < 1 {
|
||||
if len(opts.Range) < 1 {
|
||||
return ws, ErrSparklineRange
|
||||
}
|
||||
// The ranges and locations must match.\
|
||||
if len(opt.Location) != len(opt.Range) {
|
||||
// The range and locations must match
|
||||
if len(opts.Location) != len(opts.Range) {
|
||||
return ws, ErrSparkline
|
||||
}
|
||||
if opt.Style < 0 || opt.Style > 35 {
|
||||
if opts.Style < 0 || opts.Style > 35 {
|
||||
return ws, ErrSparklineStyle
|
||||
}
|
||||
if ws.ExtLst == nil {
|
||||
|
@ -488,10 +488,10 @@ func (f *File) parseFormatAddSparklineSet(sheet string, opt *SparklineOption) (*
|
|||
|
||||
// addSparkline provides a function to create a sparkline in a sparkline group
|
||||
// by given properties.
|
||||
func (f *File) addSparkline(opt *SparklineOption, group *xlsxX14SparklineGroup) {
|
||||
for idx, location := range opt.Location {
|
||||
func (f *File) addSparkline(opts *SparklineOption, group *xlsxX14SparklineGroup) {
|
||||
for idx, location := range opts.Location {
|
||||
group.Sparklines.Sparkline = append(group.Sparklines.Sparkline, &xlsxX14Sparkline{
|
||||
F: opt.Range[idx],
|
||||
F: opts.Range[idx],
|
||||
Sqref: location,
|
||||
})
|
||||
}
|
||||
|
|
32
stream.go
32
stream.go
|
@ -117,7 +117,7 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
|
|||
}
|
||||
|
||||
// AddTable creates an Excel table for the StreamWriter using the given
|
||||
// coordinate area and format set. For example, create a table of A1:D5:
|
||||
// cell range and format set. For example, create a table of A1:D5:
|
||||
//
|
||||
// err := sw.AddTable("A1", "D5", "")
|
||||
//
|
||||
|
@ -156,7 +156,7 @@ func (sw *StreamWriter) AddTable(hCell, vCell, format string) error {
|
|||
coordinates[3]++
|
||||
}
|
||||
|
||||
// Correct table reference coordinate area, such correct C1:B3 to B1:C3.
|
||||
// Correct table reference range, such correct C1:B3 to B1:C3.
|
||||
ref, err := sw.File.coordinatesToAreaRef(coordinates)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -308,8 +308,8 @@ type RowOpts struct {
|
|||
//
|
||||
// As a special case, if Cell is used as a value, then the Cell.StyleID will be
|
||||
// applied to that cell.
|
||||
func (sw *StreamWriter) SetRow(axis string, values []interface{}, opts ...RowOpts) error {
|
||||
col, row, err := CellNameToCoordinates(axis)
|
||||
func (sw *StreamWriter) SetRow(cell string, values []interface{}, opts ...RowOpts) error {
|
||||
col, row, err := CellNameToCoordinates(cell)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -329,11 +329,11 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}, opts ...RowOpt
|
|||
if val == nil {
|
||||
continue
|
||||
}
|
||||
axis, err := CoordinatesToCellName(col+i, row)
|
||||
ref, err := CoordinatesToCellName(col+i, row)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c := xlsxC{R: axis}
|
||||
c := xlsxC{R: ref}
|
||||
if v, ok := val.(Cell); ok {
|
||||
c.S = v.StyleID
|
||||
val = v.Value
|
||||
|
@ -355,24 +355,24 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}, opts ...RowOpt
|
|||
|
||||
// marshalRowAttrs prepare attributes of the row by given options.
|
||||
func marshalRowAttrs(opts ...RowOpts) (attrs string, err error) {
|
||||
var opt *RowOpts
|
||||
var options *RowOpts
|
||||
for i := range opts {
|
||||
opt = &opts[i]
|
||||
options = &opts[i]
|
||||
}
|
||||
if opt == nil {
|
||||
if options == nil {
|
||||
return
|
||||
}
|
||||
if opt.Height > MaxRowHeight {
|
||||
if options.Height > MaxRowHeight {
|
||||
err = ErrMaxRowHeight
|
||||
return
|
||||
}
|
||||
if opt.StyleID > 0 {
|
||||
attrs += fmt.Sprintf(` s="%d" customFormat="true"`, opt.StyleID)
|
||||
if options.StyleID > 0 {
|
||||
attrs += fmt.Sprintf(` s="%d" customFormat="true"`, options.StyleID)
|
||||
}
|
||||
if opt.Height > 0 {
|
||||
attrs += fmt.Sprintf(` ht="%v" customHeight="true"`, opt.Height)
|
||||
if options.Height > 0 {
|
||||
attrs += fmt.Sprintf(` ht="%v" customHeight="true"`, options.Height)
|
||||
}
|
||||
if opt.Hidden {
|
||||
if options.Hidden {
|
||||
attrs += ` hidden="true"`
|
||||
}
|
||||
return
|
||||
|
@ -401,7 +401,7 @@ func (sw *StreamWriter) SetColWidth(min, max int, width float64) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MergeCell provides a function to merge cells by a given coordinate area for
|
||||
// MergeCell provides a function to merge cells by a given range reference for
|
||||
// the StreamWriter. Don't create a merged cell that overlaps with another
|
||||
// existing merged cell.
|
||||
func (sw *StreamWriter) MergeCell(hCell, vCell string) error {
|
||||
|
|
|
@ -175,7 +175,7 @@ func TestStreamTable(t *testing.T) {
|
|||
|
||||
// Test add table with illegal formatset.
|
||||
assert.EqualError(t, streamWriter.AddTable("B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
|
||||
// Test add table with illegal cell coordinates.
|
||||
// Test add table with illegal cell reference.
|
||||
assert.EqualError(t, streamWriter.AddTable("A", "B1", `{}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
assert.EqualError(t, streamWriter.AddTable("A1", "B", `{}`), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ func TestStreamMergeCells(t *testing.T) {
|
|||
streamWriter, err := file.NewStreamWriter("Sheet1")
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, streamWriter.MergeCell("A1", "D1"))
|
||||
// Test merge cells with illegal cell coordinates.
|
||||
// Test merge cells with illegal cell reference.
|
||||
assert.EqualError(t, streamWriter.MergeCell("A", "D1"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
assert.NoError(t, streamWriter.Flush())
|
||||
// Save spreadsheet by the given path.
|
||||
|
|
26
styles.go
26
styles.go
|
@ -1992,9 +1992,9 @@ func (f *File) getStyleID(ss *xlsxStyleSheet, style *Style) (styleID int) {
|
|||
}
|
||||
|
||||
// NewConditionalStyle provides a function to create style for conditional
|
||||
// format by given style format. The parameters are the same as function
|
||||
// NewStyle(). Note that the color field uses RGB color code and only support
|
||||
// to set font, fills, alignment and borders currently.
|
||||
// format by given style format. The parameters are the same with the NewStyle
|
||||
// function. Note that the color field uses RGB color code and only support to
|
||||
// set font, fills, alignment and borders currently.
|
||||
func (f *File) NewConditionalStyle(style string) (int, error) {
|
||||
s := f.stylesReader()
|
||||
fs, err := parseFormatStyleSet(style)
|
||||
|
@ -2480,23 +2480,23 @@ func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, a
|
|||
}
|
||||
|
||||
// GetCellStyle provides a function to get cell style index by given worksheet
|
||||
// name and cell coordinates.
|
||||
func (f *File) GetCellStyle(sheet, axis string) (int, error) {
|
||||
// name and cell reference.
|
||||
func (f *File) GetCellStyle(sheet, cell string) (int, error) {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cellData, col, row, err := f.prepareCell(ws, axis)
|
||||
c, col, row, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return f.prepareCellStyle(ws, col, row, cellData.S), err
|
||||
return f.prepareCellStyle(ws, col, row, c.S), err
|
||||
}
|
||||
|
||||
// SetCellStyle provides a function to add style attribute for cells by given
|
||||
// worksheet name, coordinate area and style ID. This function is concurrency
|
||||
// worksheet name, range reference and style ID. This function is concurrency
|
||||
// safe. Note that diagonalDown and diagonalUp type border should be use same
|
||||
// color in the same coordinate area. SetCellStyle will overwrite the existing
|
||||
// color in the same range. SetCellStyle will overwrite the existing
|
||||
// styles for the cell, it won't append or merge style with existing styles.
|
||||
//
|
||||
// For example create a borders of cell H9 on Sheet1:
|
||||
|
@ -2607,7 +2607,7 @@ func (f *File) SetCellStyle(sheet, hCell, vCell string, styleID int) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Normalize the coordinate area, such correct C1:B3 to B1:C3.
|
||||
// Normalize the range, such correct C1:B3 to B1:C3.
|
||||
if vCol < hCol {
|
||||
vCol, hCol = hCol, vCol
|
||||
}
|
||||
|
@ -3050,14 +3050,14 @@ func (f *File) GetConditionalFormats(sheet string) (map[string]string, error) {
|
|||
}
|
||||
|
||||
// UnsetConditionalFormat provides a function to unset the conditional format
|
||||
// by given worksheet name and range.
|
||||
func (f *File) UnsetConditionalFormat(sheet, area string) error {
|
||||
// by given worksheet name and range reference.
|
||||
func (f *File) UnsetConditionalFormat(sheet, reference string) error {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for i, cf := range ws.ConditionalFormatting {
|
||||
if cf.SQRef == area {
|
||||
if cf.SQRef == reference {
|
||||
ws.ConditionalFormatting = append(ws.ConditionalFormatting[:i], ws.ConditionalFormatting[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
|
|
14
table.go
14
table.go
|
@ -29,7 +29,7 @@ func parseFormatTableSet(formatSet string) (*formatTable, error) {
|
|||
}
|
||||
|
||||
// AddTable provides the method to add table in a worksheet by given worksheet
|
||||
// name, coordinate area and format set. For example, create a table of A1:D5
|
||||
// name, range reference and format set. For example, create a table of A1:D5
|
||||
// on Sheet1:
|
||||
//
|
||||
// err := f.AddTable("Sheet1", "A1", "D5", "")
|
||||
|
@ -159,14 +159,14 @@ func (f *File) setTableHeader(sheet string, x1, y1, x2 int) ([]*xlsxTableColumn,
|
|||
}
|
||||
|
||||
// addTable provides a function to add table by given worksheet name,
|
||||
// coordinate area and format set.
|
||||
// range reference and format set.
|
||||
func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, formatSet *formatTable) error {
|
||||
// Correct the minimum number of rows, the table at least two lines.
|
||||
if y1 == y2 {
|
||||
y2++
|
||||
}
|
||||
|
||||
// Correct table reference coordinate area, such correct C1:B3 to B1:C3.
|
||||
// Correct table range reference, such correct C1:B3 to B1:C3.
|
||||
ref, err := f.coordinatesToAreaRef([]int{x1, y1, x2, y2})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -211,17 +211,17 @@ func parseAutoFilterSet(formatSet string) (*formatAutoFilter, error) {
|
|||
}
|
||||
|
||||
// AutoFilter provides the method to add auto filter in a worksheet by given
|
||||
// worksheet name, coordinate area and settings. An autofilter in Excel is a
|
||||
// worksheet name, range reference and settings. An auto filter in Excel is a
|
||||
// way of filtering a 2D range of data based on some simple criteria. For
|
||||
// example applying an autofilter to a cell range A1:D4 in the Sheet1:
|
||||
// example applying an auto filter to a cell range A1:D4 in the Sheet1:
|
||||
//
|
||||
// err := f.AutoFilter("Sheet1", "A1", "D4", "")
|
||||
//
|
||||
// Filter data in an autofilter:
|
||||
// Filter data in an auto filter:
|
||||
//
|
||||
// err := f.AutoFilter("Sheet1", "A1", "D4", `{"column":"B","expression":"x != blanks"}`)
|
||||
//
|
||||
// column defines the filter columns in a autofilter range based on simple
|
||||
// column defines the filter columns in a auto filter range based on simple
|
||||
// criteria
|
||||
//
|
||||
// It isn't sufficient to just specify the filter condition. You must also
|
||||
|
|
|
@ -33,22 +33,22 @@ func TestAddTable(t *testing.T) {
|
|||
assert.EqualError(t, f.AddTable("SheetN", "B26", "A21", `{}`), "sheet SheetN does not exist")
|
||||
// Test add table with illegal formatset.
|
||||
assert.EqualError(t, f.AddTable("Sheet1", "B26", "A21", `{x}`), "invalid character 'x' looking for beginning of object key string")
|
||||
// Test add table with illegal cell coordinates.
|
||||
// Test add table with illegal cell reference.
|
||||
assert.EqualError(t, f.AddTable("Sheet1", "A", "B1", `{}`), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
assert.EqualError(t, f.AddTable("Sheet1", "A1", "B", `{}`), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
|
||||
|
||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddTable.xlsx")))
|
||||
|
||||
// Test addTable with illegal cell coordinates.
|
||||
// Test addTable with illegal cell reference.
|
||||
f = NewFile()
|
||||
assert.EqualError(t, f.addTable("sheet1", "", 0, 0, 0, 0, 0, nil), "invalid cell coordinates [0, 0]")
|
||||
assert.EqualError(t, f.addTable("sheet1", "", 1, 1, 0, 0, 0, nil), "invalid cell coordinates [0, 0]")
|
||||
assert.EqualError(t, f.addTable("sheet1", "", 0, 0, 0, 0, 0, nil), "invalid cell reference [0, 0]")
|
||||
assert.EqualError(t, f.addTable("sheet1", "", 1, 1, 0, 0, 0, nil), "invalid cell reference [0, 0]")
|
||||
}
|
||||
|
||||
func TestSetTableHeader(t *testing.T) {
|
||||
f := NewFile()
|
||||
_, err := f.setTableHeader("Sheet1", 1, 0, 1)
|
||||
assert.EqualError(t, err, "invalid cell coordinates [1, 0]")
|
||||
assert.EqualError(t, err, "invalid cell reference [1, 0]")
|
||||
}
|
||||
|
||||
func TestAutoFilter(t *testing.T) {
|
||||
|
@ -78,7 +78,7 @@ func TestAutoFilter(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
// Test AutoFilter with illegal cell coordinates.
|
||||
// Test AutoFilter with illegal cell reference.
|
||||
assert.EqualError(t, f.AutoFilter("Sheet1", "A", "B1", ""), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||
assert.EqualError(t, f.AutoFilter("Sheet1", "A1", "B", ""), newCellNameToCoordinatesError("B", newInvalidCellNameError("B")).Error())
|
||||
}
|
||||
|
|
14
xmlApp.go
14
xmlApp.go
|
@ -15,13 +15,13 @@ import "encoding/xml"
|
|||
|
||||
// AppProperties directly maps the document application properties.
|
||||
type AppProperties struct {
|
||||
Application string
|
||||
ScaleCrop bool
|
||||
DocSecurity int
|
||||
Company string
|
||||
LinksUpToDate bool
|
||||
HyperlinksChanged bool
|
||||
AppVersion string
|
||||
Application string `json:"application"`
|
||||
ScaleCrop bool `json:"scale_crop"`
|
||||
DocSecurity int `json:"doc_security"`
|
||||
Company string `json:"company"`
|
||||
LinksUpToDate bool `json:"links_up_to_date"`
|
||||
HyperlinksChanged bool `json:"hyperlinks_changed"`
|
||||
AppVersion string `json:"app_version"`
|
||||
}
|
||||
|
||||
// xlsxProperties specifies to an OOXML document properties such as the
|
||||
|
|
Loading…
Reference in New Issue