refactor: handler error instead of panic,
Exported functions: SetCellStyle InsertCol RemoveCol RemoveRow InsertRow DuplicateRow DuplicateRowTo SetRowHeight GetRowHeight GetCellValue GetCellFormula GetCellHyperLink SetCellHyperLink SetCellInt SetCellBool SetCellFloat SetCellStr SetCellDefault GetCellStyle SetCellValue MergeCell SetSheetRow SetRowVisible GetRowVisible SetRowOutlineLevel GetRowOutlineLevel GetRows Columns SearchSheet AddTable GetPicture AutoFilter GetColVisible SetColVisible GetColOutlineLevel SetColOutlineLevel SetColWidth GetColWidth inner functions: adjustHelper adjustMergeCells adjustAutoFilter prepareCell setDefaultTimeStyle timeToExcelTime addDrawingChart addDrawingVML addDrawingPicture getTotalRowsCols checkRow addDrawingShape addTable
This commit is contained in:
parent
2874d75555
commit
40ff5dc1a7
|
@ -1,5 +1,4 @@
|
||||||
~$*.xlsx
|
~$*.xlsx
|
||||||
test/Test*.xlsx
|
test/Test*.xlsx
|
||||||
*.out
|
*.out
|
||||||
test/image3.png
|
|
||||||
*.test
|
*.test
|
|
@ -15,11 +15,6 @@
|
||||||
|
|
||||||
Excelize is a library written in pure Go and providing a set of functions that allow you to write to and read from XLSX files. Support reads and writes XLSX file generated by Microsoft Excel™ 2007 and later. Support save file without losing original charts of XLSX. This library needs Go version 1.8 or later. The full API docs can be seen using go's built-in documentation tool, or online at [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) and [docs reference](https://xuri.me/excelize/).
|
Excelize is a library written in pure Go and providing a set of functions that allow you to write to and read from XLSX files. Support reads and writes XLSX file generated by Microsoft Excel™ 2007 and later. Support save file without losing original charts of XLSX. This library needs Go version 1.8 or later. The full API docs can be seen using go's built-in documentation tool, or online at [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) and [docs reference](https://xuri.me/excelize/).
|
||||||
|
|
||||||
**WARNING!**
|
|
||||||
|
|
||||||
From version 1.5.0 all row manipulation methods uses Excel row numbering starting with `1` instead of zero-based numbering
|
|
||||||
which take place in some methods in eraler versions.
|
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
@ -123,7 +118,6 @@ func main() {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Add picture to XLSX file
|
### Add picture to XLSX file
|
||||||
|
|
|
@ -15,10 +15,6 @@
|
||||||
|
|
||||||
Excelize 是 Go 语言编写的用于操作 Office Excel 文档类库,基于 ECMA-376 Office OpenXML 标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的 XLSX 文档。相比较其他的开源类库,Excelize 支持写入原本带有图片(表)、透视表和切片器等复杂样式的文档,还支持向 Excel 文档中插入图片与图表,并且在保存后不会丢失文档原有样式,可以应用于各类报表系统中。使用本类库要求使用的 Go 语言为 1.8 或更高版本,完整的 API 使用文档请访问 [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) 或查看 [参考文档](https://xuri.me/excelize/)。
|
Excelize 是 Go 语言编写的用于操作 Office Excel 文档类库,基于 ECMA-376 Office OpenXML 标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的 XLSX 文档。相比较其他的开源类库,Excelize 支持写入原本带有图片(表)、透视表和切片器等复杂样式的文档,还支持向 Excel 文档中插入图片与图表,并且在保存后不会丢失文档原有样式,可以应用于各类报表系统中。使用本类库要求使用的 Go 语言为 1.8 或更高版本,完整的 API 使用文档请访问 [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) 或查看 [参考文档](https://xuri.me/excelize/)。
|
||||||
|
|
||||||
**重要提示**
|
|
||||||
|
|
||||||
从版本 1.5.0 开始,所有行操作方法都使用从 `1` 开始的 Excel 行编号,早期版本中某些方法中的基于 `0` 的行编号将不再使用。
|
|
||||||
|
|
||||||
## 快速上手
|
## 快速上手
|
||||||
|
|
||||||
### 安装
|
### 安装
|
||||||
|
|
35
adjust.go
35
adjust.go
|
@ -30,7 +30,7 @@ const (
|
||||||
// TODO: adjustCalcChain, adjustPageBreaks, adjustComments,
|
// TODO: adjustCalcChain, adjustPageBreaks, adjustComments,
|
||||||
// adjustDataValidations, adjustProtectedCells
|
// adjustDataValidations, adjustProtectedCells
|
||||||
//
|
//
|
||||||
func (f *File) adjustHelper(sheet string, dir adjustDirection, num, offset int) {
|
func (f *File) adjustHelper(sheet string, dir adjustDirection, num, offset int) error {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
|
|
||||||
if dir == rows {
|
if dir == rows {
|
||||||
|
@ -39,11 +39,16 @@ func (f *File) adjustHelper(sheet string, dir adjustDirection, num, offset int)
|
||||||
f.adjustColDimensions(xlsx, num, offset)
|
f.adjustColDimensions(xlsx, num, offset)
|
||||||
}
|
}
|
||||||
f.adjustHyperlinks(xlsx, sheet, dir, num, offset)
|
f.adjustHyperlinks(xlsx, sheet, dir, num, offset)
|
||||||
f.adjustMergeCells(xlsx, dir, num, offset)
|
if err := f.adjustMergeCells(xlsx, dir, num, offset); err != nil {
|
||||||
f.adjustAutoFilter(xlsx, dir, num, offset)
|
return err
|
||||||
|
}
|
||||||
|
if err := f.adjustAutoFilter(xlsx, dir, num, offset); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
checkSheet(xlsx)
|
checkSheet(xlsx)
|
||||||
checkRow(xlsx)
|
checkRow(xlsx)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjustColDimensions provides a function to update column dimensions when
|
// adjustColDimensions provides a function to update column dimensions when
|
||||||
|
@ -127,9 +132,9 @@ func (f *File) adjustHyperlinks(xlsx *xlsxWorksheet, sheet string, dir adjustDir
|
||||||
|
|
||||||
// adjustAutoFilter provides a function to update the auto filter when
|
// adjustAutoFilter provides a function to update the auto filter when
|
||||||
// inserting or deleting rows or columns.
|
// inserting or deleting rows or columns.
|
||||||
func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, offset int) {
|
func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, offset int) error {
|
||||||
if xlsx.AutoFilter == nil {
|
if xlsx.AutoFilter == nil {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rng := strings.Split(xlsx.AutoFilter.Ref, ":")
|
rng := strings.Split(xlsx.AutoFilter.Ref, ":")
|
||||||
|
@ -138,12 +143,12 @@ func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, o
|
||||||
|
|
||||||
firstCol, firstRow, err := CellNameToCoordinates(firstCell)
|
firstCol, firstRow, err := CellNameToCoordinates(firstCell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lastCol, lastRow, err := CellNameToCoordinates(lastCell)
|
lastCol, lastRow, err := CellNameToCoordinates(lastCell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dir == rows && firstRow == num && offset < 0) || (dir == columns && firstCol == num && lastCol == num) {
|
if (dir == rows && firstRow == num && offset < 0) || (dir == columns && firstCol == num && lastCol == num) {
|
||||||
|
@ -154,7 +159,7 @@ func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, o
|
||||||
rowData.Hidden = false
|
rowData.Hidden = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir == rows {
|
if dir == rows {
|
||||||
|
@ -171,13 +176,14 @@ func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, dir adjustDirection, num, o
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.AutoFilter.Ref = firstCell + ":" + lastCell
|
xlsx.AutoFilter.Ref = firstCell + ":" + lastCell
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjustMergeCells provides a function to update merged cells when inserting
|
// adjustMergeCells provides a function to update merged cells when inserting
|
||||||
// or deleting rows or columns.
|
// or deleting rows or columns.
|
||||||
func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, dir adjustDirection, num, offset int) {
|
func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, dir adjustDirection, num, offset int) error {
|
||||||
if xlsx.MergeCells == nil {
|
if xlsx.MergeCells == nil {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, areaData := range xlsx.MergeCells.Cells {
|
for i, areaData := range xlsx.MergeCells.Cells {
|
||||||
|
@ -187,12 +193,12 @@ func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, dir adjustDirection, num, o
|
||||||
|
|
||||||
firstCol, firstRow, err := CellNameToCoordinates(firstCell)
|
firstCol, firstRow, err := CellNameToCoordinates(firstCell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
lastCol, lastRow, err := CellNameToCoordinates(lastCell)
|
lastCol, lastRow, err := CellNameToCoordinates(lastCell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
adjust := func(v int) int {
|
adjust := func(v int) int {
|
||||||
|
@ -224,13 +230,14 @@ func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, dir adjustDirection, num, o
|
||||||
}
|
}
|
||||||
|
|
||||||
if firstCell, err = CoordinatesToCellName(firstCol, firstRow); err != nil {
|
if firstCell, err = CoordinatesToCellName(firstCol, firstRow); err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if lastCell, err = CoordinatesToCellName(lastCol, lastRow); err != nil {
|
if lastCell, err = CoordinatesToCellName(lastCol, lastRow); err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
areaData.Ref = firstCell + ":" + lastCell
|
areaData.Ref = firstCell + ":" + lastCell
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
210
cell.go
210
cell.go
|
@ -34,13 +34,13 @@ const (
|
||||||
// worksheet name and axis in XLSX file. If it is possible to apply a format
|
// worksheet name and axis in XLSX 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,
|
// to the cell value, it will do so, if not then an error will be returned,
|
||||||
// along with the raw value of the cell.
|
// along with the raw value of the cell.
|
||||||
func (f *File) GetCellValue(sheet, axis string) string {
|
func (f *File) GetCellValue(sheet, axis string) (string, error) {
|
||||||
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool) {
|
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
|
||||||
val, err := c.getValueFrom(f, f.sharedStringsReader())
|
val, err := c.getValueFrom(f, f.sharedStringsReader())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // Fail fast to avoid future side effects!
|
return val, false, err
|
||||||
}
|
}
|
||||||
return val, true
|
return val, true, err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ func (f *File) GetCellValue(sheet, axis string) string {
|
||||||
//
|
//
|
||||||
// Note that default date format is m/d/yy h:mm of time.Time type value. You can
|
// Note that default date format is m/d/yy h:mm of time.Time type value. You can
|
||||||
// set numbers format by SetCellStyle() method.
|
// set numbers format by SetCellStyle() method.
|
||||||
func (f *File) SetCellValue(sheet, axis string, value interface{}) {
|
func (f *File) SetCellValue(sheet, axis string, value interface{}) error {
|
||||||
switch v := value.(type) {
|
switch v := value.(type) {
|
||||||
case int:
|
case int:
|
||||||
f.SetCellInt(sheet, axis, v)
|
f.SetCellInt(sheet, axis, v)
|
||||||
|
@ -102,9 +102,12 @@ func (f *File) SetCellValue(sheet, axis string, value interface{}) {
|
||||||
f.SetCellDefault(sheet, axis, strconv.FormatFloat(v.Seconds()/86400.0, 'f', -1, 32))
|
f.SetCellDefault(sheet, axis, strconv.FormatFloat(v.Seconds()/86400.0, 'f', -1, 32))
|
||||||
f.setDefaultTimeStyle(sheet, axis, 21)
|
f.setDefaultTimeStyle(sheet, axis, 21)
|
||||||
case time.Time:
|
case time.Time:
|
||||||
vv := timeToExcelTime(v)
|
excelTime, err := timeToExcelTime(v)
|
||||||
if vv > 0 {
|
if err != nil {
|
||||||
f.SetCellDefault(sheet, axis, strconv.FormatFloat(timeToExcelTime(v), 'f', -1, 64))
|
return err
|
||||||
|
}
|
||||||
|
if excelTime > 0 {
|
||||||
|
f.SetCellDefault(sheet, axis, strconv.FormatFloat(excelTime, 'f', -1, 64))
|
||||||
f.setDefaultTimeStyle(sheet, axis, 22)
|
f.setDefaultTimeStyle(sheet, axis, 22)
|
||||||
} else {
|
} else {
|
||||||
f.SetCellStr(sheet, axis, v.Format(time.RFC3339Nano))
|
f.SetCellStr(sheet, axis, v.Format(time.RFC3339Nano))
|
||||||
|
@ -116,23 +119,31 @@ func (f *File) SetCellValue(sheet, axis string, value interface{}) {
|
||||||
default:
|
default:
|
||||||
f.SetCellStr(sheet, axis, fmt.Sprintf("%v", value))
|
f.SetCellStr(sheet, axis, fmt.Sprintf("%v", value))
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellInt provides a function to set int type value of a cell by given
|
// SetCellInt provides a function to set int type value of a cell by given
|
||||||
// worksheet name, cell coordinates and cell value.
|
// worksheet name, cell coordinates and cell value.
|
||||||
func (f *File) SetCellInt(sheet, axis string, value int) {
|
func (f *File) SetCellInt(sheet, axis string, value int) error {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
cellData, col, _ := f.prepareCell(xlsx, sheet, axis)
|
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
||||||
cellData.T = ""
|
cellData.T = ""
|
||||||
cellData.V = strconv.Itoa(value)
|
cellData.V = strconv.Itoa(value)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellBool provides a function to set bool type value of a cell by given
|
// SetCellBool provides a function to set bool type value of a cell by given
|
||||||
// worksheet name, cell name and cell value.
|
// worksheet name, cell name and cell value.
|
||||||
func (f *File) SetCellBool(sheet, axis string, value bool) {
|
func (f *File) SetCellBool(sheet, axis string, value bool) error {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
cellData, col, _ := f.prepareCell(xlsx, sheet, axis)
|
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
||||||
cellData.T = "b"
|
cellData.T = "b"
|
||||||
if value {
|
if value {
|
||||||
|
@ -140,6 +151,7 @@ func (f *File) SetCellBool(sheet, axis string, value bool) {
|
||||||
} else {
|
} else {
|
||||||
cellData.V = "0"
|
cellData.V = "0"
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellFloat sets a floating point value into a cell. The prec parameter
|
// SetCellFloat sets a floating point value into a cell. The prec parameter
|
||||||
|
@ -151,20 +163,26 @@ func (f *File) SetCellBool(sheet, axis string, value bool) {
|
||||||
// var x float32 = 1.325
|
// var x float32 = 1.325
|
||||||
// f.SetCellFloat("Sheet1", "A1", float64(x), 2, 32)
|
// f.SetCellFloat("Sheet1", "A1", float64(x), 2, 32)
|
||||||
//
|
//
|
||||||
func (f *File) SetCellFloat(sheet, axis string, value float64, prec, bitSize int) {
|
func (f *File) SetCellFloat(sheet, axis string, value float64, prec, bitSize int) error {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
cellData, col, _ := f.prepareCell(xlsx, sheet, axis)
|
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
||||||
cellData.T = ""
|
cellData.T = ""
|
||||||
cellData.V = strconv.FormatFloat(value, 'f', prec, bitSize)
|
cellData.V = strconv.FormatFloat(value, 'f', prec, bitSize)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellStr provides a function to set string type value of a cell. Total
|
// SetCellStr provides a function to set string type value of a cell. Total
|
||||||
// number of characters that a cell can contain 32767 characters.
|
// number of characters that a cell can contain 32767 characters.
|
||||||
func (f *File) SetCellStr(sheet, axis, value string) {
|
func (f *File) SetCellStr(sheet, axis, value string) error {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
cellData, col, _ := f.prepareCell(xlsx, sheet, axis)
|
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Leading space(s) character detection.
|
// Leading space(s) character detection.
|
||||||
if len(value) > 0 && value[0] == 32 {
|
if len(value) > 0 && value[0] == 32 {
|
||||||
cellData.XMLSpace = xml.Attr{
|
cellData.XMLSpace = xml.Attr{
|
||||||
|
@ -176,42 +194,49 @@ func (f *File) SetCellStr(sheet, axis, value string) {
|
||||||
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
||||||
cellData.T = "str"
|
cellData.T = "str"
|
||||||
cellData.V = value
|
cellData.V = value
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellDefault provides a function to set string type value of a cell as
|
// SetCellDefault provides a function to set string type value of a cell as
|
||||||
// default format without escaping the cell.
|
// default format without escaping the cell.
|
||||||
func (f *File) SetCellDefault(sheet, axis, value string) {
|
func (f *File) SetCellDefault(sheet, axis, value string) error {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
cellData, col, _ := f.prepareCell(xlsx, sheet, axis)
|
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
cellData.S = f.prepareCellStyle(xlsx, col, cellData.S)
|
||||||
cellData.T = ""
|
cellData.T = ""
|
||||||
cellData.V = value
|
cellData.V = value
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCellFormula provides a function to get formula from cell by given
|
// GetCellFormula provides a function to get formula from cell by given
|
||||||
// worksheet name and axis in XLSX file.
|
// worksheet name and axis in XLSX file.
|
||||||
func (f *File) GetCellFormula(sheet, axis string) string {
|
func (f *File) GetCellFormula(sheet, axis string) (string, error) {
|
||||||
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool) {
|
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
|
||||||
if c.F == nil {
|
if c.F == nil {
|
||||||
return "", false
|
return "", false, nil
|
||||||
}
|
}
|
||||||
if c.F.T == STCellFormulaTypeShared {
|
if c.F.T == STCellFormulaTypeShared {
|
||||||
return getSharedForumula(x, c.F.Si), true
|
return getSharedForumula(x, c.F.Si), true, nil
|
||||||
}
|
}
|
||||||
return c.F.Content, true
|
return c.F.Content, true, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellFormula provides a function to set cell formula by given string and
|
// SetCellFormula provides a function to set cell formula by given string and
|
||||||
// worksheet name.
|
// worksheet name.
|
||||||
func (f *File) SetCellFormula(sheet, axis, formula string) {
|
func (f *File) SetCellFormula(sheet, axis, formula string) error {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
cellData, _, _ := f.prepareCell(xlsx, sheet, axis)
|
cellData, _, _, err := f.prepareCell(xlsx, sheet, axis)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if formula == "" {
|
if formula == "" {
|
||||||
cellData.F = nil
|
cellData.F = nil
|
||||||
f.deleteCalcChain(axis)
|
f.deleteCalcChain(axis)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cellData.F != nil {
|
if cellData.F != nil {
|
||||||
|
@ -219,6 +244,7 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
|
||||||
} else {
|
} else {
|
||||||
cellData.F = &xlsxF{Content: formula}
|
cellData.F = &xlsxF{Content: formula}
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCellHyperLink provides a function to get cell hyperlink by given
|
// GetCellHyperLink provides a function to get cell hyperlink by given
|
||||||
|
@ -227,28 +253,30 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
|
||||||
// the value of link will be false and the value of the target will be a blank
|
// the value of link will be false and the value of the target will be a blank
|
||||||
// string. For example get hyperlink of Sheet1!H6:
|
// string. For example get hyperlink of Sheet1!H6:
|
||||||
//
|
//
|
||||||
// link, target := xlsx.GetCellHyperLink("Sheet1", "H6")
|
// link, target, err := xlsx.GetCellHyperLink("Sheet1", "H6")
|
||||||
//
|
//
|
||||||
func (f *File) GetCellHyperLink(sheet, axis string) (bool, string) {
|
func (f *File) GetCellHyperLink(sheet, axis string) (bool, string, error) {
|
||||||
// Check for correct cell name
|
// Check for correct cell name
|
||||||
if _, _, err := SplitCellName(axis); err != nil {
|
if _, _, err := SplitCellName(axis); err != nil {
|
||||||
panic(err) // Fail fast to avoid possible future side effects
|
return false, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
axis = f.mergeCellsParser(xlsx, axis)
|
axis, err := f.mergeCellsParser(xlsx, axis)
|
||||||
|
if err != nil {
|
||||||
|
return false, "", err
|
||||||
|
}
|
||||||
if xlsx.Hyperlinks != nil {
|
if xlsx.Hyperlinks != nil {
|
||||||
for _, link := range xlsx.Hyperlinks.Hyperlink {
|
for _, link := range xlsx.Hyperlinks.Hyperlink {
|
||||||
if link.Ref == axis {
|
if link.Ref == axis {
|
||||||
if link.RID != "" {
|
if link.RID != "" {
|
||||||
return true, f.getSheetRelationshipsTargetByID(sheet, link.RID)
|
return true, f.getSheetRelationshipsTargetByID(sheet, link.RID), err
|
||||||
}
|
}
|
||||||
return true, link.Location
|
return true, link.Location, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, ""
|
return false, "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellHyperLink provides a function to set cell hyperlink by given
|
// SetCellHyperLink provides a function to set cell hyperlink by given
|
||||||
|
@ -256,23 +284,26 @@ func (f *File) GetCellHyperLink(sheet, axis string) (bool, string) {
|
||||||
// hyperlink "External" for web site or "Location" for moving to one of cell
|
// hyperlink "External" for web site or "Location" for moving to one of cell
|
||||||
// in this workbook. The below is example for external link.
|
// in this workbook. The below is example for external link.
|
||||||
//
|
//
|
||||||
// xlsx.SetCellHyperLink("Sheet1", "A3", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
|
// err := xlsx.SetCellHyperLink("Sheet1", "A3", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
|
||||||
// // Set underline and font color style for the cell.
|
// // Set underline and font color style for the cell.
|
||||||
// style, _ := xlsx.NewStyle(`{"font":{"color":"#1265BE","underline":"single"}}`)
|
// style, err := xlsx.NewStyle(`{"font":{"color":"#1265BE","underline":"single"}}`)
|
||||||
// xlsx.SetCellStyle("Sheet1", "A3", "A3", style)
|
// err = xlsx.SetCellStyle("Sheet1", "A3", "A3", style)
|
||||||
//
|
//
|
||||||
// A this is another example for "Location":
|
// A this is another example for "Location":
|
||||||
//
|
//
|
||||||
// xlsx.SetCellHyperLink("Sheet1", "A3", "Sheet1!A40", "Location")
|
// err := xlsx.SetCellHyperLink("Sheet1", "A3", "Sheet1!A40", "Location")
|
||||||
//
|
//
|
||||||
func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) {
|
func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) error {
|
||||||
// Check for correct cell name
|
// Check for correct cell name
|
||||||
if _, _, err := SplitCellName(axis); err != nil {
|
if _, _, err := SplitCellName(axis); err != nil {
|
||||||
panic(err) // Fail fast to avoid possible future side effects
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
axis = f.mergeCellsParser(xlsx, axis)
|
axis, err := f.mergeCellsParser(xlsx, axis)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var linkData xlsxHyperlink
|
var linkData xlsxHyperlink
|
||||||
|
|
||||||
|
@ -289,35 +320,36 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) {
|
||||||
Location: link,
|
Location: link,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("invalid link type %q", linkType))
|
return fmt.Errorf("invalid link type %q", linkType)
|
||||||
}
|
}
|
||||||
|
|
||||||
if xlsx.Hyperlinks == nil {
|
if xlsx.Hyperlinks == nil {
|
||||||
xlsx.Hyperlinks = new(xlsxHyperlinks)
|
xlsx.Hyperlinks = new(xlsxHyperlinks)
|
||||||
}
|
}
|
||||||
xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink, linkData)
|
xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink, linkData)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MergeCell provides a function to merge cells by given coordinate area and
|
// MergeCell provides a function to merge cells by given coordinate area and
|
||||||
// sheet name. For example create a merged cell of D3:E9 on Sheet1:
|
// sheet name. For example create a merged cell of D3:E9 on Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.MergeCell("Sheet1", "D3", "E9")
|
// err := xlsx.MergeCell("Sheet1", "D3", "E9")
|
||||||
//
|
//
|
||||||
// If you create a merged cell that overlaps with another existing merged cell,
|
// If you create a merged cell that overlaps with another existing merged cell,
|
||||||
// those merged cells that already exist will be removed.
|
// those merged cells that already exist will be removed.
|
||||||
func (f *File) MergeCell(sheet, hcell, vcell string) {
|
func (f *File) MergeCell(sheet, hcell, vcell string) error {
|
||||||
hcol, hrow, err := CellNameToCoordinates(hcell)
|
hcol, hrow, err := CellNameToCoordinates(hcell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
vcol, vrow, err := CellNameToCoordinates(vcell)
|
vcol, vrow, err := CellNameToCoordinates(vcell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if hcol == vcol && hrow == vrow {
|
if hcol == vcol && hrow == vrow {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if vcol < hcol {
|
if vcol < hcol {
|
||||||
|
@ -340,11 +372,13 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
|
||||||
for _, cellData := range xlsx.MergeCells.Cells {
|
for _, cellData := range xlsx.MergeCells.Cells {
|
||||||
cc := strings.Split(cellData.Ref, ":")
|
cc := strings.Split(cellData.Ref, ":")
|
||||||
if len(cc) != 2 {
|
if len(cc) != 2 {
|
||||||
panic(fmt.Errorf("invalid area %q", cellData.Ref))
|
return fmt.Errorf("invalid area %q", cellData.Ref)
|
||||||
}
|
}
|
||||||
|
c1, _ := checkCellInArea(hcell, cellData.Ref)
|
||||||
if !checkCellInArea(hcell, cellData.Ref) && !checkCellInArea(vcell, cellData.Ref) &&
|
c2, _ := checkCellInArea(vcell, cellData.Ref)
|
||||||
!checkCellInArea(cc[0], ref) && !checkCellInArea(cc[1], ref) {
|
c3, _ := checkCellInArea(cc[0], ref)
|
||||||
|
c4, _ := checkCellInArea(cc[1], ref)
|
||||||
|
if !c1 && !c2 && !c3 && !c4 {
|
||||||
cells = append(cells, cellData)
|
cells = append(cells, cellData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,24 +387,25 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
|
||||||
} else {
|
} else {
|
||||||
xlsx.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: hcell + ":" + vcell}}}
|
xlsx.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: hcell + ":" + vcell}}}
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSheetRow writes an array to row by given worksheet name, starting
|
// SetSheetRow writes an array to row by given worksheet name, starting
|
||||||
// coordinate and a pointer to array type 'slice'. For example, writes an
|
// coordinate and a pointer to array type 'slice'. For example, writes an
|
||||||
// array to row 6 start with the cell B6 on Sheet1:
|
// array to row 6 start with the cell B6 on Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.SetSheetRow("Sheet1", "B6", &[]interface{}{"1", nil, 2})
|
// err := xlsx.SetSheetRow("Sheet1", "B6", &[]interface{}{"1", nil, 2})
|
||||||
//
|
//
|
||||||
func (f *File) SetSheetRow(sheet, axis string, slice interface{}) {
|
func (f *File) SetSheetRow(sheet, axis string, slice interface{}) error {
|
||||||
col, row, err := CellNameToCoordinates(axis)
|
col, row, err := CellNameToCoordinates(axis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // Fail fast to avoid future side effects!
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure 'slice' is a Ptr to Slice
|
// Make sure 'slice' is a Ptr to Slice
|
||||||
v := reflect.ValueOf(slice)
|
v := reflect.ValueOf(slice)
|
||||||
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Slice {
|
if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Slice {
|
||||||
panic(errors.New("pointer to slice expected")) // Fail fast to avoid future side effects!
|
return errors.New("pointer to slice expected")
|
||||||
}
|
}
|
||||||
v = v.Elem()
|
v = v.Elem()
|
||||||
|
|
||||||
|
@ -379,35 +414,42 @@ func (f *File) SetSheetRow(sheet, axis string, slice interface{}) {
|
||||||
// Error should never happens here. But keep ckecking to early detect regresions
|
// Error should never happens here. But keep ckecking to early detect regresions
|
||||||
// if it will be introduced in furure
|
// if it will be introduced in furure
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // Fail fast to avoid future side effects!
|
return err
|
||||||
}
|
}
|
||||||
f.SetCellValue(sheet, cell, v.Index(i).Interface())
|
f.SetCellValue(sheet, cell, v.Index(i).Interface())
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCellInfo does common preparation for all SetCell* methods.
|
// getCellInfo does common preparation for all SetCell* methods.
|
||||||
func (f *File) prepareCell(xlsx *xlsxWorksheet, sheet, cell string) (*xlsxC, int, int) {
|
func (f *File) prepareCell(xlsx *xlsxWorksheet, sheet, cell string) (*xlsxC, int, int, error) {
|
||||||
cell = f.mergeCellsParser(xlsx, cell)
|
var err error
|
||||||
|
cell, err = f.mergeCellsParser(xlsx, cell)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, 0, err
|
||||||
|
}
|
||||||
col, row, err := CellNameToCoordinates(cell)
|
col, row, err := CellNameToCoordinates(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // Fail fast and prevent future side effects
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareSheetXML(xlsx, col, row)
|
prepareSheetXML(xlsx, col, row)
|
||||||
|
|
||||||
return &xlsx.SheetData.Row[row-1].C[col-1], col, row
|
return &xlsx.SheetData.Row[row-1].C[col-1], col, row, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCellStringFunc does common value extraction workflow for all GetCell* methods.
|
// getCellStringFunc does common value extraction workflow for all GetCell*
|
||||||
// Passed function implements specific part of required logic.
|
// methods. Passed function implements specific part of required logic.
|
||||||
func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c *xlsxC) (string, bool)) string {
|
func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c *xlsxC) (string, bool, error)) (string, error) {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
axis = f.mergeCellsParser(xlsx, axis)
|
var err error
|
||||||
|
axis, err = f.mergeCellsParser(xlsx, axis)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
_, row, err := CellNameToCoordinates(axis)
|
_, row, err := CellNameToCoordinates(axis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // Fail fast to avoid future side effects!
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
lastRowNum := 0
|
lastRowNum := 0
|
||||||
|
@ -417,7 +459,7 @@ func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c
|
||||||
|
|
||||||
// keep in mind: row starts from 1
|
// keep in mind: row starts from 1
|
||||||
if row > lastRowNum {
|
if row > lastRowNum {
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for rowIdx := range xlsx.SheetData.Row {
|
for rowIdx := range xlsx.SheetData.Row {
|
||||||
|
@ -430,12 +472,16 @@ func (f *File) getCellStringFunc(sheet, axis string, fn func(x *xlsxWorksheet, c
|
||||||
if axis != colData.R {
|
if axis != colData.R {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if val, ok := fn(xlsx, colData); ok {
|
val, ok, err := fn(xlsx, colData)
|
||||||
return val
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
return val, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ""
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// formattedValue provides a function to returns a value after formatted. If
|
// formattedValue provides a function to returns a value after formatted. If
|
||||||
|
@ -468,35 +514,39 @@ func (f *File) prepareCellStyle(xlsx *xlsxWorksheet, col, style int) int {
|
||||||
|
|
||||||
// mergeCellsParser provides a function to check merged cells in worksheet by
|
// mergeCellsParser provides a function to check merged cells in worksheet by
|
||||||
// given axis.
|
// given axis.
|
||||||
func (f *File) mergeCellsParser(xlsx *xlsxWorksheet, axis string) string {
|
func (f *File) mergeCellsParser(xlsx *xlsxWorksheet, axis string) (string, error) {
|
||||||
axis = strings.ToUpper(axis)
|
axis = strings.ToUpper(axis)
|
||||||
if xlsx.MergeCells != nil {
|
if xlsx.MergeCells != nil {
|
||||||
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
||||||
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
ok, err := checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref)
|
||||||
|
if err != nil {
|
||||||
|
return axis, err
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0]
|
axis = strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return axis
|
return axis, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkCellInArea provides a function to determine if a given coordinate is
|
// checkCellInArea provides a function to determine if a given coordinate is
|
||||||
// within an area.
|
// within an area.
|
||||||
func checkCellInArea(cell, area string) bool {
|
func checkCellInArea(cell, area string) (bool, error) {
|
||||||
col, row, err := CellNameToCoordinates(cell)
|
col, row, err := CellNameToCoordinates(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rng := strings.Split(area, ":")
|
rng := strings.Split(area, ":")
|
||||||
if len(rng) != 2 {
|
if len(rng) != 2 {
|
||||||
return false
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
firstCol, firtsRow, _ := CellNameToCoordinates(rng[0])
|
firstCol, firtsRow, _ := CellNameToCoordinates(rng[0])
|
||||||
lastCol, lastRow, _ := CellNameToCoordinates(rng[1])
|
lastCol, lastRow, _ := CellNameToCoordinates(rng[1])
|
||||||
|
|
||||||
return col >= firstCol && col <= lastCol && row >= firtsRow && row <= lastRow
|
return col >= firstCol && col <= lastCol && row >= firtsRow && row <= lastRow, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSharedForumula find a cell contains the same formula as another cell,
|
// getSharedForumula find a cell contains the same formula as another cell,
|
||||||
|
|
35
cell_test.go
35
cell_test.go
|
@ -17,8 +17,9 @@ func TestCheckCellInArea(t *testing.T) {
|
||||||
for _, expectedTrueCellInArea := range expectedTrueCellInAreaList {
|
for _, expectedTrueCellInArea := range expectedTrueCellInAreaList {
|
||||||
cell := expectedTrueCellInArea[0]
|
cell := expectedTrueCellInArea[0]
|
||||||
area := expectedTrueCellInArea[1]
|
area := expectedTrueCellInArea[1]
|
||||||
|
ok, err := checkCellInArea(cell, area)
|
||||||
assert.Truef(t, checkCellInArea(cell, area),
|
assert.NoError(t, err)
|
||||||
|
assert.Truef(t, ok,
|
||||||
"Expected cell %v to be in area %v, got false\n", cell, area)
|
"Expected cell %v to be in area %v, got false\n", cell, area)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,14 +32,15 @@ func TestCheckCellInArea(t *testing.T) {
|
||||||
for _, expectedFalseCellInArea := range expectedFalseCellInAreaList {
|
for _, expectedFalseCellInArea := range expectedFalseCellInAreaList {
|
||||||
cell := expectedFalseCellInArea[0]
|
cell := expectedFalseCellInArea[0]
|
||||||
area := expectedFalseCellInArea[1]
|
area := expectedFalseCellInArea[1]
|
||||||
|
ok, err := checkCellInArea(cell, area)
|
||||||
assert.Falsef(t, checkCellInArea(cell, area),
|
assert.NoError(t, err)
|
||||||
|
assert.Falsef(t, ok,
|
||||||
"Expected cell %v not to be inside of area %v, but got true\n", cell, area)
|
"Expected cell %v not to be inside of area %v, but got true\n", cell, area)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
ok, err := checkCellInArea("AA0", "Z0:AB1")
|
||||||
checkCellInArea("AA0", "Z0:AB1")
|
assert.EqualError(t, err, `cannot convert cell "AA0" to coordinates: invalid cell name "AA0"`)
|
||||||
})
|
assert.False(t, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetCellFloat(t *testing.T) {
|
func TestSetCellFloat(t *testing.T) {
|
||||||
|
@ -47,20 +49,28 @@ func TestSetCellFloat(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
f.SetCellFloat(sheet, "A1", 123.0, -1, 64)
|
f.SetCellFloat(sheet, "A1", 123.0, -1, 64)
|
||||||
f.SetCellFloat(sheet, "A2", 123.0, 1, 64)
|
f.SetCellFloat(sheet, "A2", 123.0, 1, 64)
|
||||||
assert.Equal(t, "123", f.GetCellValue(sheet, "A1"), "A1 should be 123")
|
val, err := f.GetCellValue(sheet, "A1")
|
||||||
assert.Equal(t, "123.0", f.GetCellValue(sheet, "A2"), "A2 should be 123.0")
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "123", val, "A1 should be 123")
|
||||||
|
val, err = f.GetCellValue(sheet, "A2")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "123.0", val, "A2 should be 123.0")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with a decimal and precision limit", func(t *testing.T) {
|
t.Run("with a decimal and precision limit", func(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
f.SetCellFloat(sheet, "A1", 123.42, 1, 64)
|
f.SetCellFloat(sheet, "A1", 123.42, 1, 64)
|
||||||
assert.Equal(t, "123.4", f.GetCellValue(sheet, "A1"), "A1 should be 123.4")
|
val, err := f.GetCellValue(sheet, "A1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "123.4", val, "A1 should be 123.4")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("with a decimal and no limit", func(t *testing.T) {
|
t.Run("with a decimal and no limit", func(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
f.SetCellFloat(sheet, "A1", 123.42, -1, 64)
|
f.SetCellFloat(sheet, "A1", 123.42, -1, 64)
|
||||||
assert.Equal(t, "123.42", f.GetCellValue(sheet, "A1"), "A1 should be 123.42")
|
val, err := f.GetCellValue(sheet, "A1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "123.42", val, "A1 should be 123.42")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +78,7 @@ func ExampleFile_SetCellFloat() {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
var x = 3.14159265
|
var x = 3.14159265
|
||||||
f.SetCellFloat("Sheet1", "A1", x, 2, 64)
|
f.SetCellFloat("Sheet1", "A1", x, 2, 64)
|
||||||
fmt.Println(f.GetCellValue("Sheet1", "A1"))
|
val, _ := f.GetCellValue("Sheet1", "A1")
|
||||||
|
fmt.Println(val)
|
||||||
// Output: 3.14
|
// Output: 3.14
|
||||||
}
|
}
|
||||||
|
|
13
chart.go
13
chart.go
|
@ -456,7 +456,10 @@ func (f *File) AddChart(sheet, cell, format string) error {
|
||||||
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
|
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
|
||||||
drawingID, drawingXML = f.prepareDrawing(xlsx, drawingID, sheet, drawingXML)
|
drawingID, drawingXML = f.prepareDrawing(xlsx, drawingID, sheet, drawingXML)
|
||||||
drawingRID := f.addDrawingRelationships(drawingID, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
|
drawingRID := f.addDrawingRelationships(drawingID, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
|
||||||
f.addDrawingChart(sheet, drawingXML, cell, formatSet.Dimension.Width, formatSet.Dimension.Height, drawingRID, &formatSet.Format)
|
err = f.addDrawingChart(sheet, drawingXML, cell, formatSet.Dimension.Width, formatSet.Dimension.Height, drawingRID, &formatSet.Format)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
f.addChart(formatSet)
|
f.addChart(formatSet)
|
||||||
f.addContentTypePart(chartID, "chart")
|
f.addContentTypePart(chartID, "chart")
|
||||||
f.addContentTypePart(drawingID, "drawings")
|
f.addContentTypePart(drawingID, "drawings")
|
||||||
|
@ -1239,8 +1242,11 @@ func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
|
||||||
|
|
||||||
// addDrawingChart provides a function to add chart graphic frame by given
|
// addDrawingChart provides a function to add chart graphic frame by given
|
||||||
// sheet, drawingXML, cell, width, height, relationship index and format sets.
|
// sheet, drawingXML, cell, width, height, relationship index and format sets.
|
||||||
func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rID int, formatSet *formatPicture) {
|
func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rID int, formatSet *formatPicture) error {
|
||||||
col, row := MustCellNameToCoordinates(cell)
|
col, row, err := CellNameToCoordinates(cell)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
colIdx := col - 1
|
colIdx := col - 1
|
||||||
rowIdx := row - 1
|
rowIdx := row - 1
|
||||||
|
|
||||||
|
@ -1290,4 +1296,5 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
|
||||||
}
|
}
|
||||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
||||||
f.Drawings[drawingXML] = content
|
f.Drawings[drawingXML] = content
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
100
col.go
100
col.go
|
@ -22,33 +22,39 @@ const (
|
||||||
// worksheet name and column name. For example, get visible state of column D
|
// worksheet name and column name. For example, get visible state of column D
|
||||||
// in Sheet1:
|
// in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.GetColVisible("Sheet1", "D")
|
// visiable, err := xlsx.GetColVisible("Sheet1", "D")
|
||||||
//
|
//
|
||||||
func (f *File) GetColVisible(sheet, col string) bool {
|
func (f *File) GetColVisible(sheet, col string) (bool, error) {
|
||||||
colNum := MustColumnNameToNumber(col)
|
visible := true
|
||||||
|
colNum, err := ColumnNameToNumber(col)
|
||||||
|
if err != nil {
|
||||||
|
return visible, err
|
||||||
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
if xlsx.Cols == nil {
|
if xlsx.Cols == nil {
|
||||||
return true
|
return visible, err
|
||||||
}
|
}
|
||||||
|
|
||||||
visible := true
|
|
||||||
for c := range xlsx.Cols.Col {
|
for c := range xlsx.Cols.Col {
|
||||||
colData := &xlsx.Cols.Col[c]
|
colData := &xlsx.Cols.Col[c]
|
||||||
if colData.Min <= colNum && colNum <= colData.Max {
|
if colData.Min <= colNum && colNum <= colData.Max {
|
||||||
visible = !colData.Hidden
|
visible = !colData.Hidden
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return visible
|
return visible, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetColVisible provides a function to set visible of a single column by given
|
// SetColVisible provides a function to set visible of a single column by given
|
||||||
// worksheet name and column name. For example, hide column D in Sheet1:
|
// worksheet name and column name. For example, hide column D in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.SetColVisible("Sheet1", "D", false)
|
// err := xlsx.SetColVisible("Sheet1", "D", false)
|
||||||
//
|
//
|
||||||
func (f *File) SetColVisible(sheet, col string, visible bool) {
|
func (f *File) SetColVisible(sheet, col string, visible bool) error {
|
||||||
colNum := MustColumnNameToNumber(col)
|
colNum, err := ColumnNameToNumber(col)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
colData := xlsxCol{
|
colData := xlsxCol{
|
||||||
Min: colNum,
|
Min: colNum,
|
||||||
Max: colNum,
|
Max: colNum,
|
||||||
|
@ -60,7 +66,7 @@ func (f *File) SetColVisible(sheet, col string, visible bool) {
|
||||||
cols := xlsxCols{}
|
cols := xlsxCols{}
|
||||||
cols.Col = append(cols.Col, colData)
|
cols.Col = append(cols.Col, colData)
|
||||||
xlsx.Cols = &cols
|
xlsx.Cols = &cols
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
for v := range xlsx.Cols.Col {
|
for v := range xlsx.Cols.Col {
|
||||||
if xlsx.Cols.Col[v].Min <= colNum && colNum <= xlsx.Cols.Col[v].Max {
|
if xlsx.Cols.Col[v].Min <= colNum && colNum <= xlsx.Cols.Col[v].Max {
|
||||||
|
@ -72,20 +78,24 @@ func (f *File) SetColVisible(sheet, col string, visible bool) {
|
||||||
colData.Hidden = !visible
|
colData.Hidden = !visible
|
||||||
colData.CustomWidth = true
|
colData.CustomWidth = true
|
||||||
xlsx.Cols.Col = append(xlsx.Cols.Col, colData)
|
xlsx.Cols.Col = append(xlsx.Cols.Col, colData)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetColOutlineLevel provides a function to get outline level of a single
|
// GetColOutlineLevel provides a function to get outline level of a single
|
||||||
// column by given worksheet name and column name. For example, get outline
|
// column by given worksheet name and column name. For example, get outline
|
||||||
// level of column D in Sheet1:
|
// level of column D in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.GetColOutlineLevel("Sheet1", "D")
|
// level, err := xlsx.GetColOutlineLevel("Sheet1", "D")
|
||||||
//
|
//
|
||||||
func (f *File) GetColOutlineLevel(sheet, col string) uint8 {
|
func (f *File) GetColOutlineLevel(sheet, col string) (uint8, error) {
|
||||||
colNum := MustColumnNameToNumber(col)
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
|
||||||
level := uint8(0)
|
level := uint8(0)
|
||||||
|
colNum, err := ColumnNameToNumber(col)
|
||||||
|
if err != nil {
|
||||||
|
return level, err
|
||||||
|
}
|
||||||
|
xlsx := f.workSheetReader(sheet)
|
||||||
if xlsx.Cols == nil {
|
if xlsx.Cols == nil {
|
||||||
return level
|
return level, err
|
||||||
}
|
}
|
||||||
for c := range xlsx.Cols.Col {
|
for c := range xlsx.Cols.Col {
|
||||||
colData := &xlsx.Cols.Col[c]
|
colData := &xlsx.Cols.Col[c]
|
||||||
|
@ -93,17 +103,20 @@ func (f *File) GetColOutlineLevel(sheet, col string) uint8 {
|
||||||
level = colData.OutlineLevel
|
level = colData.OutlineLevel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return level
|
return level, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetColOutlineLevel provides a function to set outline level of a single
|
// SetColOutlineLevel provides a function to set outline level of a single
|
||||||
// column by given worksheet name and column name. For example, set outline
|
// column by given worksheet name and column name. For example, set outline
|
||||||
// level of column D in Sheet1 to 2:
|
// level of column D in Sheet1 to 2:
|
||||||
//
|
//
|
||||||
// xlsx.SetColOutlineLevel("Sheet1", "D", 2)
|
// err := xlsx.SetColOutlineLevel("Sheet1", "D", 2)
|
||||||
//
|
//
|
||||||
func (f *File) SetColOutlineLevel(sheet, col string, level uint8) {
|
func (f *File) SetColOutlineLevel(sheet, col string, level uint8) error {
|
||||||
colNum := MustColumnNameToNumber(col)
|
colNum, err := ColumnNameToNumber(col)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
colData := xlsxCol{
|
colData := xlsxCol{
|
||||||
Min: colNum,
|
Min: colNum,
|
||||||
Max: colNum,
|
Max: colNum,
|
||||||
|
@ -115,7 +128,7 @@ func (f *File) SetColOutlineLevel(sheet, col string, level uint8) {
|
||||||
cols := xlsxCols{}
|
cols := xlsxCols{}
|
||||||
cols.Col = append(cols.Col, colData)
|
cols.Col = append(cols.Col, colData)
|
||||||
xlsx.Cols = &cols
|
xlsx.Cols = &cols
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
for v := range xlsx.Cols.Col {
|
for v := range xlsx.Cols.Col {
|
||||||
if xlsx.Cols.Col[v].Min <= colNum && colNum <= xlsx.Cols.Col[v].Max {
|
if xlsx.Cols.Col[v].Min <= colNum && colNum <= xlsx.Cols.Col[v].Max {
|
||||||
|
@ -127,21 +140,24 @@ func (f *File) SetColOutlineLevel(sheet, col string, level uint8) {
|
||||||
colData.OutlineLevel = level
|
colData.OutlineLevel = level
|
||||||
colData.CustomWidth = true
|
colData.CustomWidth = true
|
||||||
xlsx.Cols.Col = append(xlsx.Cols.Col, colData)
|
xlsx.Cols.Col = append(xlsx.Cols.Col, colData)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetColWidth provides a function to set the width of a single column or
|
// SetColWidth provides a function to set the width of a single column or
|
||||||
// multiple columns. For example:
|
// multiple columns. For example:
|
||||||
//
|
//
|
||||||
// xlsx := excelize.NewFile()
|
// xlsx := excelize.NewFile()
|
||||||
// xlsx.SetColWidth("Sheet1", "A", "H", 20)
|
// err := xlsx.SetColWidth("Sheet1", "A", "H", 20)
|
||||||
// err := xlsx.Save()
|
|
||||||
// if err != nil {
|
|
||||||
// fmt.Println(err)
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) {
|
func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) error {
|
||||||
min := MustColumnNameToNumber(startcol)
|
min, err := ColumnNameToNumber(startcol)
|
||||||
max := MustColumnNameToNumber(endcol)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
max, err := ColumnNameToNumber(endcol)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if min > max {
|
if min > max {
|
||||||
min, max = max, min
|
min, max = max, min
|
||||||
}
|
}
|
||||||
|
@ -160,6 +176,7 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) {
|
||||||
cols.Col = append(cols.Col, col)
|
cols.Col = append(cols.Col, col)
|
||||||
xlsx.Cols = &cols
|
xlsx.Cols = &cols
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// positionObjectPixels calculate the vertices that define the position of a
|
// positionObjectPixels calculate the vertices that define the position of a
|
||||||
|
@ -289,8 +306,11 @@ func (f *File) getColWidth(sheet string, col int) int {
|
||||||
|
|
||||||
// GetColWidth provides a function to get column width by given worksheet name
|
// GetColWidth provides a function to get column width by given worksheet name
|
||||||
// and column index.
|
// and column index.
|
||||||
func (f *File) GetColWidth(sheet, col string) float64 {
|
func (f *File) GetColWidth(sheet, col string) (float64, error) {
|
||||||
colNum := MustColumnNameToNumber(col)
|
colNum, err := ColumnNameToNumber(col)
|
||||||
|
if err != nil {
|
||||||
|
return defaultColWidthPixels, err
|
||||||
|
}
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
if xlsx.Cols != nil {
|
if xlsx.Cols != nil {
|
||||||
var width float64
|
var width float64
|
||||||
|
@ -300,39 +320,39 @@ func (f *File) GetColWidth(sheet, col string) float64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if width != 0 {
|
if width != 0 {
|
||||||
return width
|
return width, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Optimisation for when the column widths haven't changed.
|
// Optimisation for when the column widths haven't changed.
|
||||||
return defaultColWidthPixels
|
return defaultColWidthPixels, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertCol provides a function to insert a new column before given column
|
// InsertCol provides a function to insert a new column before given column
|
||||||
// index. For example, create a new column before column C in Sheet1:
|
// index. For example, create a new column before column C in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.InsertCol("Sheet1", "C")
|
// err := xlsx.InsertCol("Sheet1", "C")
|
||||||
//
|
//
|
||||||
func (f *File) InsertCol(sheet, col string) {
|
func (f *File) InsertCol(sheet, col string) error {
|
||||||
num, err := ColumnNameToNumber(col)
|
num, err := ColumnNameToNumber(col)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
f.adjustHelper(sheet, columns, num, 1)
|
return f.adjustHelper(sheet, columns, num, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveCol provides a function to remove single column by given worksheet
|
// RemoveCol provides a function to remove single column by given worksheet
|
||||||
// name and column index. For example, remove column C in Sheet1:
|
// name and column index. For example, remove column C in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.RemoveCol("Sheet1", "C")
|
// err := xlsx.RemoveCol("Sheet1", "C")
|
||||||
//
|
//
|
||||||
// Use this method with caution, which will affect changes in references such
|
// Use this method with caution, which will affect changes in references such
|
||||||
// as formulas, charts, and so on. If there is any referenced value of the
|
// as formulas, charts, and so on. If there is any referenced value of the
|
||||||
// worksheet, it will cause a file error when you open it. The excelize only
|
// worksheet, it will cause a file error when you open it. The excelize only
|
||||||
// partially updates these references currently.
|
// partially updates these references currently.
|
||||||
func (f *File) RemoveCol(sheet, col string) {
|
func (f *File) RemoveCol(sheet, col string) error {
|
||||||
num, err := ColumnNameToNumber(col)
|
num, err := ColumnNameToNumber(col)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err) // Fail fast to avoid possible future side effects!
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
|
@ -346,7 +366,7 @@ func (f *File) RemoveCol(sheet, col string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.adjustHelper(sheet, columns, num, -1)
|
return f.adjustHelper(sheet, columns, num, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertColWidthToPixels provieds function to convert the width of a cell
|
// convertColWidthToPixels provieds function to convert the width of a cell
|
||||||
|
|
15
comment.go
15
comment.go
|
@ -72,7 +72,7 @@ func (f *File) getSheetComments(sheetID int) string {
|
||||||
// author length is 255 and the max text length is 32512. For example, add a
|
// author length is 255 and the max text length is 32512. For example, add a
|
||||||
// comment in Sheet1!$A$30:
|
// comment in Sheet1!$A$30:
|
||||||
//
|
//
|
||||||
// xlsx.AddComment("Sheet1", "A30", `{"author":"Excelize: ","text":"This is a comment."}`)
|
// err := xlsx.AddComment("Sheet1", "A30", `{"author":"Excelize: ","text":"This is a comment."}`)
|
||||||
//
|
//
|
||||||
func (f *File) AddComment(sheet, cell, format string) error {
|
func (f *File) AddComment(sheet, cell, format string) error {
|
||||||
formatSet, err := parseFormatCommentsSet(format)
|
formatSet, err := parseFormatCommentsSet(format)
|
||||||
|
@ -107,15 +107,21 @@ func (f *File) AddComment(sheet, cell, format string) error {
|
||||||
colCount = ll
|
colCount = ll
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.addDrawingVML(commentID, drawingVML, cell, strings.Count(formatSet.Text, "\n")+1, colCount)
|
err = f.addDrawingVML(commentID, drawingVML, cell, strings.Count(formatSet.Text, "\n")+1, colCount)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
f.addContentTypePart(commentID, "comments")
|
f.addContentTypePart(commentID, "comments")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// addDrawingVML provides a function to create comment as
|
// addDrawingVML provides a function to create comment as
|
||||||
// xl/drawings/vmlDrawing%d.vml by given commit ID and cell.
|
// xl/drawings/vmlDrawing%d.vml by given commit ID and cell.
|
||||||
func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, colCount int) {
|
func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, colCount int) error {
|
||||||
col, row := MustCellNameToCoordinates(cell)
|
col, row, err := CellNameToCoordinates(cell)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
yAxis := col - 1
|
yAxis := col - 1
|
||||||
xAxis := row - 1
|
xAxis := row - 1
|
||||||
vml := f.VMLDrawing[drawingVML]
|
vml := f.VMLDrawing[drawingVML]
|
||||||
|
@ -206,6 +212,7 @@ func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount,
|
||||||
}
|
}
|
||||||
vml.Shape = append(vml.Shape, shape)
|
vml.Shape = append(vml.Shape, shape)
|
||||||
f.VMLDrawing[drawingVML] = vml
|
f.VMLDrawing[drawingVML] = vml
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// addComment provides a function to create chart as xl/comments%d.xml by
|
// addComment provides a function to create chart as xl/comments%d.xml by
|
||||||
|
|
9
date.go
9
date.go
|
@ -10,6 +10,7 @@
|
||||||
package excelize
|
package excelize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -25,18 +26,18 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// timeToExcelTime provides a function to convert time to Excel time.
|
// timeToExcelTime provides a function to convert time to Excel time.
|
||||||
func timeToExcelTime(t time.Time) float64 {
|
func timeToExcelTime(t time.Time) (float64, error) {
|
||||||
// TODO in future this should probably also handle date1904 and like TimeFromExcelTime
|
// TODO in future this should probably also handle date1904 and like TimeFromExcelTime
|
||||||
|
|
||||||
// Force user to explicit convet passed value to UTC time.
|
// Force user to explicit convet passed value to UTC time.
|
||||||
// Because for example 1900-01-01 00:00:00 +0300 MSK converts to 1900-01-01 00:00:00 +0230 LMT
|
// Because for example 1900-01-01 00:00:00 +0300 MSK converts to 1900-01-01 00:00:00 +0230 LMT
|
||||||
// probably due to daylight saving.
|
// probably due to daylight saving.
|
||||||
if t.Location() != time.UTC {
|
if t.Location() != time.UTC {
|
||||||
panic("only UTC time expected")
|
return 0.0, errors.New("only UTC time expected")
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Before(excelMinTime1900) {
|
if t.Before(excelMinTime1900) {
|
||||||
return 0.0
|
return 0.0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tt := t
|
tt := t
|
||||||
|
@ -60,7 +61,7 @@ func timeToExcelTime(t time.Time) float64 {
|
||||||
if t.After(excelBuggyPeriodStart) {
|
if t.After(excelBuggyPeriodStart) {
|
||||||
result += 1.0
|
result += 1.0
|
||||||
}
|
}
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// shiftJulianToNoon provides a function to process julian date to noon.
|
// shiftJulianToNoon provides a function to process julian date to noon.
|
||||||
|
|
|
@ -31,7 +31,9 @@ var trueExpectedDateList = []dateTest{
|
||||||
func TestTimeToExcelTime(t *testing.T) {
|
func TestTimeToExcelTime(t *testing.T) {
|
||||||
for i, test := range trueExpectedDateList {
|
for i, test := range trueExpectedDateList {
|
||||||
t.Run(fmt.Sprintf("TestData%d", i+1), func(t *testing.T) {
|
t.Run(fmt.Sprintf("TestData%d", i+1), func(t *testing.T) {
|
||||||
assert.Equalf(t, test.ExcelValue, timeToExcelTime(test.GoValue),
|
excelTime, err := timeToExcelTime(test.GoValue)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equalf(t, test.ExcelValue, excelTime,
|
||||||
"Time: %s", test.GoValue.String())
|
"Time: %s", test.GoValue.String())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -44,9 +46,8 @@ func TestTimeToExcelTime_Timezone(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, test := range trueExpectedDateList {
|
for i, test := range trueExpectedDateList {
|
||||||
t.Run(fmt.Sprintf("TestData%d", i+1), func(t *testing.T) {
|
t.Run(fmt.Sprintf("TestData%d", i+1), func(t *testing.T) {
|
||||||
assert.Panics(t, func() {
|
_, err := timeToExcelTime(test.GoValue.In(location))
|
||||||
timeToExcelTime(test.GoValue.In(location))
|
assert.EqualError(t, err, "only UTC time expected")
|
||||||
}, "Time: %s", test.GoValue.String())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
excelize.go
12
excelize.go
|
@ -98,11 +98,16 @@ func OpenReader(r io.Reader) (*File, error) {
|
||||||
// setDefaultTimeStyle provides a function to set default numbers format for
|
// 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 coordinates and
|
||||||
// number format code.
|
// number format code.
|
||||||
func (f *File) setDefaultTimeStyle(sheet, axis string, format int) {
|
func (f *File) setDefaultTimeStyle(sheet, axis string, format int) error {
|
||||||
if f.GetCellStyle(sheet, axis) == 0 {
|
s, err := f.GetCellStyle(sheet, axis)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if s == 0 {
|
||||||
style, _ := f.NewStyle(`{"number_format": ` + strconv.Itoa(format) + `}`)
|
style, _ := f.NewStyle(`{"number_format": ` + strconv.Itoa(format) + `}`)
|
||||||
f.SetCellStyle(sheet, axis, axis, style)
|
f.SetCellStyle(sheet, axis, axis, style)
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// workSheetReader provides a function to get the pointer to the structure
|
// workSheetReader provides a function to get the pointer to the structure
|
||||||
|
@ -218,7 +223,8 @@ func (f *File) GetMergeCells(sheet string) []MergeCell {
|
||||||
for i := range xlsx.MergeCells.Cells {
|
for i := range xlsx.MergeCells.Cells {
|
||||||
ref := xlsx.MergeCells.Cells[i].Ref
|
ref := xlsx.MergeCells.Cells[i].Ref
|
||||||
axis := strings.Split(ref, ":")[0]
|
axis := strings.Split(ref, ":")[0]
|
||||||
mergeCells = append(mergeCells, []string{ref, f.GetCellValue(sheet, axis)})
|
val, _ := f.GetCellValue(sheet, axis)
|
||||||
|
mergeCells = append(mergeCells, []string{ref, val})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
202
excelize_test.go
202
excelize_test.go
|
@ -27,7 +27,8 @@ func TestOpenFile(t *testing.T) {
|
||||||
// Test get all the rows in a not exists worksheet.
|
// Test get all the rows in a not exists worksheet.
|
||||||
xlsx.GetRows("Sheet4")
|
xlsx.GetRows("Sheet4")
|
||||||
// Test get all the rows in a worksheet.
|
// Test get all the rows in a worksheet.
|
||||||
rows := xlsx.GetRows("Sheet2")
|
rows, err := xlsx.GetRows("Sheet2")
|
||||||
|
assert.NoError(t, err)
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
for _, cell := range row {
|
for _, cell := range row {
|
||||||
t.Log(cell, "\t")
|
t.Log(cell, "\t")
|
||||||
|
@ -40,16 +41,13 @@ func TestOpenFile(t *testing.T) {
|
||||||
xlsx.SetCellDefault("Sheet2", "A1", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64))
|
xlsx.SetCellDefault("Sheet2", "A1", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64))
|
||||||
|
|
||||||
// Test set cell value with illegal row number.
|
// Test set cell value with illegal row number.
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetCellDefault("Sheet2", "A", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64)),
|
||||||
xlsx.SetCellDefault("Sheet2", "A", strconv.FormatFloat(float64(-100.1588), 'f', -1, 64))
|
`cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
||||||
})
|
|
||||||
|
|
||||||
xlsx.SetCellInt("Sheet2", "A1", 100)
|
xlsx.SetCellInt("Sheet2", "A1", 100)
|
||||||
|
|
||||||
// Test set cell integer value with illegal row number.
|
// Test set cell integer value with illegal row number.
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetCellInt("Sheet2", "A", 100), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
||||||
xlsx.SetCellInt("Sheet2", "A", 100)
|
|
||||||
})
|
|
||||||
|
|
||||||
xlsx.SetCellStr("Sheet2", "C11", "Knowns")
|
xlsx.SetCellStr("Sheet2", "C11", "Knowns")
|
||||||
// Test max characters in a cell.
|
// Test max characters in a cell.
|
||||||
|
@ -62,35 +60,31 @@ func TestOpenFile(t *testing.T) {
|
||||||
xlsx.SetCellStr("Sheet10", "b230", "10")
|
xlsx.SetCellStr("Sheet10", "b230", "10")
|
||||||
|
|
||||||
// Test set cell string value with illegal row number.
|
// Test set cell string value with illegal row number.
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetCellStr("Sheet10", "A", "10"), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
||||||
xlsx.SetCellStr("Sheet10", "A", "10")
|
|
||||||
})
|
|
||||||
|
|
||||||
xlsx.SetActiveSheet(2)
|
xlsx.SetActiveSheet(2)
|
||||||
// Test get cell formula with given rows number.
|
// Test get cell formula with given rows number.
|
||||||
xlsx.GetCellFormula("Sheet1", "B19")
|
_, err = xlsx.GetCellFormula("Sheet1", "B19")
|
||||||
|
assert.NoError(t, err)
|
||||||
// Test get cell formula with illegal worksheet name.
|
// Test get cell formula with illegal worksheet name.
|
||||||
xlsx.GetCellFormula("Sheet2", "B20")
|
_, err = xlsx.GetCellFormula("Sheet2", "B20")
|
||||||
xlsx.GetCellFormula("Sheet1", "B20")
|
assert.NoError(t, err)
|
||||||
|
_, err = xlsx.GetCellFormula("Sheet1", "B20")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Test get cell formula with illegal rows number.
|
// Test get cell formula with illegal rows number.
|
||||||
assert.Panics(t, func() {
|
_, err = xlsx.GetCellFormula("Sheet1", "B")
|
||||||
xlsx.GetCellFormula("Sheet1", "B")
|
assert.EqualError(t, err, `cannot convert cell "B" to coordinates: invalid cell name "B"`)
|
||||||
})
|
|
||||||
|
|
||||||
// Test get shared cell formula
|
// Test get shared cell formula
|
||||||
xlsx.GetCellFormula("Sheet2", "H11")
|
xlsx.GetCellFormula("Sheet2", "H11")
|
||||||
xlsx.GetCellFormula("Sheet2", "I11")
|
xlsx.GetCellFormula("Sheet2", "I11")
|
||||||
getSharedForumula(&xlsxWorksheet{}, "")
|
getSharedForumula(&xlsxWorksheet{}, "")
|
||||||
|
|
||||||
// Test read cell value with given illegal rows number.
|
// Test read cell value with given illegal rows number.
|
||||||
assert.Panics(t, func() {
|
_, err = xlsx.GetCellValue("Sheet2", "a-1")
|
||||||
xlsx.GetCellValue("Sheet2", "a-1")
|
assert.EqualError(t, err, `cannot convert cell "A-1" to coordinates: invalid cell name "A-1"`)
|
||||||
})
|
_, err = xlsx.GetCellValue("Sheet2", "A")
|
||||||
|
assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
||||||
assert.Panics(t, func() {
|
|
||||||
xlsx.GetCellValue("Sheet2", "A")
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test read cell value with given lowercase column number.
|
// Test read cell value with given lowercase column number.
|
||||||
xlsx.GetCellValue("Sheet2", "a5")
|
xlsx.GetCellValue("Sheet2", "a5")
|
||||||
|
@ -127,14 +121,14 @@ func TestOpenFile(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, test := range booltest {
|
for _, test := range booltest {
|
||||||
xlsx.SetCellValue("Sheet2", "F16", test.value)
|
xlsx.SetCellValue("Sheet2", "F16", test.value)
|
||||||
assert.Equal(t, test.expected, xlsx.GetCellValue("Sheet2", "F16"))
|
val, err := xlsx.GetCellValue("Sheet2", "F16")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, test.expected, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellValue("Sheet2", "G2", nil)
|
xlsx.SetCellValue("Sheet2", "G2", nil)
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetCellValue("Sheet2", "G4", time.Now()), "only UTC time expected")
|
||||||
xlsx.SetCellValue("Sheet2", "G4", time.Now())
|
|
||||||
})
|
|
||||||
|
|
||||||
xlsx.SetCellValue("Sheet2", "G4", time.Now().UTC())
|
xlsx.SetCellValue("Sheet2", "G4", time.Now().UTC())
|
||||||
// 02:46:40
|
// 02:46:40
|
||||||
|
@ -320,19 +314,15 @@ func TestSetCellHyperLink(t *testing.T) {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
// Test set cell hyperlink in a work sheet already have hyperlinks.
|
// Test set cell hyperlink in a work sheet already have hyperlinks.
|
||||||
xlsx.SetCellHyperLink("Sheet1", "B19", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
|
assert.NoError(t, xlsx.SetCellHyperLink("Sheet1", "B19", "https://github.com/360EntSecGroup-Skylar/excelize", "External"))
|
||||||
// Test add first hyperlink in a work sheet.
|
// Test add first hyperlink in a work sheet.
|
||||||
xlsx.SetCellHyperLink("Sheet2", "C1", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
|
assert.NoError(t, xlsx.SetCellHyperLink("Sheet2", "C1", "https://github.com/360EntSecGroup-Skylar/excelize", "External"))
|
||||||
// Test add Location hyperlink in a work sheet.
|
// Test add Location hyperlink in a work sheet.
|
||||||
xlsx.SetCellHyperLink("Sheet2", "D6", "Sheet1!D8", "Location")
|
assert.NoError(t, xlsx.SetCellHyperLink("Sheet2", "D6", "Sheet1!D8", "Location"))
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetCellHyperLink("Sheet2", "C3", "Sheet1!D8", ""), `invalid link type ""`)
|
||||||
xlsx.SetCellHyperLink("Sheet2", "C3", "Sheet1!D8", "")
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetCellHyperLink("Sheet2", "", "Sheet1!D60", "Location"), `invalid cell name ""`)
|
||||||
xlsx.SetCellHyperLink("Sheet2", "", "Sheet1!D60", "Location")
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellHyperLink.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellHyperLink.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -343,15 +333,17 @@ func TestGetCellHyperLink(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
link, target, err := xlsx.GetCellHyperLink("Sheet1", "")
|
||||||
xlsx.GetCellHyperLink("Sheet1", "")
|
assert.EqualError(t, err, `invalid cell name ""`)
|
||||||
})
|
|
||||||
|
|
||||||
link, target := xlsx.GetCellHyperLink("Sheet1", "A22")
|
link, target, err = xlsx.GetCellHyperLink("Sheet1", "A22")
|
||||||
|
assert.NoError(t, err)
|
||||||
t.Log(link, target)
|
t.Log(link, target)
|
||||||
link, target = xlsx.GetCellHyperLink("Sheet2", "D6")
|
link, target, err = xlsx.GetCellHyperLink("Sheet2", "D6")
|
||||||
|
assert.NoError(t, err)
|
||||||
t.Log(link, target)
|
t.Log(link, target)
|
||||||
link, target = xlsx.GetCellHyperLink("Sheet3", "H3")
|
link, target, err = xlsx.GetCellHyperLink("Sheet3", "H3")
|
||||||
|
assert.NoError(t, err)
|
||||||
t.Log(link, target)
|
t.Log(link, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,9 +357,7 @@ func TestSetCellFormula(t *testing.T) {
|
||||||
xlsx.SetCellFormula("Sheet1", "C19", "SUM(Sheet2!D2,Sheet2!D9)")
|
xlsx.SetCellFormula("Sheet1", "C19", "SUM(Sheet2!D2,Sheet2!D9)")
|
||||||
|
|
||||||
// Test set cell formula with illegal rows number.
|
// Test set cell formula with illegal rows number.
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetCellFormula("Sheet1", "C", "SUM(Sheet2!D2,Sheet2!D9)"), `cannot convert cell "C" to coordinates: invalid cell name "C"`)
|
||||||
xlsx.SetCellFormula("Sheet1", "C", "SUM(Sheet2!D2,Sheet2!D9)")
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellFormula1.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellFormula1.xlsx")))
|
||||||
|
|
||||||
|
@ -496,21 +486,16 @@ func TestSetCellStyleAlignment(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet1", "A22", "A22", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "A22", "A22", style))
|
||||||
|
|
||||||
// Test set cell style with given illegal rows number.
|
// Test set cell style with given illegal rows number.
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetCellStyle("Sheet1", "A", "A22", style), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
||||||
xlsx.SetCellStyle("Sheet1", "A", "A22", style)
|
assert.EqualError(t, xlsx.SetCellStyle("Sheet1", "A22", "A", style), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
||||||
})
|
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
|
||||||
xlsx.SetCellStyle("Sheet1", "A22", "A", style)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Test get cell style with given illegal rows number.
|
// Test get cell style with given illegal rows number.
|
||||||
assert.Panics(t, func() {
|
index, err := xlsx.GetCellStyle("Sheet1", "A")
|
||||||
xlsx.GetCellStyle("Sheet1", "A")
|
assert.Equal(t, 0, index)
|
||||||
})
|
assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleAlignment.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleAlignment.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -528,19 +513,19 @@ func TestSetCellStyleBorder(t *testing.T) {
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "J21", "L25", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "J21", "L25", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":2},{"type":"top","color":"00FF00","style":3},{"type":"bottom","color":"FFFF00","style":4},{"type":"right","color":"FF0000","style":5},{"type":"diagonalDown","color":"A020F0","style":6},{"type":"diagonalUp","color":"A020F0","style":7}],"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":1}}`)
|
style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":2},{"type":"top","color":"00FF00","style":3},{"type":"bottom","color":"FFFF00","style":4},{"type":"right","color":"FF0000","style":5},{"type":"diagonalDown","color":"A020F0","style":6},{"type":"diagonalUp","color":"A020F0","style":7}],"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":1}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "M28", "K24", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "M28", "K24", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":2},{"type":"top","color":"00FF00","style":3},{"type":"bottom","color":"FFFF00","style":4},{"type":"right","color":"FF0000","style":5},{"type":"diagonalDown","color":"A020F0","style":6},{"type":"diagonalUp","color":"A020F0","style":7}],"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":4}}`)
|
style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":2},{"type":"top","color":"00FF00","style":3},{"type":"bottom","color":"FFFF00","style":4},{"type":"right","color":"FF0000","style":5},{"type":"diagonalDown","color":"A020F0","style":6},{"type":"diagonalUp","color":"A020F0","style":7}],"fill":{"type":"gradient","color":["#FFFFFF","#E0EBF5"],"shading":4}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "M28", "K24", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "M28", "K24", style))
|
||||||
|
|
||||||
// Test set border and solid style pattern fill for a single cell.
|
// Test set border and solid style pattern fill for a single cell.
|
||||||
style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":8},{"type":"top","color":"00FF00","style":9},{"type":"bottom","color":"FFFF00","style":10},{"type":"right","color":"FF0000","style":11},{"type":"diagonalDown","color":"A020F0","style":12},{"type":"diagonalUp","color":"A020F0","style":13}],"fill":{"type":"pattern","color":["#E0EBF5"],"pattern":1}}`)
|
style, err = xlsx.NewStyle(`{"border":[{"type":"left","color":"0000FF","style":8},{"type":"top","color":"00FF00","style":9},{"type":"bottom","color":"FFFF00","style":10},{"type":"right","color":"FF0000","style":11},{"type":"diagonalDown","color":"A020F0","style":12},{"type":"diagonalUp","color":"A020F0","style":13}],"fill":{"type":"pattern","color":["#E0EBF5"],"pattern":1}}`)
|
||||||
|
@ -548,7 +533,7 @@ func TestSetCellStyleBorder(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet1", "O22", "O22", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "O22", "O22", style))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleBorder.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleBorder.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -596,7 +581,7 @@ func TestSetCellStyleNumberFormat(t *testing.T) {
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet2", c, c, style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet2", c, c, style))
|
||||||
t.Log(xlsx.GetCellValue("Sheet2", c))
|
t.Log(xlsx.GetCellValue("Sheet2", c))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -605,7 +590,7 @@ func TestSetCellStyleNumberFormat(t *testing.T) {
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet2", "L33", "L33", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet2", "L33", "L33", style))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleNumberFormat.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleNumberFormat.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -625,13 +610,13 @@ func TestSetCellStyleCurrencyNumberFormat(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet1", "A1", "A1", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "A1", "A1", style))
|
||||||
style, err = xlsx.NewStyle(`{"number_format": 188, "decimal_places": 31, "negred": true}`)
|
style, err = xlsx.NewStyle(`{"number_format": 188, "decimal_places": 31, "negred": true}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet1", "A2", "A2", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "A2", "A2", style))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCurrencyNumberFormat.TestBook3.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCurrencyNumberFormat.TestBook3.xlsx")))
|
||||||
})
|
})
|
||||||
|
@ -654,19 +639,19 @@ func TestSetCellStyleCurrencyNumberFormat(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet1", "A1", "A1", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "A1", "A1", style))
|
||||||
style, err = xlsx.NewStyle(`{"number_format": 31, "lang": "ko-kr"}`)
|
style, err = xlsx.NewStyle(`{"number_format": 31, "lang": "ko-kr"}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet1", "A2", "A2", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "A2", "A2", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"number_format": 71, "lang": "th-th"}`)
|
style, err = xlsx.NewStyle(`{"number_format": 71, "lang": "th-th"}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "A2", "A2", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "A2", "A2", style))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCurrencyNumberFormat.TestBook4.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCurrencyNumberFormat.TestBook4.xlsx")))
|
||||||
})
|
})
|
||||||
|
@ -680,12 +665,12 @@ func TestSetCellStyleCustomNumberFormat(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "A1", "A1", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "A1", "A1", style))
|
||||||
style, err = xlsx.NewStyle(`{"custom_number_format": "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yyyy;@"}`)
|
style, err = xlsx.NewStyle(`{"custom_number_format": "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yyyy;@"}`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "A2", "A2", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "A2", "A2", style))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCustomNumberFormat.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleCustomNumberFormat.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -702,25 +687,25 @@ func TestSetCellStyleFill(t *testing.T) {
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "O23", "O23", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "O23", "O23", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"fill":{"type":"gradient","color":["#FFFFFF"],"shading":1}}`)
|
style, err = xlsx.NewStyle(`{"fill":{"type":"gradient","color":["#FFFFFF"],"shading":1}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "O23", "O23", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "O23", "O23", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"fill":{"type":"pattern","color":[],"pattern":1}}`)
|
style, err = xlsx.NewStyle(`{"fill":{"type":"pattern","color":[],"pattern":1}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "O23", "O23", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "O23", "O23", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"fill":{"type":"pattern","color":["#E0EBF5"],"pattern":19}}`)
|
style, err = xlsx.NewStyle(`{"fill":{"type":"pattern","color":["#E0EBF5"],"pattern":19}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
xlsx.SetCellStyle("Sheet1", "O23", "O23", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet1", "O23", "O23", style))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleFill.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleFill.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -737,35 +722,35 @@ func TestSetCellStyleFont(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet2", "A1", "A1", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet2", "A1", "A1", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"font":{"italic":true,"underline":"double"}}`)
|
style, err = xlsx.NewStyle(`{"font":{"italic":true,"underline":"double"}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet2", "A2", "A2", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet2", "A2", "A2", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"font":{"bold":true}}`)
|
style, err = xlsx.NewStyle(`{"font":{"bold":true}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet2", "A3", "A3", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet2", "A3", "A3", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"font":{"bold":true,"family":"","size":0,"color":"","underline":""}}`)
|
style, err = xlsx.NewStyle(`{"font":{"bold":true,"family":"","size":0,"color":"","underline":""}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet2", "A4", "A4", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet2", "A4", "A4", style))
|
||||||
|
|
||||||
style, err = xlsx.NewStyle(`{"font":{"color":"#777777"}}`)
|
style, err = xlsx.NewStyle(`{"font":{"color":"#777777"}}`)
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet2", "A5", "A5", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet2", "A5", "A5", style))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleFont.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleFont.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -782,7 +767,7 @@ func TestSetCellStyleProtection(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellStyle("Sheet2", "A6", "A6", style)
|
assert.NoError(t, xlsx.SetCellStyle("Sheet2", "A6", "A6", style))
|
||||||
err = xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleProtection.xlsx"))
|
err = xlsx.SaveAs(filepath.Join("test", "TestSetCellStyleProtection.xlsx"))
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
@ -818,7 +803,8 @@ func TestGetPicture(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
file, raw := xlsx.GetPicture("Sheet1", "F21")
|
file, raw, err := xlsx.GetPicture("Sheet1", "F21")
|
||||||
|
assert.NoError(t, err)
|
||||||
if !assert.NotEmpty(t, filepath.Join("test", file)) || !assert.NotEmpty(t, raw) ||
|
if !assert.NotEmpty(t, filepath.Join("test", file)) || !assert.NotEmpty(t, raw) ||
|
||||||
!assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0644)) {
|
!assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0644)) {
|
||||||
|
|
||||||
|
@ -826,12 +812,14 @@ func TestGetPicture(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to get picture from a worksheet that doesn't contain any images.
|
// Try to get picture from a worksheet that doesn't contain any images.
|
||||||
file, raw = xlsx.GetPicture("Sheet3", "I9")
|
file, raw, err = xlsx.GetPicture("Sheet3", "I9")
|
||||||
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, file)
|
assert.Empty(t, file)
|
||||||
assert.Empty(t, raw)
|
assert.Empty(t, raw)
|
||||||
|
|
||||||
// Try to get picture from a cell that doesn't contain an image.
|
// Try to get picture from a cell that doesn't contain an image.
|
||||||
file, raw = xlsx.GetPicture("Sheet2", "A2")
|
file, raw, err = xlsx.GetPicture("Sheet2", "A2")
|
||||||
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, file)
|
assert.Empty(t, file)
|
||||||
assert.Empty(t, raw)
|
assert.Empty(t, raw)
|
||||||
|
|
||||||
|
@ -850,7 +838,8 @@ func TestGetPicture(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
file, raw = xlsx.GetPicture("Sheet1", "F21")
|
file, raw, err = xlsx.GetPicture("Sheet1", "F21")
|
||||||
|
assert.NoError(t, err)
|
||||||
if !assert.NotEmpty(t, filepath.Join("test", file)) || !assert.NotEmpty(t, raw) ||
|
if !assert.NotEmpty(t, filepath.Join("test", file)) || !assert.NotEmpty(t, raw) ||
|
||||||
!assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0644)) {
|
!assert.NoError(t, ioutil.WriteFile(filepath.Join("test", file), raw, 0644)) {
|
||||||
|
|
||||||
|
@ -858,7 +847,8 @@ func TestGetPicture(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to get picture from a local storage file that doesn't contain an image.
|
// Try to get picture from a local storage file that doesn't contain an image.
|
||||||
file, raw = xlsx.GetPicture("Sheet1", "F22")
|
file, raw, err = xlsx.GetPicture("Sheet1", "F22")
|
||||||
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, file)
|
assert.Empty(t, file)
|
||||||
assert.Empty(t, raw)
|
assert.Empty(t, raw)
|
||||||
}
|
}
|
||||||
|
@ -913,7 +903,9 @@ func TestCopySheet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.SetCellValue("Sheet4", "F1", "Hello")
|
xlsx.SetCellValue("Sheet4", "F1", "Hello")
|
||||||
assert.NotEqual(t, "Hello", xlsx.GetCellValue("Sheet1", "F1"))
|
val, err := xlsx.GetCellValue("Sheet1", "F1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotEqual(t, "Hello", val)
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestCopySheet.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestCopySheet.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -1101,7 +1093,7 @@ func TestInsertCol(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.InsertCol(sheet1, "A")
|
assert.NoError(t, xlsx.InsertCol(sheet1, "A"))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertCol.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertCol.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -1118,8 +1110,8 @@ func TestRemoveCol(t *testing.T) {
|
||||||
xlsx.MergeCell(sheet1, "A1", "B1")
|
xlsx.MergeCell(sheet1, "A1", "B1")
|
||||||
xlsx.MergeCell(sheet1, "A2", "B2")
|
xlsx.MergeCell(sheet1, "A2", "B2")
|
||||||
|
|
||||||
xlsx.RemoveCol(sheet1, "A")
|
assert.NoError(t, xlsx.RemoveCol(sheet1, "A"))
|
||||||
xlsx.RemoveCol(sheet1, "A")
|
assert.NoError(t, xlsx.RemoveCol(sheet1, "A"))
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestRemoveCol.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestRemoveCol.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -1242,18 +1234,11 @@ func TestSetSheetRow(t *testing.T) {
|
||||||
|
|
||||||
xlsx.SetSheetRow("Sheet1", "B27", &[]interface{}{"cell", nil, int32(42), float64(42), time.Now().UTC()})
|
xlsx.SetSheetRow("Sheet1", "B27", &[]interface{}{"cell", nil, int32(42), float64(42), time.Now().UTC()})
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetSheetRow("Sheet1", "", &[]interface{}{"cell", nil, 2}),
|
||||||
xlsx.SetSheetRow("Sheet1", "", &[]interface{}{"cell", nil, 2})
|
`cannot convert cell "" to coordinates: invalid cell name ""`)
|
||||||
})
|
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
|
||||||
xlsx.SetSheetRow("Sheet1", "B27", []interface{}{})
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
|
||||||
xlsx.SetSheetRow("Sheet1", "B27", &xlsx)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
assert.EqualError(t, xlsx.SetSheetRow("Sheet1", "B27", []interface{}{}), `pointer to slice expected`)
|
||||||
|
assert.EqualError(t, xlsx.SetSheetRow("Sheet1", "B27", &xlsx), `pointer to slice expected`)
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetSheetRow.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestSetSheetRow.xlsx")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1267,16 +1252,15 @@ func TestOutlineLevel(t *testing.T) {
|
||||||
xlsx.SetColOutlineLevel("Sheet2", "B", 2)
|
xlsx.SetColOutlineLevel("Sheet2", "B", 2)
|
||||||
xlsx.SetRowOutlineLevel("Sheet1", 2, 250)
|
xlsx.SetRowOutlineLevel("Sheet1", 2, 250)
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetRowOutlineLevel("Sheet1", 0, 1), "invalid row number 0")
|
||||||
xlsx.SetRowOutlineLevel("Sheet1", 0, 1)
|
level, err := xlsx.GetRowOutlineLevel("Sheet1", 2)
|
||||||
})
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, uint8(250), level)
|
||||||
|
|
||||||
assert.Equal(t, uint8(250), xlsx.GetRowOutlineLevel("Sheet1", 2))
|
_, err = xlsx.GetRowOutlineLevel("Sheet1", 0)
|
||||||
|
assert.EqualError(t, err, `invalid row number 0`)
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
err = xlsx.SaveAs(filepath.Join("test", "TestOutlineLevel.xlsx"))
|
||||||
xlsx.GetRowOutlineLevel("Sheet1", 0)
|
|
||||||
})
|
|
||||||
err := xlsx.SaveAs(filepath.Join("test", "TestOutlineLevel.xlsx"))
|
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
@ -1418,7 +1402,7 @@ func prepareTestBook4() (*File, error) {
|
||||||
func fillCells(xlsx *File, sheet string, colCount, rowCount int) {
|
func fillCells(xlsx *File, sheet string, colCount, rowCount int) {
|
||||||
for col := 1; col <= colCount; col++ {
|
for col := 1; col <= colCount; col++ {
|
||||||
for row := 1; row <= rowCount; row++ {
|
for row := 1; row <= rowCount; row++ {
|
||||||
cell := MustCoordinatesToCellName(col, row)
|
cell, _ := CoordinatesToCellName(col, row)
|
||||||
xlsx.SetCellStr(sheet, cell, cell)
|
xlsx.SetCellStr(sheet, cell, cell)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
lib.go
53
lib.go
|
@ -135,22 +135,6 @@ func ColumnNameToNumber(name string) (int, error) {
|
||||||
return col, nil
|
return col, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustColumnNameToNumber provides a function to convert Excel sheet column
|
|
||||||
// name to int. Column name case insencitive.
|
|
||||||
// Function returns error if column name incorrect.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// excelize.MustColumnNameToNumber("AK") // returns 37
|
|
||||||
//
|
|
||||||
func MustColumnNameToNumber(name string) int {
|
|
||||||
n, err := ColumnNameToNumber(name)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// ColumnNumberToName provides a function to convert integer
|
// ColumnNumberToName provides a function to convert integer
|
||||||
// to Excel sheet column title.
|
// to Excel sheet column title.
|
||||||
//
|
//
|
||||||
|
@ -174,8 +158,9 @@ func ColumnNumberToName(num int) (string, error) {
|
||||||
// to [X, Y] coordinates or retrusn an error.
|
// to [X, Y] coordinates or retrusn an error.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// CellCoordinates("A1") // returns 1, 1, nil
|
//
|
||||||
// CellCoordinates("Z3") // returns 26, 3, nil
|
// CellCoordinates("A1") // returns 1, 1, nil
|
||||||
|
// CellCoordinates("Z3") // returns 26, 3, nil
|
||||||
//
|
//
|
||||||
func CellNameToCoordinates(cell string) (int, int, error) {
|
func CellNameToCoordinates(cell string) (int, int, error) {
|
||||||
const msg = "cannot convert cell %q to coordinates: %v"
|
const msg = "cannot convert cell %q to coordinates: %v"
|
||||||
|
@ -193,25 +178,12 @@ func CellNameToCoordinates(cell string) (int, int, error) {
|
||||||
return col, row, nil
|
return col, row, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustCellNameToCoordinates converts alpha-numeric cell name
|
// CoordinatesToCellName converts [X, Y] coordinates to alpha-numeric cell
|
||||||
// to [X, Y] coordinates or panics.
|
// name or returns an error.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// MustCellNameToCoordinates("A1") // returns 1, 1
|
|
||||||
// MustCellNameToCoordinates("Z3") // returns 26, 3
|
|
||||||
//
|
//
|
||||||
func MustCellNameToCoordinates(cell string) (int, int) {
|
// CoordinatesToCellName(1, 1) // returns "A1", nil
|
||||||
c, r, err := CellNameToCoordinates(cell)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return c, r
|
|
||||||
}
|
|
||||||
|
|
||||||
// CoordinatesToCellName converts [X, Y] coordinates to alpha-numeric cell name or returns an error.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// CoordinatesToCellName(1, 1) // returns "A1", nil
|
|
||||||
//
|
//
|
||||||
func CoordinatesToCellName(col, row int) (string, error) {
|
func CoordinatesToCellName(col, row int) (string, error) {
|
||||||
if col < 1 || row < 1 {
|
if col < 1 || row < 1 {
|
||||||
|
@ -224,19 +196,6 @@ func CoordinatesToCellName(col, row int) (string, error) {
|
||||||
return fmt.Sprintf("%s%d", colname, row), nil
|
return fmt.Sprintf("%s%d", colname, row), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustCoordinatesToCellName converts [X, Y] coordinates to alpha-numeric cell name or panics.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// MustCoordinatesToCellName(1, 1) // returns "A1"
|
|
||||||
//
|
|
||||||
func MustCoordinatesToCellName(col, row int) string {
|
|
||||||
n, err := CoordinatesToCellName(col, row)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// boolPtr returns a pointer to a bool with the given value.
|
// boolPtr returns a pointer to a bool with the given value.
|
||||||
func boolPtr(b bool) *bool { return &b }
|
func boolPtr(b bool) *bool { return &b }
|
||||||
|
|
||||||
|
|
|
@ -71,9 +71,6 @@ func TestColumnNameToNumber_Error(t *testing.T) {
|
||||||
if assert.Errorf(t, err, msg, col.Name) {
|
if assert.Errorf(t, err, msg, col.Name) {
|
||||||
assert.Equalf(t, col.Num, out, msg, col.Name)
|
assert.Equalf(t, col.Num, out, msg, col.Name)
|
||||||
}
|
}
|
||||||
assert.Panicsf(t, func() {
|
|
||||||
MustColumnNameToNumber(col.Name)
|
|
||||||
}, msg, col.Name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +171,6 @@ func TestCellNameToCoordinates_Error(t *testing.T) {
|
||||||
assert.Equalf(t, -1, c, msg, cell)
|
assert.Equalf(t, -1, c, msg, cell)
|
||||||
assert.Equalf(t, -1, r, msg, cell)
|
assert.Equalf(t, -1, r, msg, cell)
|
||||||
}
|
}
|
||||||
assert.Panicsf(t, func() {
|
|
||||||
MustCellNameToCoordinates(cell)
|
|
||||||
}, msg, cell)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,9 +193,6 @@ func TestCoordinatesToCellName_Error(t *testing.T) {
|
||||||
if assert.Errorf(t, err, msg, col, row) {
|
if assert.Errorf(t, err, msg, col, row) {
|
||||||
assert.Equalf(t, "", cell, msg, col, row)
|
assert.Equalf(t, "", cell, msg, col, row)
|
||||||
}
|
}
|
||||||
assert.Panicsf(t, func() {
|
|
||||||
MustCoordinatesToCellName(col, row)
|
|
||||||
}, msg, col, row)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, col := range invalidIndexes {
|
for _, col := range invalidIndexes {
|
||||||
|
|
32
picture.go
32
picture.go
|
@ -162,7 +162,10 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
|
||||||
}
|
}
|
||||||
drawingHyperlinkRID = f.addDrawingRelationships(drawingID, SourceRelationshipHyperLink, formatSet.Hyperlink, hyperlinkType)
|
drawingHyperlinkRID = f.addDrawingRelationships(drawingID, SourceRelationshipHyperLink, formatSet.Hyperlink, hyperlinkType)
|
||||||
}
|
}
|
||||||
f.addDrawingPicture(sheet, drawingXML, cell, name, img.Width, img.Height, drawingRID, drawingHyperlinkRID, formatSet)
|
err = f.addDrawingPicture(sheet, drawingXML, cell, name, img.Width, img.Height, drawingRID, drawingHyperlinkRID, formatSet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
f.addMedia(file, ext)
|
f.addMedia(file, ext)
|
||||||
f.addContentTypePart(drawingID, "drawings")
|
f.addContentTypePart(drawingID, "drawings")
|
||||||
return err
|
return err
|
||||||
|
@ -270,8 +273,11 @@ func (f *File) countDrawings() int {
|
||||||
// addDrawingPicture provides a function to add picture by given sheet,
|
// addDrawingPicture provides a function to add picture by given sheet,
|
||||||
// drawingXML, cell, file name, width, height relationship index and format
|
// drawingXML, cell, file name, width, height relationship index and format
|
||||||
// sets.
|
// sets.
|
||||||
func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, height, rID, hyperlinkRID int, formatSet *formatPicture) {
|
func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, height, rID, hyperlinkRID int, formatSet *formatPicture) error {
|
||||||
col, row := MustCellNameToCoordinates(cell)
|
col, row, err := CellNameToCoordinates(cell)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
width = int(float64(width) * formatSet.XScale)
|
width = int(float64(width) * formatSet.XScale)
|
||||||
height = int(float64(height) * formatSet.YScale)
|
height = int(float64(height) * formatSet.YScale)
|
||||||
col--
|
col--
|
||||||
|
@ -315,6 +321,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
|
||||||
}
|
}
|
||||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
||||||
f.Drawings[drawingXML] = content
|
f.Drawings[drawingXML] = content
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// addDrawingRelationships provides a function to add image part relationships
|
// addDrawingRelationships provides a function to add image part relationships
|
||||||
|
@ -468,7 +475,7 @@ func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
// file, raw := xlsx.GetPicture("Sheet1", "A2")
|
// file, raw, err := xlsx.GetPicture("Sheet1", "A2")
|
||||||
// if file == "" {
|
// if file == "" {
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
|
@ -477,13 +484,16 @@ func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
func (f *File) GetPicture(sheet, cell string) (string, []byte) {
|
func (f *File) GetPicture(sheet, cell string) (string, []byte, error) {
|
||||||
col, row := MustCellNameToCoordinates(cell)
|
col, row, err := CellNameToCoordinates(cell)
|
||||||
|
if err != nil {
|
||||||
|
return "", []byte{}, err
|
||||||
|
}
|
||||||
col--
|
col--
|
||||||
row--
|
row--
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
if xlsx.Drawing == nil {
|
if xlsx.Drawing == nil {
|
||||||
return "", []byte{}
|
return "", []byte{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
target := f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID)
|
target := f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID)
|
||||||
|
@ -503,7 +513,7 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte) {
|
||||||
if ok {
|
if ok {
|
||||||
return filepath.Base(xlsxWorkbookRelation.Target),
|
return filepath.Base(xlsxWorkbookRelation.Target),
|
||||||
[]byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target,
|
[]byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target,
|
||||||
"..", "xl", -1)])
|
"..", "xl", -1)]), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -511,7 +521,7 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte) {
|
||||||
|
|
||||||
_, ok := f.XLSX[drawingXML]
|
_, ok := f.XLSX[drawingXML]
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", nil
|
return "", nil, err
|
||||||
}
|
}
|
||||||
decodeWsDr := decodeWsDr{}
|
decodeWsDr := decodeWsDr{}
|
||||||
_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr)
|
_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr)
|
||||||
|
@ -523,12 +533,12 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte) {
|
||||||
xlsxWorkbookRelation := f.getDrawingRelationships(drawingRelationships, decodeTwoCellAnchor.Pic.BlipFill.Blip.Embed)
|
xlsxWorkbookRelation := f.getDrawingRelationships(drawingRelationships, decodeTwoCellAnchor.Pic.BlipFill.Blip.Embed)
|
||||||
_, ok := supportImageTypes[filepath.Ext(xlsxWorkbookRelation.Target)]
|
_, ok := supportImageTypes[filepath.Ext(xlsxWorkbookRelation.Target)]
|
||||||
if ok {
|
if ok {
|
||||||
return filepath.Base(xlsxWorkbookRelation.Target), []byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target, "..", "xl", -1)])
|
return filepath.Base(xlsxWorkbookRelation.Target), []byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target, "..", "xl", -1)]), err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", []byte{}
|
return "", []byte{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDrawingRelationships provides a function to get drawing relationships
|
// getDrawingRelationships provides a function to get drawing relationships
|
||||||
|
|
|
@ -4,17 +4,18 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkAddPictureFromBytes(b *testing.B) {
|
func BenchmarkAddPictureFromBytes(b *testing.B) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
imgFile, err := ioutil.ReadFile("logo.png")
|
imgFile, err := ioutil.ReadFile(filepath.Join("test", "images", "excel.png"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("unable to load image for benchmark")
|
b.Error("unable to load image for benchmark")
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 1; i <= b.N; i++ {
|
for i := 1; i <= b.N; i++ {
|
||||||
f.AddPictureFromBytes("Sheet1", fmt.Sprint("A", i), "", "logo", ".png", imgFile)
|
f.AddPictureFromBytes("Sheet1", fmt.Sprint("A", i), "", "excel", ".png", imgFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
157
rows.go
157
rows.go
|
@ -21,17 +21,18 @@ import (
|
||||||
// GetRows return all the rows in a sheet by given worksheet name (case
|
// GetRows return all the rows in a sheet by given worksheet name (case
|
||||||
// sensitive). For example:
|
// sensitive). For example:
|
||||||
//
|
//
|
||||||
// for _, row := range xlsx.GetRows("Sheet1") {
|
// rows, err := xlsx.GetRows("Sheet1")
|
||||||
|
// for _, row := range rows {
|
||||||
// for _, colCell := range row {
|
// for _, colCell := range row {
|
||||||
// fmt.Print(colCell, "\t")
|
// fmt.Print(colCell, "\t")
|
||||||
// }
|
// }
|
||||||
// fmt.Println()
|
// fmt.Println()
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
func (f *File) GetRows(sheet string) [][]string {
|
func (f *File) GetRows(sheet string) ([][]string, error) {
|
||||||
name, ok := f.sheetMap[trimSheetName(sheet)]
|
name, ok := f.sheetMap[trimSheetName(sheet)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
|
@ -47,7 +48,10 @@ func (f *File) GetRows(sheet string) [][]string {
|
||||||
rowData xlsxRow
|
rowData xlsxRow
|
||||||
)
|
)
|
||||||
|
|
||||||
rowCount, colCount := f.getTotalRowsCols(name)
|
rowCount, colCount, err := f.getTotalRowsCols(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
rows := make([][]string, rowCount)
|
rows := make([][]string, rowCount)
|
||||||
for i := range rows {
|
for i := range rows {
|
||||||
rows[i] = make([]string, colCount+1)
|
rows[i] = make([]string, colCount+1)
|
||||||
|
@ -68,7 +72,10 @@ func (f *File) GetRows(sheet string) [][]string {
|
||||||
_ = decoder.DecodeElement(&rowData, &startElement)
|
_ = decoder.DecodeElement(&rowData, &startElement)
|
||||||
cr := rowData.R - 1
|
cr := rowData.R - 1
|
||||||
for _, colCell := range rowData.C {
|
for _, colCell := range rowData.C {
|
||||||
col, _ := MustCellNameToCoordinates(colCell.R)
|
col, _, err := CellNameToCoordinates(colCell.R)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
val, _ := colCell.getValueFrom(f, d)
|
val, _ := colCell.getValueFrom(f, d)
|
||||||
rows[cr][col-1] = val
|
rows[cr][col-1] = val
|
||||||
if val != "" {
|
if val != "" {
|
||||||
|
@ -79,7 +86,7 @@ func (f *File) GetRows(sheet string) [][]string {
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rows[:row]
|
return rows[:row], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rows defines an iterator to a sheet
|
// Rows defines an iterator to a sheet
|
||||||
|
@ -117,9 +124,9 @@ func (rows *Rows) Error() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Columns return the current row's column values
|
// Columns return the current row's column values
|
||||||
func (rows *Rows) Columns() []string {
|
func (rows *Rows) Columns() ([]string, error) {
|
||||||
if rows.token == nil {
|
if rows.token == nil {
|
||||||
return []string{}
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
startElement := rows.token.(xml.StartElement)
|
startElement := rows.token.(xml.StartElement)
|
||||||
r := xlsxRow{}
|
r := xlsxRow{}
|
||||||
|
@ -127,11 +134,14 @@ func (rows *Rows) Columns() []string {
|
||||||
d := rows.f.sharedStringsReader()
|
d := rows.f.sharedStringsReader()
|
||||||
columns := make([]string, len(r.C))
|
columns := make([]string, len(r.C))
|
||||||
for _, colCell := range r.C {
|
for _, colCell := range r.C {
|
||||||
col, _ := MustCellNameToCoordinates(colCell.R)
|
col, _, err := CellNameToCoordinates(colCell.R)
|
||||||
|
if err != nil {
|
||||||
|
return columns, err
|
||||||
|
}
|
||||||
val, _ := colCell.getValueFrom(rows.f, d)
|
val, _ := colCell.getValueFrom(rows.f, d)
|
||||||
columns[col-1] = val
|
columns[col-1] = val
|
||||||
}
|
}
|
||||||
return columns
|
return columns, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrSheetNotExist defines an error of sheet is not exist
|
// ErrSheetNotExist defines an error of sheet is not exist
|
||||||
|
@ -147,7 +157,8 @@ func (err ErrSheetNotExist) Error() string {
|
||||||
//
|
//
|
||||||
// rows, err := xlsx.Rows("Sheet1")
|
// rows, err := xlsx.Rows("Sheet1")
|
||||||
// for rows.Next() {
|
// for rows.Next() {
|
||||||
// for _, colCell := range rows.Columns() {
|
// row, err := rows.Columns()
|
||||||
|
// for _, colCell := range row {
|
||||||
// fmt.Print(colCell, "\t")
|
// fmt.Print(colCell, "\t")
|
||||||
// }
|
// }
|
||||||
// fmt.Println()
|
// fmt.Println()
|
||||||
|
@ -171,7 +182,7 @@ func (f *File) Rows(sheet string) (*Rows, error) {
|
||||||
|
|
||||||
// getTotalRowsCols provides a function to get total columns and rows in a
|
// getTotalRowsCols provides a function to get total columns and rows in a
|
||||||
// worksheet.
|
// worksheet.
|
||||||
func (f *File) getTotalRowsCols(name string) (int, int) {
|
func (f *File) getTotalRowsCols(name string) (int, int, error) {
|
||||||
decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name)))
|
decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name)))
|
||||||
var inElement string
|
var inElement string
|
||||||
var r xlsxRow
|
var r xlsxRow
|
||||||
|
@ -189,7 +200,10 @@ func (f *File) getTotalRowsCols(name string) (int, int) {
|
||||||
_ = decoder.DecodeElement(&r, &startElement)
|
_ = decoder.DecodeElement(&r, &startElement)
|
||||||
tr = r.R
|
tr = r.R
|
||||||
for _, colCell := range r.C {
|
for _, colCell := range r.C {
|
||||||
col, _ := MustCellNameToCoordinates(colCell.R)
|
col, _, err := CellNameToCoordinates(colCell.R)
|
||||||
|
if err != nil {
|
||||||
|
return tr, tc, err
|
||||||
|
}
|
||||||
if col > tc {
|
if col > tc {
|
||||||
tc = col
|
tc = col
|
||||||
}
|
}
|
||||||
|
@ -198,17 +212,17 @@ func (f *File) getTotalRowsCols(name string) (int, int) {
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tr, tc
|
return tr, tc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRowHeight provides a function to set the height of a single row. For
|
// SetRowHeight provides a function to set the height of a single row. For
|
||||||
// example, set the height of the first row in Sheet1:
|
// example, set the height of the first row in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.SetRowHeight("Sheet1", 1, 50)
|
// err := xlsx.SetRowHeight("Sheet1", 1, 50)
|
||||||
//
|
//
|
||||||
func (f *File) SetRowHeight(sheet string, row int, height float64) {
|
func (f *File) SetRowHeight(sheet string, row int, height float64) error {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
|
@ -218,6 +232,7 @@ func (f *File) SetRowHeight(sheet string, row int, height float64) {
|
||||||
rowIdx := row - 1
|
rowIdx := row - 1
|
||||||
xlsx.SheetData.Row[rowIdx].Ht = height
|
xlsx.SheetData.Row[rowIdx].Ht = height
|
||||||
xlsx.SheetData.Row[rowIdx].CustomHeight = true
|
xlsx.SheetData.Row[rowIdx].CustomHeight = true
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRowHeight provides a function to get row height in pixels by given sheet
|
// getRowHeight provides a function to get row height in pixels by given sheet
|
||||||
|
@ -236,24 +251,24 @@ func (f *File) getRowHeight(sheet string, row int) int {
|
||||||
// GetRowHeight provides a function to get row height by given worksheet name
|
// GetRowHeight provides a function to get row height by given worksheet name
|
||||||
// and row index. For example, get the height of the first row in Sheet1:
|
// and row index. For example, get the height of the first row in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.GetRowHeight("Sheet1", 1)
|
// height, err := xlsx.GetRowHeight("Sheet1", 1)
|
||||||
//
|
//
|
||||||
func (f *File) GetRowHeight(sheet string, row int) float64 {
|
func (f *File) GetRowHeight(sheet string, row int) (float64, error) {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return defaultRowHeightPixels, newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
if row > len(xlsx.SheetData.Row) {
|
if row > len(xlsx.SheetData.Row) {
|
||||||
return defaultRowHeightPixels // it will be better to use 0, but we take care with BC
|
return defaultRowHeightPixels, nil // it will be better to use 0, but we take care with BC
|
||||||
}
|
}
|
||||||
for _, v := range xlsx.SheetData.Row {
|
for _, v := range xlsx.SheetData.Row {
|
||||||
if v.R == row && v.Ht != 0 {
|
if v.R == row && v.Ht != 0 {
|
||||||
return v.Ht
|
return v.Ht, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Optimisation for when the row heights haven't changed.
|
// Optimisation for when the row heights haven't changed.
|
||||||
return defaultRowHeightPixels
|
return defaultRowHeightPixels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sharedStringsReader provides a function to get the pointer to the structure
|
// sharedStringsReader provides a function to get the pointer to the structure
|
||||||
|
@ -299,138 +314,140 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
|
||||||
// SetRowVisible provides a function to set visible of a single row by given
|
// SetRowVisible provides a function to set visible of a single row by given
|
||||||
// worksheet name and Excel row number. For example, hide row 2 in Sheet1:
|
// worksheet name and Excel row number. For example, hide row 2 in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.SetRowVisible("Sheet1", 2, false)
|
// err := xlsx.SetRowVisible("Sheet1", 2, false)
|
||||||
//
|
//
|
||||||
func (f *File) SetRowVisible(sheet string, row int, visible bool) {
|
func (f *File) SetRowVisible(sheet string, row int, visible bool) error {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
prepareSheetXML(xlsx, 0, row)
|
prepareSheetXML(xlsx, 0, row)
|
||||||
xlsx.SheetData.Row[row-1].Hidden = !visible
|
xlsx.SheetData.Row[row-1].Hidden = !visible
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRowVisible provides a function to get visible of a single row by given
|
// GetRowVisible provides a function to get visible of a single row by given
|
||||||
// worksheet name and Excel row number. For example, get visible state of row
|
// worksheet name and Excel row number. For example, get visible state of row
|
||||||
// 2 in Sheet1:
|
// 2 in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.GetRowVisible("Sheet1", 2)
|
// visible, err := xlsx.GetRowVisible("Sheet1", 2)
|
||||||
//
|
//
|
||||||
func (f *File) GetRowVisible(sheet string, row int) bool {
|
func (f *File) GetRowVisible(sheet string, row int) (bool, error) {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return false, newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
if row > len(xlsx.SheetData.Row) {
|
if row > len(xlsx.SheetData.Row) {
|
||||||
return false
|
return false, nil
|
||||||
}
|
}
|
||||||
return !xlsx.SheetData.Row[row-1].Hidden
|
return !xlsx.SheetData.Row[row-1].Hidden, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRowOutlineLevel provides a function to set outline level number of a
|
// SetRowOutlineLevel provides a function to set outline level number of a
|
||||||
// single row by given worksheet name and Excel row number. For example,
|
// single row by given worksheet name and Excel row number. For example,
|
||||||
// outline row 2 in Sheet1 to level 1:
|
// outline row 2 in Sheet1 to level 1:
|
||||||
//
|
//
|
||||||
// xlsx.SetRowOutlineLevel("Sheet1", 2, 1)
|
// err := xlsx.SetRowOutlineLevel("Sheet1", 2, 1)
|
||||||
//
|
//
|
||||||
func (f *File) SetRowOutlineLevel(sheet string, row int, level uint8) {
|
func (f *File) SetRowOutlineLevel(sheet string, row int, level uint8) error {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
prepareSheetXML(xlsx, 0, row)
|
prepareSheetXML(xlsx, 0, row)
|
||||||
xlsx.SheetData.Row[row-1].OutlineLevel = level
|
xlsx.SheetData.Row[row-1].OutlineLevel = level
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRowOutlineLevel provides a function to get outline level number of a
|
// GetRowOutlineLevel provides a function to get outline level number of a
|
||||||
// single row by given worksheet name and Excel row number. For example, get
|
// single row by given worksheet name and Excel row number. For example, get
|
||||||
// outline number of row 2 in Sheet1:
|
// outline number of row 2 in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.GetRowOutlineLevel("Sheet1", 2)
|
// level, err := xlsx.GetRowOutlineLevel("Sheet1", 2)
|
||||||
//
|
//
|
||||||
func (f *File) GetRowOutlineLevel(sheet string, row int) uint8 {
|
func (f *File) GetRowOutlineLevel(sheet string, row int) (uint8, error) {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return 0, newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
if row > len(xlsx.SheetData.Row) {
|
if row > len(xlsx.SheetData.Row) {
|
||||||
return 0
|
return 0, nil
|
||||||
}
|
}
|
||||||
return xlsx.SheetData.Row[row-1].OutlineLevel
|
return xlsx.SheetData.Row[row-1].OutlineLevel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveRow provides a function to remove single row by given worksheet name
|
// RemoveRow provides a function to remove single row by given worksheet name
|
||||||
// and Excel row number. For example, remove row 3 in Sheet1:
|
// and Excel row number. For example, remove row 3 in Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.RemoveRow("Sheet1", 3)
|
// err := xlsx.RemoveRow("Sheet1", 3)
|
||||||
//
|
//
|
||||||
// Use this method with caution, which will affect changes in references such
|
// Use this method with caution, which will affect changes in references such
|
||||||
// as formulas, charts, and so on. If there is any referenced value of the
|
// as formulas, charts, and so on. If there is any referenced value of the
|
||||||
// worksheet, it will cause a file error when you open it. The excelize only
|
// worksheet, it will cause a file error when you open it. The excelize only
|
||||||
// partially updates these references currently.
|
// partially updates these references currently.
|
||||||
func (f *File) RemoveRow(sheet string, row int) {
|
func (f *File) RemoveRow(sheet string, row int) error {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
if row > len(xlsx.SheetData.Row) {
|
if row > len(xlsx.SheetData.Row) {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
for rowIdx := range xlsx.SheetData.Row {
|
for rowIdx := range xlsx.SheetData.Row {
|
||||||
if xlsx.SheetData.Row[rowIdx].R == row {
|
if xlsx.SheetData.Row[rowIdx].R == row {
|
||||||
xlsx.SheetData.Row = append(xlsx.SheetData.Row[:rowIdx],
|
xlsx.SheetData.Row = append(xlsx.SheetData.Row[:rowIdx],
|
||||||
xlsx.SheetData.Row[rowIdx+1:]...)[:len(xlsx.SheetData.Row)-1]
|
xlsx.SheetData.Row[rowIdx+1:]...)[:len(xlsx.SheetData.Row)-1]
|
||||||
f.adjustHelper(sheet, rows, row, -1)
|
return f.adjustHelper(sheet, rows, row, -1)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertRow provides a function to insert a new row after given Excel row
|
// InsertRow provides a function to insert a new row after given Excel row
|
||||||
// number starting from 1. For example, create a new row before row 3 in
|
// number starting from 1. For example, create a new row before row 3 in
|
||||||
// Sheet1:
|
// Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.InsertRow("Sheet1", 3)
|
// err := elsx.InsertRow("Sheet1", 3)
|
||||||
//
|
//
|
||||||
func (f *File) InsertRow(sheet string, row int) {
|
func (f *File) InsertRow(sheet string, row int) error {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
f.adjustHelper(sheet, rows, row, 1)
|
return f.adjustHelper(sheet, rows, row, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DuplicateRow inserts a copy of specified row (by it Excel row number) below
|
// DuplicateRow inserts a copy of specified row (by it Excel row number) below
|
||||||
//
|
//
|
||||||
// xlsx.DuplicateRow("Sheet1", 2)
|
// err := xlsx.DuplicateRow("Sheet1", 2)
|
||||||
//
|
//
|
||||||
// Use this method with caution, which will affect changes in references such
|
// Use this method with caution, which will affect changes in references such
|
||||||
// as formulas, charts, and so on. If there is any referenced value of the
|
// as formulas, charts, and so on. If there is any referenced value of the
|
||||||
// worksheet, it will cause a file error when you open it. The excelize only
|
// worksheet, it will cause a file error when you open it. The excelize only
|
||||||
// partially updates these references currently.
|
// partially updates these references currently.
|
||||||
func (f *File) DuplicateRow(sheet string, row int) {
|
func (f *File) DuplicateRow(sheet string, row int) error {
|
||||||
f.DuplicateRowTo(sheet, row, row+1)
|
return f.DuplicateRowTo(sheet, row, row+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DuplicateRowTo inserts a copy of specified row by it Excel number
|
// DuplicateRowTo inserts a copy of specified row by it Excel number
|
||||||
// to specified row position moving down exists rows after target position
|
// to specified row position moving down exists rows after target position
|
||||||
//
|
//
|
||||||
// xlsx.DuplicateRowTo("Sheet1", 2, 7)
|
// err := xlsx.DuplicateRowTo("Sheet1", 2, 7)
|
||||||
//
|
//
|
||||||
// Use this method with caution, which will affect changes in references such
|
// Use this method with caution, which will affect changes in references such
|
||||||
// as formulas, charts, and so on. If there is any referenced value of the
|
// as formulas, charts, and so on. If there is any referenced value of the
|
||||||
// worksheet, it will cause a file error when you open it. The excelize only
|
// worksheet, it will cause a file error when you open it. The excelize only
|
||||||
// partially updates these references currently.
|
// partially updates these references currently.
|
||||||
func (f *File) DuplicateRowTo(sheet string, row, row2 int) {
|
func (f *File) DuplicateRowTo(sheet string, row, row2 int) error {
|
||||||
if row < 1 {
|
if row < 1 {
|
||||||
panic(newInvalidRowNumberError(row)) // Fail fast to avoid possible future side effects!
|
return newInvalidRowNumberError(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
if row > len(xlsx.SheetData.Row) || row2 < 1 || row == row2 {
|
if row > len(xlsx.SheetData.Row) || row2 < 1 || row == row2 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var ok bool
|
var ok bool
|
||||||
|
@ -444,10 +461,12 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f.adjustHelper(sheet, rows, row2, 1)
|
if err := f.adjustHelper(sheet, rows, row2, 1); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
idx2 := -1
|
idx2 := -1
|
||||||
for i, r := range xlsx.SheetData.Row {
|
for i, r := range xlsx.SheetData.Row {
|
||||||
|
@ -457,7 +476,7 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if idx2 == -1 && len(xlsx.SheetData.Row) >= row2 {
|
if idx2 == -1 && len(xlsx.SheetData.Row) >= row2 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rowCopy.C = append(make([]xlsxC, 0, len(rowCopy.C)), rowCopy.C...)
|
rowCopy.C = append(make([]xlsxC, 0, len(rowCopy.C)), rowCopy.C...)
|
||||||
|
@ -468,6 +487,7 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) {
|
||||||
} else {
|
} else {
|
||||||
xlsx.SheetData.Row = append(xlsx.SheetData.Row, rowCopy)
|
xlsx.SheetData.Row = append(xlsx.SheetData.Row, rowCopy)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkRow provides a function to check and fill each column element for all
|
// checkRow provides a function to check and fill each column element for all
|
||||||
|
@ -494,7 +514,7 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) {
|
||||||
//
|
//
|
||||||
// Noteice: this method could be very slow for large spreadsheets (more than
|
// Noteice: this method could be very slow for large spreadsheets (more than
|
||||||
// 3000 rows one sheet).
|
// 3000 rows one sheet).
|
||||||
func checkRow(xlsx *xlsxWorksheet) {
|
func checkRow(xlsx *xlsxWorksheet) error {
|
||||||
for rowIdx := range xlsx.SheetData.Row {
|
for rowIdx := range xlsx.SheetData.Row {
|
||||||
rowData := &xlsx.SheetData.Row[rowIdx]
|
rowData := &xlsx.SheetData.Row[rowIdx]
|
||||||
|
|
||||||
|
@ -502,7 +522,10 @@ func checkRow(xlsx *xlsxWorksheet) {
|
||||||
if colCount == 0 {
|
if colCount == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lastCol, _ := MustCellNameToCoordinates(rowData.C[colCount-1].R)
|
lastCol, _, err := CellNameToCoordinates(rowData.C[colCount-1].R)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if colCount < lastCol {
|
if colCount < lastCol {
|
||||||
oldList := rowData.C
|
oldList := rowData.C
|
||||||
|
@ -511,18 +534,26 @@ func checkRow(xlsx *xlsxWorksheet) {
|
||||||
rowData.C = xlsx.SheetData.Row[rowIdx].C[:0]
|
rowData.C = xlsx.SheetData.Row[rowIdx].C[:0]
|
||||||
|
|
||||||
for colIdx := 0; colIdx < lastCol; colIdx++ {
|
for colIdx := 0; colIdx < lastCol; colIdx++ {
|
||||||
newlist = append(newlist, xlsxC{R: MustCoordinatesToCellName(colIdx+1, rowIdx+1)})
|
cellName, err := CoordinatesToCellName(colIdx+1, rowIdx+1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newlist = append(newlist, xlsxC{R: cellName})
|
||||||
}
|
}
|
||||||
|
|
||||||
rowData.C = newlist
|
rowData.C = newlist
|
||||||
|
|
||||||
for colIdx := range oldList {
|
for colIdx := range oldList {
|
||||||
colData := &oldList[colIdx]
|
colData := &oldList[colIdx]
|
||||||
colNum, _ := MustCellNameToCoordinates(colData.R)
|
colNum, _, err := CellNameToCoordinates(colData.R)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
xlsx.SheetData.Row[rowIdx].C[colNum-1] = *colData
|
xlsx.SheetData.Row[rowIdx].C[colNum-1] = *colData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertRowHeightToPixels provides a function to convert the height of a
|
// convertRowHeightToPixels provides a function to convert the height of a
|
||||||
|
|
173
rows_test.go
173
rows_test.go
|
@ -23,13 +23,16 @@ func TestRows(t *testing.T) {
|
||||||
|
|
||||||
collectedRows := make([][]string, 0)
|
collectedRows := make([][]string, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
collectedRows = append(collectedRows, trimSliceSpace(rows.Columns()))
|
columns, err := rows.Columns()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
collectedRows = append(collectedRows, trimSliceSpace(columns))
|
||||||
}
|
}
|
||||||
if !assert.NoError(t, rows.Error()) {
|
if !assert.NoError(t, rows.Error()) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
returnedRows := xlsx.GetRows(sheet2)
|
returnedRows, err := xlsx.GetRows(sheet2)
|
||||||
|
assert.NoError(t, err)
|
||||||
for i := range returnedRows {
|
for i := range returnedRows {
|
||||||
returnedRows[i] = trimSliceSpace(returnedRows[i])
|
returnedRows[i] = trimSliceSpace(returnedRows[i])
|
||||||
}
|
}
|
||||||
|
@ -54,21 +57,22 @@ func TestRowHeight(t *testing.T) {
|
||||||
xlsx := NewFile()
|
xlsx := NewFile()
|
||||||
sheet1 := xlsx.GetSheetName(1)
|
sheet1 := xlsx.GetSheetName(1)
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetRowHeight(sheet1, 0, defaultRowHeightPixels+1.0), "invalid row number 0")
|
||||||
xlsx.SetRowHeight(sheet1, 0, defaultRowHeightPixels+1.0)
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
height, err := xlsx.GetRowHeight("Sheet1", 0)
|
||||||
xlsx.GetRowHeight("Sheet1", 0)
|
assert.EqualError(t, err, "invalid row number 0")
|
||||||
})
|
|
||||||
|
|
||||||
xlsx.SetRowHeight(sheet1, 1, 111.0)
|
assert.NoError(t, xlsx.SetRowHeight(sheet1, 1, 111.0))
|
||||||
assert.Equal(t, 111.0, xlsx.GetRowHeight(sheet1, 1))
|
height, err = xlsx.GetRowHeight(sheet1, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 111.0, height)
|
||||||
|
|
||||||
xlsx.SetRowHeight(sheet1, 4, 444.0)
|
assert.NoError(t, xlsx.SetRowHeight(sheet1, 4, 444.0))
|
||||||
assert.Equal(t, 444.0, xlsx.GetRowHeight(sheet1, 4))
|
height, err = xlsx.GetRowHeight(sheet1, 4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 444.0, height)
|
||||||
|
|
||||||
err := xlsx.SaveAs(filepath.Join("test", "TestRowHeight.xlsx"))
|
err = xlsx.SaveAs(filepath.Join("test", "TestRowHeight.xlsx"))
|
||||||
if !assert.NoError(t, err) {
|
if !assert.NoError(t, err) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
@ -86,13 +90,11 @@ func TestRowVisibility(t *testing.T) {
|
||||||
xlsx.SetRowVisible("Sheet3", 2, true)
|
xlsx.SetRowVisible("Sheet3", 2, true)
|
||||||
xlsx.GetRowVisible("Sheet3", 2)
|
xlsx.GetRowVisible("Sheet3", 2)
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.SetRowVisible("Sheet3", 0, true), "invalid row number 0")
|
||||||
xlsx.SetRowVisible("Sheet3", 0, true)
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
visible, err := xlsx.GetRowVisible("Sheet3", 0)
|
||||||
xlsx.GetRowVisible("Sheet3", 0)
|
assert.Equal(t, false, visible)
|
||||||
})
|
assert.EqualError(t, err, "invalid row number 0")
|
||||||
|
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestRowVisibility.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestRowVisibility.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -110,27 +112,23 @@ func TestRemoveRow(t *testing.T) {
|
||||||
|
|
||||||
xlsx.SetCellHyperLink(sheet1, "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
|
xlsx.SetCellHyperLink(sheet1, "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.RemoveRow(sheet1, -1), "invalid row number -1")
|
||||||
xlsx.RemoveRow(sheet1, -1)
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.RemoveRow(sheet1, 0), "invalid row number 0")
|
||||||
xlsx.RemoveRow(sheet1, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
xlsx.RemoveRow(sheet1, 4)
|
assert.NoError(t, xlsx.RemoveRow(sheet1, 4))
|
||||||
if !assert.Len(t, r.SheetData.Row, rowCount-1) {
|
if !assert.Len(t, r.SheetData.Row, rowCount-1) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.MergeCell(sheet1, "B3", "B5")
|
xlsx.MergeCell(sheet1, "B3", "B5")
|
||||||
|
|
||||||
xlsx.RemoveRow(sheet1, 2)
|
assert.NoError(t, xlsx.RemoveRow(sheet1, 2))
|
||||||
if !assert.Len(t, r.SheetData.Row, rowCount-2) {
|
if !assert.Len(t, r.SheetData.Row, rowCount-2) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.RemoveRow(sheet1, 4)
|
assert.NoError(t, xlsx.RemoveRow(sheet1, 4))
|
||||||
if !assert.Len(t, r.SheetData.Row, rowCount-3) {
|
if !assert.Len(t, r.SheetData.Row, rowCount-3) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
@ -140,17 +138,17 @@ func TestRemoveRow(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.RemoveRow(sheet1, 1)
|
assert.NoError(t, xlsx.RemoveRow(sheet1, 1))
|
||||||
if !assert.Len(t, r.SheetData.Row, rowCount-4) {
|
if !assert.Len(t, r.SheetData.Row, rowCount-4) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.RemoveRow(sheet1, 2)
|
assert.NoError(t, xlsx.RemoveRow(sheet1, 2))
|
||||||
if !assert.Len(t, r.SheetData.Row, rowCount-5) {
|
if !assert.Len(t, r.SheetData.Row, rowCount-5) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.RemoveRow(sheet1, 1)
|
assert.NoError(t, xlsx.RemoveRow(sheet1, 1))
|
||||||
if !assert.Len(t, r.SheetData.Row, rowCount-6) {
|
if !assert.Len(t, r.SheetData.Row, rowCount-6) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
@ -171,20 +169,16 @@ func TestInsertRow(t *testing.T) {
|
||||||
|
|
||||||
xlsx.SetCellHyperLink(sheet1, "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
|
xlsx.SetCellHyperLink(sheet1, "A5", "https://github.com/360EntSecGroup-Skylar/excelize", "External")
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.InsertRow(sheet1, -1), "invalid row number -1")
|
||||||
xlsx.InsertRow(sheet1, -1)
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.InsertRow(sheet1, 0), "invalid row number 0")
|
||||||
xlsx.InsertRow(sheet1, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
xlsx.InsertRow(sheet1, 1)
|
assert.NoError(t, xlsx.InsertRow(sheet1, 1))
|
||||||
if !assert.Len(t, r.SheetData.Row, rowCount+1) {
|
if !assert.Len(t, r.SheetData.Row, rowCount+1) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.InsertRow(sheet1, 4)
|
assert.NoError(t, xlsx.InsertRow(sheet1, 4))
|
||||||
if !assert.Len(t, r.SheetData.Row, rowCount+2) {
|
if !assert.Len(t, r.SheetData.Row, rowCount+2) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
@ -198,11 +192,11 @@ func TestInsertRowInEmptyFile(t *testing.T) {
|
||||||
xlsx := NewFile()
|
xlsx := NewFile()
|
||||||
sheet1 := xlsx.GetSheetName(1)
|
sheet1 := xlsx.GetSheetName(1)
|
||||||
r := xlsx.workSheetReader(sheet1)
|
r := xlsx.workSheetReader(sheet1)
|
||||||
xlsx.InsertRow(sheet1, 1)
|
assert.NoError(t, xlsx.InsertRow(sheet1, 1))
|
||||||
assert.Len(t, r.SheetData.Row, 0)
|
assert.Len(t, r.SheetData.Row, 0)
|
||||||
xlsx.InsertRow(sheet1, 2)
|
assert.NoError(t, xlsx.InsertRow(sheet1, 2))
|
||||||
assert.Len(t, r.SheetData.Row, 0)
|
assert.Len(t, r.SheetData.Row, 0)
|
||||||
xlsx.InsertRow(sheet1, 99)
|
assert.NoError(t, xlsx.InsertRow(sheet1, 99))
|
||||||
assert.Len(t, r.SheetData.Row, 0)
|
assert.Len(t, r.SheetData.Row, 0)
|
||||||
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertRowInEmptyFile.xlsx")))
|
assert.NoError(t, xlsx.SaveAs(filepath.Join("test", "TestInsertRowInEmptyFile.xlsx")))
|
||||||
}
|
}
|
||||||
|
@ -234,7 +228,7 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
xlsx.SetCellStr(sheet, "A1", cells["A1"])
|
xlsx.SetCellStr(sheet, "A1", cells["A1"])
|
||||||
xlsx.SetCellStr(sheet, "B1", cells["B1"])
|
xlsx.SetCellStr(sheet, "B1", cells["B1"])
|
||||||
|
|
||||||
xlsx.DuplicateRow(sheet, 1)
|
assert.NoError(t, xlsx.DuplicateRow(sheet, 1))
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_1"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_1"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
@ -243,12 +237,14 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A2": cells["A1"], "B2": cells["B1"],
|
"A2": cells["A1"], "B2": cells["B1"],
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xlsx.DuplicateRow(sheet, 2)
|
assert.NoError(t, xlsx.DuplicateRow(sheet, 2))
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_2"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FromSingleRow_2"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
@ -258,7 +254,9 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A3": cells["A1"], "B3": cells["B1"],
|
"A3": cells["A1"], "B3": cells["B1"],
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,7 +267,7 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
xlsx.SetCellStr(sheet, "A1", cells["A1"])
|
xlsx.SetCellStr(sheet, "A1", cells["A1"])
|
||||||
xlsx.SetCellStr(sheet, "B1", cells["B1"])
|
xlsx.SetCellStr(sheet, "B1", cells["B1"])
|
||||||
|
|
||||||
xlsx.DuplicateRow(sheet, 1)
|
assert.NoError(t, xlsx.DuplicateRow(sheet, 1))
|
||||||
|
|
||||||
xlsx.SetCellStr(sheet, "A2", cells["A2"])
|
xlsx.SetCellStr(sheet, "A2", cells["A2"])
|
||||||
xlsx.SetCellStr(sheet, "B2", cells["B2"])
|
xlsx.SetCellStr(sheet, "B2", cells["B2"])
|
||||||
|
@ -282,7 +280,9 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A2": cells["A2"], "B2": cells["B2"],
|
"A2": cells["A2"], "B2": cells["B2"],
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,7 +291,7 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
t.Run("FirstOfMultipleRows", func(t *testing.T) {
|
t.Run("FirstOfMultipleRows", func(t *testing.T) {
|
||||||
xlsx := newFileWithDefaults()
|
xlsx := newFileWithDefaults()
|
||||||
|
|
||||||
xlsx.DuplicateRow(sheet, 1)
|
assert.NoError(t, xlsx.DuplicateRow(sheet, 1))
|
||||||
|
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FirstOfMultipleRows"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.FirstOfMultipleRows"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
@ -303,7 +303,9 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A4": cells["A3"], "B4": cells["B3"],
|
"A4": cells["A3"], "B4": cells["B3"],
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,26 +314,35 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
t.Run("ZeroWithNoRows", func(t *testing.T) {
|
t.Run("ZeroWithNoRows", func(t *testing.T) {
|
||||||
xlsx := NewFile()
|
xlsx := NewFile()
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.DuplicateRow(sheet, 0), "invalid row number 0")
|
||||||
xlsx.DuplicateRow(sheet, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.ZeroWithNoRows"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.ZeroWithNoRows"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, "", xlsx.GetCellValue(sheet, "A1"))
|
val, err := xlsx.GetCellValue(sheet, "A1")
|
||||||
assert.Equal(t, "", xlsx.GetCellValue(sheet, "B1"))
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "", xlsx.GetCellValue(sheet, "A2"))
|
assert.Equal(t, "", val)
|
||||||
assert.Equal(t, "", xlsx.GetCellValue(sheet, "B2"))
|
val, err = xlsx.GetCellValue(sheet, "B1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "", val)
|
||||||
|
val, err = xlsx.GetCellValue(sheet, "A2")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "", val)
|
||||||
|
val, err = xlsx.GetCellValue(sheet, "B2")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "", val)
|
||||||
|
|
||||||
|
assert.NoError(t, err)
|
||||||
expect := map[string]string{
|
expect := map[string]string{
|
||||||
"A1": "", "B1": "",
|
"A1": "", "B1": "",
|
||||||
"A2": "", "B2": "",
|
"A2": "", "B2": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +351,7 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
t.Run("MiddleRowOfEmptyFile", func(t *testing.T) {
|
t.Run("MiddleRowOfEmptyFile", func(t *testing.T) {
|
||||||
xlsx := NewFile()
|
xlsx := NewFile()
|
||||||
|
|
||||||
xlsx.DuplicateRow(sheet, 99)
|
assert.NoError(t, xlsx.DuplicateRow(sheet, 99))
|
||||||
|
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.MiddleRowOfEmptyFile"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.MiddleRowOfEmptyFile"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
@ -351,7 +362,9 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A100": "",
|
"A100": "",
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,7 +373,7 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
t.Run("WithLargeOffsetToMiddleOfData", func(t *testing.T) {
|
t.Run("WithLargeOffsetToMiddleOfData", func(t *testing.T) {
|
||||||
xlsx := newFileWithDefaults()
|
xlsx := newFileWithDefaults()
|
||||||
|
|
||||||
xlsx.DuplicateRowTo(sheet, 1, 3)
|
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 1, 3))
|
||||||
|
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToMiddleOfData"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToMiddleOfData"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
@ -372,7 +385,9 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A4": cells["A3"], "B4": cells["B3"],
|
"A4": cells["A3"], "B4": cells["B3"],
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,7 +396,7 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
t.Run("WithLargeOffsetToEmptyRows", func(t *testing.T) {
|
t.Run("WithLargeOffsetToEmptyRows", func(t *testing.T) {
|
||||||
xlsx := newFileWithDefaults()
|
xlsx := newFileWithDefaults()
|
||||||
|
|
||||||
xlsx.DuplicateRowTo(sheet, 1, 7)
|
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 1, 7))
|
||||||
|
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToEmptyRows"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.WithLargeOffsetToEmptyRows"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
@ -393,7 +408,9 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A7": cells["A1"], "B7": cells["B1"],
|
"A7": cells["A1"], "B7": cells["B1"],
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,7 +419,7 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
t.Run("InsertBefore", func(t *testing.T) {
|
t.Run("InsertBefore", func(t *testing.T) {
|
||||||
xlsx := newFileWithDefaults()
|
xlsx := newFileWithDefaults()
|
||||||
|
|
||||||
xlsx.DuplicateRowTo(sheet, 2, 1)
|
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 2, 1))
|
||||||
|
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBefore"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBefore"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
@ -415,7 +432,9 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A4": cells["A3"], "B4": cells["B3"],
|
"A4": cells["A3"], "B4": cells["B3"],
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell), cell) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v, cell) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -424,7 +443,7 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
t.Run("InsertBeforeWithLargeOffset", func(t *testing.T) {
|
t.Run("InsertBeforeWithLargeOffset", func(t *testing.T) {
|
||||||
xlsx := newFileWithDefaults()
|
xlsx := newFileWithDefaults()
|
||||||
|
|
||||||
xlsx.DuplicateRowTo(sheet, 3, 1)
|
assert.NoError(t, xlsx.DuplicateRowTo(sheet, 3, 1))
|
||||||
|
|
||||||
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBeforeWithLargeOffset"))) {
|
if !assert.NoError(t, xlsx.SaveAs(fmt.Sprintf(outFile, "TestDuplicateRow.InsertBeforeWithLargeOffset"))) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
@ -437,7 +456,9 @@ func TestDuplicateRow(t *testing.T) {
|
||||||
"A4": cells["A3"], "B4": cells["B3"],
|
"A4": cells["A3"], "B4": cells["B3"],
|
||||||
}
|
}
|
||||||
for cell, val := range expect {
|
for cell, val := range expect {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, cell)) {
|
v, err := xlsx.GetCellValue(sheet, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,12 +488,12 @@ func TestDuplicateRowInvalidRownum(t *testing.T) {
|
||||||
xlsx.SetCellStr(sheet, col, val)
|
xlsx.SetCellStr(sheet, col, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.DuplicateRow(sheet, row), fmt.Sprintf("invalid row number %d", row))
|
||||||
xlsx.DuplicateRow(sheet, row)
|
|
||||||
})
|
|
||||||
|
|
||||||
for col, val := range cells {
|
for col, val := range cells {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, col)) {
|
v, err := xlsx.GetCellValue(sheet, col)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -489,12 +510,12 @@ func TestDuplicateRowInvalidRownum(t *testing.T) {
|
||||||
xlsx.SetCellStr(sheet, col, val)
|
xlsx.SetCellStr(sheet, col, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Panics(t, func() {
|
assert.EqualError(t, xlsx.DuplicateRowTo(sheet, row1, row2), fmt.Sprintf("invalid row number %d", row1))
|
||||||
xlsx.DuplicateRowTo(sheet, row1, row2)
|
|
||||||
})
|
|
||||||
|
|
||||||
for col, val := range cells {
|
for col, val := range cells {
|
||||||
if !assert.Equal(t, val, xlsx.GetCellValue(sheet, col)) {
|
v, err := xlsx.GetCellValue(sheet, col)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if !assert.Equal(t, val, v) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
shape.go
13
shape.go
|
@ -275,15 +275,21 @@ func (f *File) AddShape(sheet, cell, format string) error {
|
||||||
rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
|
rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
|
||||||
f.addSheetDrawing(sheet, rID)
|
f.addSheetDrawing(sheet, rID)
|
||||||
}
|
}
|
||||||
f.addDrawingShape(sheet, drawingXML, cell, formatSet)
|
err = f.addDrawingShape(sheet, drawingXML, cell, formatSet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
f.addContentTypePart(drawingID, "drawings")
|
f.addContentTypePart(drawingID, "drawings")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// addDrawingShape provides a function to add preset geometry by given sheet,
|
// addDrawingShape provides a function to add preset geometry by given sheet,
|
||||||
// drawingXMLand format sets.
|
// drawingXMLand format sets.
|
||||||
func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *formatShape) {
|
func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *formatShape) error {
|
||||||
fromCol, fromRow := MustCellNameToCoordinates(cell)
|
fromCol, fromRow, err := CellNameToCoordinates(cell)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
colIdx := fromCol - 1
|
colIdx := fromCol - 1
|
||||||
rowIdx := fromRow - 1
|
rowIdx := fromRow - 1
|
||||||
|
|
||||||
|
@ -421,6 +427,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format
|
||||||
}
|
}
|
||||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
||||||
f.Drawings[drawingXML] = content
|
f.Drawings[drawingXML] = content
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// setShapeRef provides a function to set color with hex model by given actual
|
// setShapeRef provides a function to set color with hex model by given actual
|
||||||
|
|
31
sheet.go
31
sheet.go
|
@ -275,11 +275,11 @@ func (f *File) GetActiveSheetIndex() int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSheetName provides a function to set the worksheet name be given old and new
|
// SetSheetName provides a function to set the worksheet name be given old and
|
||||||
// worksheet name. Maximum 31 characters are allowed in sheet title and this
|
// new worksheet name. Maximum 31 characters are allowed in sheet title and
|
||||||
// function only changes the name of the sheet and will not update the sheet
|
// this function only changes the name of the sheet and will not update the
|
||||||
// name in the formula or reference associated with the cell. So there may be
|
// sheet name in the formula or reference associated with the cell. So there
|
||||||
// problem formula error or reference missing.
|
// may be problem formula error or reference missing.
|
||||||
func (f *File) SetSheetName(oldName, newName string) {
|
func (f *File) SetSheetName(oldName, newName string) {
|
||||||
oldName = trimSheetName(oldName)
|
oldName = trimSheetName(oldName)
|
||||||
newName = trimSheetName(newName)
|
newName = trimSheetName(newName)
|
||||||
|
@ -665,14 +665,14 @@ func (f *File) GetSheetVisible(name string) bool {
|
||||||
//
|
//
|
||||||
// An example of search the coordinates of the value of "100" on Sheet1:
|
// An example of search the coordinates of the value of "100" on Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.SearchSheet("Sheet1", "100")
|
// result, err := xlsx.SearchSheet("Sheet1", "100")
|
||||||
//
|
//
|
||||||
// An example of search the coordinates where the numerical value in the range
|
// An example of search the coordinates where the numerical value in the range
|
||||||
// of "0-9" of Sheet1 is described:
|
// of "0-9" of Sheet1 is described:
|
||||||
//
|
//
|
||||||
// xlsx.SearchSheet("Sheet1", "[0-9]", true)
|
// result, err := xlsx.SearchSheet("Sheet1", "[0-9]", true)
|
||||||
//
|
//
|
||||||
func (f *File) SearchSheet(sheet, value string, reg ...bool) []string {
|
func (f *File) SearchSheet(sheet, value string, reg ...bool) ([]string, error) {
|
||||||
var regSearch bool
|
var regSearch bool
|
||||||
for _, r := range reg {
|
for _, r := range reg {
|
||||||
regSearch = r
|
regSearch = r
|
||||||
|
@ -683,7 +683,7 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) []string {
|
||||||
)
|
)
|
||||||
name, ok := f.sheetMap[trimSheetName(sheet)]
|
name, ok := f.sheetMap[trimSheetName(sheet)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
if xlsx != nil {
|
if xlsx != nil {
|
||||||
output, _ := xml.Marshal(f.Sheet[name])
|
output, _ := xml.Marshal(f.Sheet[name])
|
||||||
|
@ -718,14 +718,21 @@ func (f *File) SearchSheet(sheet, value string, reg ...bool) []string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cellCol, _ := MustCellNameToCoordinates(colCell.R)
|
cellCol, _, err := CellNameToCoordinates(colCell.R)
|
||||||
result = append(result, MustCoordinatesToCellName(cellCol, r.R))
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
cellName, err := CoordinatesToCellName(cellCol, r.R)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
result = append(result, cellName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtectSheet provides a function to prevent other users from accidentally
|
// ProtectSheet provides a function to prevent other users from accidentally
|
||||||
|
|
34
styles.go
34
styles.go
|
@ -1880,8 +1880,8 @@ func parseFormatStyleSet(style string) (*formatStyle, error) {
|
||||||
//
|
//
|
||||||
// xlsx := excelize.NewFile()
|
// xlsx := excelize.NewFile()
|
||||||
// xlsx.SetCellValue("Sheet1", "A6", 42920.5)
|
// xlsx.SetCellValue("Sheet1", "A6", 42920.5)
|
||||||
// style, _ := xlsx.NewStyle(`{"custom_number_format": "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yyyy;@"}`)
|
// style, err := xlsx.NewStyle(`{"custom_number_format": "[$-380A]dddd\\,\\ dd\" de \"mmmm\" de \"yyyy;@"}`)
|
||||||
// xlsx.SetCellStyle("Sheet1", "A6", "A6", style)
|
// err = xlsx.SetCellStyle("Sheet1", "A6", "A6", style)
|
||||||
//
|
//
|
||||||
// Cell Sheet1!A6 in the Excel Application: martes, 04 de Julio de 2017
|
// Cell Sheet1!A6 in the Excel Application: martes, 04 de Julio de 2017
|
||||||
//
|
//
|
||||||
|
@ -2265,10 +2265,13 @@ func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, a
|
||||||
|
|
||||||
// GetCellStyle provides a function to get cell style index by given worksheet
|
// GetCellStyle provides a function to get cell style index by given worksheet
|
||||||
// name and cell coordinates.
|
// name and cell coordinates.
|
||||||
func (f *File) GetCellStyle(sheet, axis string) int {
|
func (f *File) GetCellStyle(sheet, axis string) (int, error) {
|
||||||
xlsx := f.workSheetReader(sheet)
|
xlsx := f.workSheetReader(sheet)
|
||||||
cellData, col, _ := f.prepareCell(xlsx, sheet, axis)
|
cellData, col, _, err := f.prepareCell(xlsx, sheet, axis)
|
||||||
return f.prepareCellStyle(xlsx, col, cellData.S)
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return f.prepareCellStyle(xlsx, col, cellData.S), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCellStyle provides a function to add style attribute for cells by given
|
// SetCellStyle provides a function to add style attribute for cells by given
|
||||||
|
@ -2282,7 +2285,7 @@ func (f *File) GetCellStyle(sheet, axis string) int {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
// xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
// err = xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
||||||
//
|
//
|
||||||
// Set gradient fill with vertical variants shading styles for cell H9 on
|
// Set gradient fill with vertical variants shading styles for cell H9 on
|
||||||
// Sheet1:
|
// Sheet1:
|
||||||
|
@ -2291,7 +2294,7 @@ func (f *File) GetCellStyle(sheet, axis string) int {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
// xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
// err = xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
||||||
//
|
//
|
||||||
// Set solid style pattern fill for cell H9 on Sheet1:
|
// Set solid style pattern fill for cell H9 on Sheet1:
|
||||||
//
|
//
|
||||||
|
@ -2299,7 +2302,7 @@ func (f *File) GetCellStyle(sheet, axis string) int {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
// xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
// err = xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
||||||
//
|
//
|
||||||
// Set alignment style for cell H9 on Sheet1:
|
// Set alignment style for cell H9 on Sheet1:
|
||||||
//
|
//
|
||||||
|
@ -2307,7 +2310,7 @@ func (f *File) GetCellStyle(sheet, axis string) int {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
// xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
// err = xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
||||||
//
|
//
|
||||||
// Dates and times in Excel are represented by real numbers, for example "Apr 7
|
// Dates and times in Excel are represented by real numbers, for example "Apr 7
|
||||||
// 2017 12:00 PM" is represented by the number 42920.5. Set date and time format
|
// 2017 12:00 PM" is represented by the number 42920.5. Set date and time format
|
||||||
|
@ -2318,7 +2321,7 @@ func (f *File) GetCellStyle(sheet, axis string) int {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
// xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
// err = xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
||||||
//
|
//
|
||||||
// Set font style for cell H9 on Sheet1:
|
// Set font style for cell H9 on Sheet1:
|
||||||
//
|
//
|
||||||
|
@ -2326,7 +2329,7 @@ func (f *File) GetCellStyle(sheet, axis string) int {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
// xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
// err = xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
||||||
//
|
//
|
||||||
// Hide and lock for cell H9 on Sheet1:
|
// Hide and lock for cell H9 on Sheet1:
|
||||||
//
|
//
|
||||||
|
@ -2334,17 +2337,17 @@ func (f *File) GetCellStyle(sheet, axis string) int {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
// xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
// err = xlsx.SetCellStyle("Sheet1", "H9", "H9", style)
|
||||||
//
|
//
|
||||||
func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) {
|
func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) error {
|
||||||
hcol, hrow, err := CellNameToCoordinates(hcell)
|
hcol, hrow, err := CellNameToCoordinates(hcell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
vcol, vrow, err := CellNameToCoordinates(vcell)
|
vcol, vrow, err := CellNameToCoordinates(vcell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize the coordinate area, such correct C1:B3 to B1:C3.
|
// Normalize the coordinate area, such correct C1:B3 to B1:C3.
|
||||||
|
@ -2370,6 +2373,7 @@ func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) {
|
||||||
xlsx.SheetData.Row[r].C[k].S = styleID
|
xlsx.SheetData.Row[r].C[k].S = styleID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConditionalFormat provides a function to create conditional formatting
|
// SetConditionalFormat provides a function to create conditional formatting
|
||||||
|
|
70
table.go
70
table.go
|
@ -33,11 +33,11 @@ func parseFormatTableSet(formatSet string) (*formatTable, error) {
|
||||||
// name, coordinate area and format set. For example, create a table of A1:D5
|
// name, coordinate area and format set. For example, create a table of A1:D5
|
||||||
// on Sheet1:
|
// on Sheet1:
|
||||||
//
|
//
|
||||||
// xlsx.AddTable("Sheet1", "A1", "D5", ``)
|
// err := xlsx.AddTable("Sheet1", "A1", "D5", ``)
|
||||||
//
|
//
|
||||||
// Create a table of F2:H6 on Sheet2 with format set:
|
// Create a table of F2:H6 on Sheet2 with format set:
|
||||||
//
|
//
|
||||||
// xlsx.AddTable("Sheet2", "F2", "H6", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
|
// err := xlsx.AddTable("Sheet2", "F2", "H6", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
|
||||||
//
|
//
|
||||||
// Note that the table at least two lines include string type header. Multiple
|
// Note that the table at least two lines include string type header. Multiple
|
||||||
// tables coordinate areas can't have an intersection.
|
// tables coordinate areas can't have an intersection.
|
||||||
|
@ -56,8 +56,14 @@ func (f *File) AddTable(sheet, hcell, vcell, format string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Coordinate conversion, convert C1:B3 to 2,0,1,2.
|
// Coordinate conversion, convert C1:B3 to 2,0,1,2.
|
||||||
hcol, hrow := MustCellNameToCoordinates(hcell)
|
hcol, hrow, err := CellNameToCoordinates(hcell)
|
||||||
vcol, vrow := MustCellNameToCoordinates(vcell)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vcol, vrow, err := CellNameToCoordinates(vcell)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if vcol < hcol {
|
if vcol < hcol {
|
||||||
vcol, hcol = hcol, vcol
|
vcol, hcol = hcol, vcol
|
||||||
|
@ -73,7 +79,10 @@ func (f *File) AddTable(sheet, hcell, vcell, format string) error {
|
||||||
// Add first table for given sheet.
|
// Add first table for given sheet.
|
||||||
rID := f.addSheetRelationships(sheet, SourceRelationshipTable, sheetRelationshipsTableXML, "")
|
rID := f.addSheetRelationships(sheet, SourceRelationshipTable, sheetRelationshipsTableXML, "")
|
||||||
f.addSheetTable(sheet, rID)
|
f.addSheetTable(sheet, rID)
|
||||||
f.addTable(sheet, tableXML, hcol, hrow, vcol, vrow, tableID, formatSet)
|
err = f.addTable(sheet, tableXML, hcol, hrow, vcol, vrow, tableID, formatSet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
f.addContentTypePart(tableID, "table")
|
f.addContentTypePart(tableID, "table")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -106,24 +115,33 @@ func (f *File) addSheetTable(sheet string, rID int) {
|
||||||
|
|
||||||
// addTable provides a function to add table by given worksheet name,
|
// addTable provides a function to add table by given worksheet name,
|
||||||
// coordinate area and format set.
|
// coordinate area and format set.
|
||||||
func (f *File) addTable(sheet, tableXML string, hcol, hrow, vcol, vrow, i int, formatSet *formatTable) {
|
func (f *File) addTable(sheet, tableXML string, hcol, hrow, vcol, vrow, i int, formatSet *formatTable) error {
|
||||||
// Correct the minimum number of rows, the table at least two lines.
|
// Correct the minimum number of rows, the table at least two lines.
|
||||||
if hrow == vrow {
|
if hrow == vrow {
|
||||||
vrow++
|
vrow++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Correct table reference coordinate area, such correct C1:B3 to B1:C3.
|
// Correct table reference coordinate area, such correct C1:B3 to B1:C3.
|
||||||
ref := MustCoordinatesToCellName(hcol, hrow) + ":" + MustCoordinatesToCellName(vcol, vrow)
|
hcell, err := CoordinatesToCellName(hcol, hrow)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vcell, err := CoordinatesToCellName(vcol, vrow)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ref := hcell + ":" + vcell
|
||||||
|
|
||||||
var (
|
var tableColumn []*xlsxTableColumn
|
||||||
tableColumn []*xlsxTableColumn
|
|
||||||
)
|
|
||||||
|
|
||||||
idx := 0
|
idx := 0
|
||||||
for i := hcol; i <= vcol; i++ {
|
for i := hcol; i <= vcol; i++ {
|
||||||
idx++
|
idx++
|
||||||
cell := MustCoordinatesToCellName(i, hrow)
|
cell, err := CoordinatesToCellName(i, hrow)
|
||||||
name := f.GetCellValue(sheet, cell)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
name, _ := f.GetCellValue(sheet, cell)
|
||||||
if _, err := strconv.Atoi(name); err == nil {
|
if _, err := strconv.Atoi(name); err == nil {
|
||||||
f.SetCellStr(sheet, cell, name)
|
f.SetCellStr(sheet, cell, name)
|
||||||
}
|
}
|
||||||
|
@ -163,6 +181,7 @@ func (f *File) addTable(sheet, tableXML string, hcol, hrow, vcol, vrow, i int, f
|
||||||
}
|
}
|
||||||
table, _ := xml.Marshal(t)
|
table, _ := xml.Marshal(t)
|
||||||
f.saveFileList(tableXML, table)
|
f.saveFileList(tableXML, table)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseAutoFilterSet provides a function to parse the settings of the auto
|
// parseAutoFilterSet provides a function to parse the settings of the auto
|
||||||
|
@ -244,8 +263,14 @@ func parseAutoFilterSet(formatSet string) (*formatAutoFilter, error) {
|
||||||
// Price < 2000
|
// Price < 2000
|
||||||
//
|
//
|
||||||
func (f *File) AutoFilter(sheet, hcell, vcell, format string) error {
|
func (f *File) AutoFilter(sheet, hcell, vcell, format string) error {
|
||||||
hcol, hrow := MustCellNameToCoordinates(hcell)
|
hcol, hrow, err := CellNameToCoordinates(hcell)
|
||||||
vcol, vrow := MustCellNameToCoordinates(vcell)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vcol, vrow, err := CellNameToCoordinates(vcell)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if vcol < hcol {
|
if vcol < hcol {
|
||||||
vcol, hcol = hcol, vcol
|
vcol, hcol = hcol, vcol
|
||||||
|
@ -256,7 +281,17 @@ func (f *File) AutoFilter(sheet, hcell, vcell, format string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
formatSet, _ := parseAutoFilterSet(format)
|
formatSet, _ := parseAutoFilterSet(format)
|
||||||
ref := MustCoordinatesToCellName(hcol, hrow) + ":" + MustCoordinatesToCellName(vcol, vrow)
|
|
||||||
|
var cellStart, cellEnd string
|
||||||
|
cellStart, err = CoordinatesToCellName(hcol, hrow)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cellEnd, err = CoordinatesToCellName(vcol, vrow)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ref := cellStart + ":" + cellEnd
|
||||||
refRange := vcol - hcol
|
refRange := vcol - hcol
|
||||||
return f.autoFilter(sheet, ref, refRange, hcol, formatSet)
|
return f.autoFilter(sheet, ref, refRange, hcol, formatSet)
|
||||||
}
|
}
|
||||||
|
@ -277,7 +312,10 @@ func (f *File) autoFilter(sheet, ref string, refRange, col int, formatSet *forma
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fsCol := MustColumnNameToNumber(formatSet.Column)
|
fsCol, err := ColumnNameToNumber(formatSet.Column)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
offset := fsCol - col
|
offset := fsCol - col
|
||||||
if offset < 0 || offset > refRange {
|
if offset < 0 || offset > refRange {
|
||||||
return fmt.Errorf("incorrect index of column '%s'", formatSet.Column)
|
return fmt.Errorf("incorrect index of column '%s'", formatSet.Column)
|
||||||
|
|
Loading…
Reference in New Issue