forked from p30928647/excelize
- Readme and go test updated
This commit is contained in:
parent
3b2c80ddc3
commit
6aa59a1af2
|
@ -2,8 +2,8 @@
|
|||
|
||||
# Excelize
|
||||
|
||||
[![Build Status](https://travis-ci.org/xuri/excelize.svg?branch=master)](https://travis-ci.org/xuri/excelize)
|
||||
[![Code Coverage](https://codecov.io/gh/xuri/excelize/branch/master/graph/badge.svg)](https://codecov.io/gh/xuri/excelize)
|
||||
[![Build Status](https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master)](https://travis-ci.org/360EntSecGroup-Skylar/excelize)
|
||||
[![Code Coverage](https://codecov.io/gh/360EntSecGroup-Skylar/excelize/branch/master/graph/badge.svg)](https://codecov.io/gh/360EntSecGroup-Skylar/excelize)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/xuri/excelize)](https://goreportcard.com/report/github.com/xuri/excelize)
|
||||
[![GoDoc](https://godoc.org/github.com/xuri/excelize?status.svg)](https://godoc.org/github.com/xuri/excelize)
|
||||
[![Licenses](https://img.shields.io/badge/license-bsd-orange.svg)](https://opensource.org/licenses/BSD-3-Clause)
|
||||
|
|
157
cell.go
157
cell.go
|
@ -1,8 +1,11 @@
|
|||
package excelize
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// mergeCellsParser provides function to check merged cells in worksheet by
|
||||
|
@ -19,6 +22,53 @@ func (f *File) mergeCellsParser(xlsx *xlsxWorksheet, axis string) string {
|
|||
return axis
|
||||
}
|
||||
|
||||
// SetCellValue provides function to set value of a cell. The following shows
|
||||
// the supported data types:
|
||||
//
|
||||
// int
|
||||
// int8
|
||||
// int16
|
||||
// int32
|
||||
// int64
|
||||
// float32
|
||||
// float64
|
||||
// string
|
||||
// []byte
|
||||
// time.Time
|
||||
// nil
|
||||
//
|
||||
// Note that default date format is m/d/yy h:mm of time.Time type value. You can
|
||||
// set numbers format by SetCellStyle() method.
|
||||
func (f *File) SetCellValue(sheet, axis string, value interface{}) {
|
||||
switch t := value.(type) {
|
||||
case int:
|
||||
f.SetCellInt(sheet, axis, value.(int))
|
||||
case int8:
|
||||
f.SetCellInt(sheet, axis, int(value.(int8)))
|
||||
case int16:
|
||||
f.SetCellInt(sheet, axis, int(value.(int16)))
|
||||
case int32:
|
||||
f.SetCellInt(sheet, axis, int(value.(int32)))
|
||||
case int64:
|
||||
f.SetCellInt(sheet, axis, int(value.(int64)))
|
||||
case float32:
|
||||
f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(float32)), 'f', -1, 32))
|
||||
case float64:
|
||||
f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(float64)), 'f', -1, 64))
|
||||
case string:
|
||||
f.SetCellStr(sheet, axis, t)
|
||||
case []byte:
|
||||
f.SetCellStr(sheet, axis, string(t))
|
||||
case time.Time:
|
||||
f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(timeToExcelTime(timeToUTCTime(value.(time.Time)))), 'f', -1, 32))
|
||||
f.setDefaultTimeStyle(sheet, axis)
|
||||
case nil:
|
||||
f.SetCellStr(sheet, axis, "")
|
||||
default:
|
||||
f.SetCellStr(sheet, axis, fmt.Sprintf("%v", value))
|
||||
}
|
||||
}
|
||||
|
||||
// GetCellValue provides function to get formatted value from cell by given
|
||||
// sheet index 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, along with
|
||||
|
@ -77,6 +127,25 @@ func (f *File) formattedValue(s int, v string) string {
|
|||
return v
|
||||
}
|
||||
|
||||
// GetCellStyle provides function to get cell style index by given worksheet
|
||||
// name and cell coordinates.
|
||||
func (f *File) GetCellStyle(sheet, axis string) int {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
axis = f.mergeCellsParser(xlsx, axis)
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row - 1
|
||||
yAxis := TitleToNumber(col)
|
||||
|
||||
rows := xAxis + 1
|
||||
cell := yAxis + 1
|
||||
|
||||
completeRow(xlsx, rows, cell)
|
||||
completeCol(xlsx, rows, cell)
|
||||
|
||||
return f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
|
||||
}
|
||||
|
||||
// GetCellFormula provides function to get formula from cell by given sheet
|
||||
// index and axis in XLSX file.
|
||||
func (f *File) GetCellFormula(sheet, axis string) string {
|
||||
|
@ -215,6 +284,94 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
|
|||
}
|
||||
}
|
||||
|
||||
// SetCellInt provides function to set int type value of a cell by given
|
||||
// worksheet name, cell coordinates and cell value.
|
||||
func (f *File) SetCellInt(sheet, axis string, value int) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
axis = f.mergeCellsParser(xlsx, axis)
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row - 1
|
||||
yAxis := TitleToNumber(col)
|
||||
|
||||
rows := xAxis + 1
|
||||
cell := yAxis + 1
|
||||
|
||||
completeRow(xlsx, rows, cell)
|
||||
completeCol(xlsx, rows, cell)
|
||||
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].V = strconv.Itoa(value)
|
||||
}
|
||||
|
||||
// prepareCellStyle provides function to prepare style index of cell in
|
||||
// worksheet by given column index and style index.
|
||||
func (f *File) prepareCellStyle(xlsx *xlsxWorksheet, col, style int) int {
|
||||
if xlsx.Cols != nil && style == 0 {
|
||||
for _, v := range xlsx.Cols.Col {
|
||||
if v.Min <= col && col <= v.Max {
|
||||
style = v.Style
|
||||
}
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
// SetCellStr provides function to set string type value of a cell. Total number
|
||||
// of characters that a cell can contain 32767 characters.
|
||||
func (f *File) SetCellStr(sheet, axis, value string) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
axis = f.mergeCellsParser(xlsx, axis)
|
||||
if len(value) > 32767 {
|
||||
value = value[0:32767]
|
||||
}
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row - 1
|
||||
yAxis := TitleToNumber(col)
|
||||
|
||||
rows := xAxis + 1
|
||||
cell := yAxis + 1
|
||||
|
||||
completeRow(xlsx, rows, cell)
|
||||
completeCol(xlsx, rows, cell)
|
||||
|
||||
// Leading space(s) character detection.
|
||||
if len(value) > 0 {
|
||||
if value[0] == 32 {
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].XMLSpace = xml.Attr{
|
||||
Name: xml.Name{Space: NameSpaceXML, Local: "space"},
|
||||
Value: "preserve",
|
||||
}
|
||||
}
|
||||
}
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].T = "str"
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].V = value
|
||||
}
|
||||
|
||||
// SetCellDefault provides function to set string type value of a cell as
|
||||
// default format without escaping the cell.
|
||||
func (f *File) SetCellDefault(sheet, axis, value string) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
axis = f.mergeCellsParser(xlsx, axis)
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row - 1
|
||||
yAxis := TitleToNumber(col)
|
||||
|
||||
rows := xAxis + 1
|
||||
cell := yAxis + 1
|
||||
|
||||
completeRow(xlsx, rows, cell)
|
||||
completeCol(xlsx, rows, cell)
|
||||
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].V = value
|
||||
}
|
||||
|
||||
// checkCellInArea provides function to determine if a given coordinate is
|
||||
// within an area.
|
||||
func checkCellInArea(cell, area string) bool {
|
||||
|
|
69
col.go
69
col.go
|
@ -1,7 +1,9 @@
|
|||
package excelize
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -243,6 +245,61 @@ func (f *File) GetColWidth(sheet, column string) float64 {
|
|||
return defaultColWidthPixels
|
||||
}
|
||||
|
||||
// InsertCol provides function to insert a new column before given column index.
|
||||
// For example, create a new column before column C in Sheet1:
|
||||
//
|
||||
// xlsx.InsertCol("Sheet1", "C")
|
||||
//
|
||||
func (f *File) InsertCol(sheet, column string) {
|
||||
col := TitleToNumber(strings.ToUpper(column))
|
||||
f.adjustHelper(sheet, col, -1, 1)
|
||||
}
|
||||
|
||||
// RemoveCol provides function to remove single column by given worksheet index
|
||||
// and column index. For example, remove column C in Sheet1:
|
||||
//
|
||||
// xlsx.RemoveCol("Sheet1", "C")
|
||||
//
|
||||
func (f *File) RemoveCol(sheet, column string) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
for i, r := range xlsx.SheetData.Row {
|
||||
for k, v := range r.C {
|
||||
axis := v.R
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
if col == column {
|
||||
xlsx.SheetData.Row[i].C = append(xlsx.SheetData.Row[i].C[:k], xlsx.SheetData.Row[i].C[k+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
col := TitleToNumber(strings.ToUpper(column))
|
||||
f.adjustHelper(sheet, col, -1, -1)
|
||||
}
|
||||
|
||||
// Completion column element tags of XML in a sheet.
|
||||
func completeCol(xlsx *xlsxWorksheet, row, cell int) {
|
||||
if len(xlsx.SheetData.Row) < cell {
|
||||
for i := len(xlsx.SheetData.Row); i < cell; i++ {
|
||||
xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{
|
||||
R: i + 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
buffer := bytes.Buffer{}
|
||||
for k, v := range xlsx.SheetData.Row {
|
||||
if len(v.C) < cell {
|
||||
start := len(v.C)
|
||||
for iii := start; iii < cell; iii++ {
|
||||
buffer.WriteString(ToAlphaString(iii))
|
||||
buffer.WriteString(strconv.Itoa(k + 1))
|
||||
xlsx.SheetData.Row[k].C = append(xlsx.SheetData.Row[k].C, xlsxC{
|
||||
R: buffer.String(),
|
||||
})
|
||||
buffer.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convertColWidthToPixels provieds function to convert the width of a cell from
|
||||
// user's units to pixels. Excel rounds the column width to the nearest pixel.
|
||||
// If the width hasn't been set by the user we use the default value. If the
|
||||
|
@ -261,15 +318,3 @@ func convertColWidthToPixels(width float64) float64 {
|
|||
pixels = (width*maxDigitWidth + 0.5) + padding
|
||||
return math.Ceil(pixels)
|
||||
}
|
||||
|
||||
// convertRowHeightToPixels provides function to convert the height of a cell
|
||||
// from user's units to pixels. If the height hasn't been set by the user we use
|
||||
// the default value. If the row is hidden it has a value of zero.
|
||||
func convertRowHeightToPixels(height float64) float64 {
|
||||
var pixels float64
|
||||
if height == 0 {
|
||||
return pixels
|
||||
}
|
||||
pixels = math.Ceil(4.0 / 3.0 * height)
|
||||
return pixels
|
||||
}
|
||||
|
|
489
excelize.go
489
excelize.go
|
@ -4,13 +4,11 @@ import (
|
|||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// File define a populated XLSX file struct.
|
||||
|
@ -67,72 +65,6 @@ func OpenReader(r io.Reader) (*File, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// SetCellValue provides function to set value of a cell. The following shows
|
||||
// the supported data types:
|
||||
//
|
||||
// int
|
||||
// int8
|
||||
// int16
|
||||
// int32
|
||||
// int64
|
||||
// float32
|
||||
// float64
|
||||
// string
|
||||
// []byte
|
||||
// time.Time
|
||||
// nil
|
||||
//
|
||||
// Note that default date format is m/d/yy h:mm of time.Time type value. You can
|
||||
// set numbers format by SetCellStyle() method.
|
||||
func (f *File) SetCellValue(sheet, axis string, value interface{}) {
|
||||
switch t := value.(type) {
|
||||
case int:
|
||||
f.SetCellInt(sheet, axis, value.(int))
|
||||
case int8:
|
||||
f.SetCellInt(sheet, axis, int(value.(int8)))
|
||||
case int16:
|
||||
f.SetCellInt(sheet, axis, int(value.(int16)))
|
||||
case int32:
|
||||
f.SetCellInt(sheet, axis, int(value.(int32)))
|
||||
case int64:
|
||||
f.SetCellInt(sheet, axis, int(value.(int64)))
|
||||
case float32:
|
||||
f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(float32)), 'f', -1, 32))
|
||||
case float64:
|
||||
f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(value.(float64)), 'f', -1, 64))
|
||||
case string:
|
||||
f.SetCellStr(sheet, axis, t)
|
||||
case []byte:
|
||||
f.SetCellStr(sheet, axis, string(t))
|
||||
case time.Time:
|
||||
f.SetCellDefault(sheet, axis, strconv.FormatFloat(float64(timeToExcelTime(timeToUTCTime(value.(time.Time)))), 'f', -1, 32))
|
||||
f.setDefaultTimeStyle(sheet, axis)
|
||||
case nil:
|
||||
f.SetCellStr(sheet, axis, "")
|
||||
default:
|
||||
f.SetCellStr(sheet, axis, fmt.Sprintf("%v", value))
|
||||
}
|
||||
}
|
||||
|
||||
// GetCellStyle provides function to get cell style index by given worksheet
|
||||
// name and cell coordinates.
|
||||
func (f *File) GetCellStyle(sheet, axis string) int {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
axis = f.mergeCellsParser(xlsx, axis)
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row - 1
|
||||
yAxis := TitleToNumber(col)
|
||||
|
||||
rows := xAxis + 1
|
||||
cell := yAxis + 1
|
||||
|
||||
completeRow(xlsx, rows, cell)
|
||||
completeCol(xlsx, rows, cell)
|
||||
|
||||
return f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
|
||||
}
|
||||
|
||||
// setDefaultTimeStyle provides function to set default numbers format for
|
||||
// time.Time type cell value by given worksheet name and cell coordinates.
|
||||
func (f *File) setDefaultTimeStyle(sheet, axis string) {
|
||||
|
@ -163,151 +95,6 @@ func (f *File) workSheetReader(sheet string) *xlsxWorksheet {
|
|||
return f.Sheet[name]
|
||||
}
|
||||
|
||||
// SetCellInt provides function to set int type value of a cell by given
|
||||
// worksheet name, cell coordinates and cell value.
|
||||
func (f *File) SetCellInt(sheet, axis string, value int) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
axis = f.mergeCellsParser(xlsx, axis)
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row - 1
|
||||
yAxis := TitleToNumber(col)
|
||||
|
||||
rows := xAxis + 1
|
||||
cell := yAxis + 1
|
||||
|
||||
completeRow(xlsx, rows, cell)
|
||||
completeCol(xlsx, rows, cell)
|
||||
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].V = strconv.Itoa(value)
|
||||
}
|
||||
|
||||
// prepareCellStyle provides function to prepare style index of cell in
|
||||
// worksheet by given column index and style index.
|
||||
func (f *File) prepareCellStyle(xlsx *xlsxWorksheet, col, style int) int {
|
||||
if xlsx.Cols != nil && style == 0 {
|
||||
for _, v := range xlsx.Cols.Col {
|
||||
if v.Min <= col && col <= v.Max {
|
||||
style = v.Style
|
||||
}
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
// SetCellStr provides function to set string type value of a cell. Total number
|
||||
// of characters that a cell can contain 32767 characters.
|
||||
func (f *File) SetCellStr(sheet, axis, value string) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
axis = f.mergeCellsParser(xlsx, axis)
|
||||
if len(value) > 32767 {
|
||||
value = value[0:32767]
|
||||
}
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row - 1
|
||||
yAxis := TitleToNumber(col)
|
||||
|
||||
rows := xAxis + 1
|
||||
cell := yAxis + 1
|
||||
|
||||
completeRow(xlsx, rows, cell)
|
||||
completeCol(xlsx, rows, cell)
|
||||
|
||||
// Leading space(s) character detection.
|
||||
if len(value) > 0 {
|
||||
if value[0] == 32 {
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].XMLSpace = xml.Attr{
|
||||
Name: xml.Name{Space: NameSpaceXML, Local: "space"},
|
||||
Value: "preserve",
|
||||
}
|
||||
}
|
||||
}
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].T = "str"
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].V = value
|
||||
}
|
||||
|
||||
// SetCellDefault provides function to set string type value of a cell as
|
||||
// default format without escaping the cell.
|
||||
func (f *File) SetCellDefault(sheet, axis, value string) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
axis = f.mergeCellsParser(xlsx, axis)
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row - 1
|
||||
yAxis := TitleToNumber(col)
|
||||
|
||||
rows := xAxis + 1
|
||||
cell := yAxis + 1
|
||||
|
||||
completeRow(xlsx, rows, cell)
|
||||
completeCol(xlsx, rows, cell)
|
||||
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].S = f.prepareCellStyle(xlsx, cell, xlsx.SheetData.Row[xAxis].C[yAxis].S)
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
|
||||
xlsx.SheetData.Row[xAxis].C[yAxis].V = value
|
||||
}
|
||||
|
||||
// Completion column element tags of XML in a sheet.
|
||||
func completeCol(xlsx *xlsxWorksheet, row, cell int) {
|
||||
if len(xlsx.SheetData.Row) < cell {
|
||||
for i := len(xlsx.SheetData.Row); i < cell; i++ {
|
||||
xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{
|
||||
R: i + 1,
|
||||
})
|
||||
}
|
||||
}
|
||||
buffer := bytes.Buffer{}
|
||||
for k, v := range xlsx.SheetData.Row {
|
||||
if len(v.C) < cell {
|
||||
start := len(v.C)
|
||||
for iii := start; iii < cell; iii++ {
|
||||
buffer.WriteString(ToAlphaString(iii))
|
||||
buffer.WriteString(strconv.Itoa(k + 1))
|
||||
xlsx.SheetData.Row[k].C = append(xlsx.SheetData.Row[k].C, xlsxC{
|
||||
R: buffer.String(),
|
||||
})
|
||||
buffer.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// completeRow provides function to check and fill each column element for a
|
||||
// single row and make that is continuous in a worksheet of XML by given row
|
||||
// index and axis.
|
||||
func completeRow(xlsx *xlsxWorksheet, row, cell int) {
|
||||
currentRows := len(xlsx.SheetData.Row)
|
||||
if currentRows > 1 {
|
||||
lastRow := xlsx.SheetData.Row[currentRows-1].R
|
||||
if lastRow >= row {
|
||||
row = lastRow
|
||||
}
|
||||
}
|
||||
for i := currentRows; i < row; i++ {
|
||||
xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{
|
||||
R: i + 1,
|
||||
})
|
||||
}
|
||||
buffer := bytes.Buffer{}
|
||||
for ii := currentRows; ii < row; ii++ {
|
||||
start := len(xlsx.SheetData.Row[ii].C)
|
||||
if start == 0 {
|
||||
for iii := start; iii < cell; iii++ {
|
||||
buffer.WriteString(ToAlphaString(iii))
|
||||
buffer.WriteString(strconv.Itoa(ii + 1))
|
||||
xlsx.SheetData.Row[ii].C = append(xlsx.SheetData.Row[ii].C, xlsxC{
|
||||
R: buffer.String(),
|
||||
})
|
||||
buffer.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkSheet provides function to fill each row element and make that is
|
||||
// continuous in a worksheet of XML.
|
||||
func checkSheet(xlsx *xlsxWorksheet) {
|
||||
|
@ -346,61 +133,6 @@ func replaceWorkSheetsRelationshipsNameSpace(workbookMarshal string) string {
|
|||
return workbookMarshal
|
||||
}
|
||||
|
||||
// checkRow provides function to check and fill each column element for all rows
|
||||
// and make that is continuous in a worksheet of XML. For example:
|
||||
//
|
||||
// <row r="15" spans="1:22" x14ac:dyDescent="0.2">
|
||||
// <c r="A15" s="2" />
|
||||
// <c r="B15" s="2" />
|
||||
// <c r="F15" s="1" />
|
||||
// <c r="G15" s="1" />
|
||||
// </row>
|
||||
//
|
||||
// in this case, we should to change it to
|
||||
//
|
||||
// <row r="15" spans="1:22" x14ac:dyDescent="0.2">
|
||||
// <c r="A15" s="2" />
|
||||
// <c r="B15" s="2" />
|
||||
// <c r="C15" s="2" />
|
||||
// <c r="D15" s="2" />
|
||||
// <c r="E15" s="2" />
|
||||
// <c r="F15" s="1" />
|
||||
// <c r="G15" s="1" />
|
||||
// </row>
|
||||
//
|
||||
// Noteice: this method could be very slow for large spreadsheets (more than
|
||||
// 3000 rows one sheet).
|
||||
func checkRow(xlsx *xlsxWorksheet) {
|
||||
buffer := bytes.Buffer{}
|
||||
for k, v := range xlsx.SheetData.Row {
|
||||
lenCol := len(v.C)
|
||||
if lenCol < 1 {
|
||||
continue
|
||||
}
|
||||
endR := string(strings.Map(letterOnlyMapF, v.C[lenCol-1].R))
|
||||
endRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, v.C[lenCol-1].R))
|
||||
endCol := TitleToNumber(endR) + 1
|
||||
if lenCol < endCol {
|
||||
oldRow := xlsx.SheetData.Row[k].C
|
||||
xlsx.SheetData.Row[k].C = xlsx.SheetData.Row[k].C[:0]
|
||||
tmp := []xlsxC{}
|
||||
for i := 0; i <= endCol; i++ {
|
||||
buffer.WriteString(ToAlphaString(i))
|
||||
buffer.WriteString(strconv.Itoa(endRow))
|
||||
tmp = append(tmp, xlsxC{
|
||||
R: buffer.String(),
|
||||
})
|
||||
buffer.Reset()
|
||||
}
|
||||
xlsx.SheetData.Row[k].C = tmp
|
||||
for _, y := range oldRow {
|
||||
colAxis := TitleToNumber(string(strings.Map(letterOnlyMapF, y.R)))
|
||||
xlsx.SheetData.Row[k].C[colAxis] = y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UpdateLinkedValue fix linked values within a spreadsheet are not updating in
|
||||
// Office Excel 2007 and 2010. This function will be remove value tag when met a
|
||||
// cell have a linked value. Reference
|
||||
|
@ -439,3 +171,224 @@ func (f *File) UpdateLinkedValue() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjustHelper provides function to adjust rows and columns dimensions,
|
||||
// hyperlinks, merged cells and auto filter when inserting or deleting rows or
|
||||
// columns.
|
||||
//
|
||||
// sheet: Worksheet index that we're editing
|
||||
// column: Index number of the column we're inserting/deleting before
|
||||
// row: Index number of the row we're inserting/deleting before
|
||||
// offset: Number of rows/column to insert/delete negative values indicate deletion
|
||||
//
|
||||
// TODO: adjustPageBreaks, adjustComments, adjustDataValidations, adjustProtectedCells
|
||||
//
|
||||
func (f *File) adjustHelper(sheet string, column, row, offset int) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
f.adjustRowDimensions(xlsx, row, offset)
|
||||
f.adjustColDimensions(xlsx, column, offset)
|
||||
f.adjustHyperlinks(sheet, column, row, offset)
|
||||
f.adjustMergeCells(xlsx, column, row, offset)
|
||||
f.adjustAutoFilter(xlsx, column, row, offset)
|
||||
checkSheet(xlsx)
|
||||
checkRow(xlsx)
|
||||
}
|
||||
|
||||
// adjustColDimensions provides function to update column dimensions when
|
||||
// inserting or deleting rows or columns.
|
||||
func (f *File) adjustColDimensions(xlsx *xlsxWorksheet, column, offset int) {
|
||||
for i, r := range xlsx.SheetData.Row {
|
||||
for k, v := range r.C {
|
||||
axis := v.R
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
yAxis := TitleToNumber(col)
|
||||
if yAxis >= column && column != -1 {
|
||||
xlsx.SheetData.Row[i].C[k].R = ToAlphaString(yAxis+offset) + strconv.Itoa(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjustRowDimensions provides function to update row dimensions when inserting
|
||||
// or deleting rows or columns.
|
||||
func (f *File) adjustRowDimensions(xlsx *xlsxWorksheet, rowIndex, offset int) {
|
||||
if rowIndex == -1 {
|
||||
return
|
||||
}
|
||||
for i, r := range xlsx.SheetData.Row {
|
||||
if r.R < rowIndex {
|
||||
continue
|
||||
}
|
||||
xlsx.SheetData.Row[i].R += offset
|
||||
for k, v := range xlsx.SheetData.Row[i].C {
|
||||
axis := v.R
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row + offset
|
||||
xlsx.SheetData.Row[i].C[k].R = col + strconv.Itoa(xAxis)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjustHyperlinks provides function to update hyperlinks when inserting or
|
||||
// deleting rows or columns.
|
||||
func (f *File) adjustHyperlinks(sheet string, column, rowIndex, offset int) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
|
||||
// order is important
|
||||
if xlsx.Hyperlinks != nil && offset < 0 {
|
||||
for i, v := range xlsx.Hyperlinks.Hyperlink {
|
||||
axis := v.Ref
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
yAxis := TitleToNumber(col)
|
||||
if row == rowIndex || yAxis == column {
|
||||
f.deleteSheetRelationships(sheet, v.RID)
|
||||
if len(xlsx.Hyperlinks.Hyperlink) > 1 {
|
||||
xlsx.Hyperlinks.Hyperlink = append(xlsx.Hyperlinks.Hyperlink[:i], xlsx.Hyperlinks.Hyperlink[i+1:]...)
|
||||
} else {
|
||||
xlsx.Hyperlinks = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if xlsx.Hyperlinks != nil {
|
||||
for i, v := range xlsx.Hyperlinks.Hyperlink {
|
||||
axis := v.Ref
|
||||
col := string(strings.Map(letterOnlyMapF, axis))
|
||||
row, _ := strconv.Atoi(strings.Map(intOnlyMapF, axis))
|
||||
xAxis := row + offset
|
||||
yAxis := TitleToNumber(col)
|
||||
if rowIndex != -1 && row >= rowIndex {
|
||||
xlsx.Hyperlinks.Hyperlink[i].Ref = col + strconv.Itoa(xAxis)
|
||||
}
|
||||
if column != -1 && yAxis >= column {
|
||||
xlsx.Hyperlinks.Hyperlink[i].Ref = ToAlphaString(yAxis+offset) + strconv.Itoa(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjustMergeCellsHelper provides function to update merged cells when inserting or
|
||||
// deleting rows or columns.
|
||||
func (f *File) adjustMergeCellsHelper(xlsx *xlsxWorksheet, column, rowIndex, offset int) {
|
||||
if xlsx.MergeCells != nil {
|
||||
for k, v := range xlsx.MergeCells.Cells {
|
||||
beg := strings.Split(v.Ref, ":")[0]
|
||||
end := strings.Split(v.Ref, ":")[1]
|
||||
|
||||
begcol := string(strings.Map(letterOnlyMapF, beg))
|
||||
begrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, beg))
|
||||
begxAxis := begrow + offset
|
||||
begyAxis := TitleToNumber(begcol)
|
||||
|
||||
endcol := string(strings.Map(letterOnlyMapF, end))
|
||||
endrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, end))
|
||||
endxAxis := endrow + offset
|
||||
endyAxis := TitleToNumber(endcol)
|
||||
|
||||
if rowIndex != -1 {
|
||||
if begrow > 1 && begrow >= rowIndex {
|
||||
beg = begcol + strconv.Itoa(begxAxis)
|
||||
}
|
||||
if endrow > 1 && endrow >= rowIndex {
|
||||
end = endcol + strconv.Itoa(endxAxis)
|
||||
}
|
||||
}
|
||||
|
||||
if column != -1 {
|
||||
if begyAxis >= column {
|
||||
beg = ToAlphaString(begyAxis+offset) + strconv.Itoa(endrow)
|
||||
}
|
||||
if endyAxis >= column {
|
||||
end = ToAlphaString(endyAxis+offset) + strconv.Itoa(endrow)
|
||||
}
|
||||
}
|
||||
|
||||
xlsx.MergeCells.Cells[k].Ref = beg + ":" + end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjustMergeCells provides function to update merged cells when inserting or
|
||||
// deleting rows or columns.
|
||||
func (f *File) adjustMergeCells(xlsx *xlsxWorksheet, column, rowIndex, offset int) {
|
||||
f.adjustMergeCellsHelper(xlsx, column, rowIndex, offset)
|
||||
|
||||
if xlsx.MergeCells != nil && offset < 0 {
|
||||
for k, v := range xlsx.MergeCells.Cells {
|
||||
beg := strings.Split(v.Ref, ":")[0]
|
||||
end := strings.Split(v.Ref, ":")[1]
|
||||
if beg == end {
|
||||
xlsx.MergeCells.Count += offset
|
||||
if len(xlsx.MergeCells.Cells) > 1 {
|
||||
xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:k], xlsx.MergeCells.Cells[k+1:]...)
|
||||
} else {
|
||||
xlsx.MergeCells = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjustAutoFilter provides function to update the auto filter when inserting
|
||||
// or deleting rows or columns.
|
||||
func (f *File) adjustAutoFilter(xlsx *xlsxWorksheet, column, rowIndex, offset int) {
|
||||
f.adjustAutoFilterHelper(xlsx, column, rowIndex, offset)
|
||||
|
||||
if xlsx.AutoFilter != nil {
|
||||
beg := strings.Split(xlsx.AutoFilter.Ref, ":")[0]
|
||||
end := strings.Split(xlsx.AutoFilter.Ref, ":")[1]
|
||||
|
||||
begcol := string(strings.Map(letterOnlyMapF, beg))
|
||||
begrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, beg))
|
||||
begxAxis := begrow + offset
|
||||
|
||||
endcol := string(strings.Map(letterOnlyMapF, end))
|
||||
endrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, end))
|
||||
endxAxis := endrow + offset
|
||||
endyAxis := TitleToNumber(endcol)
|
||||
|
||||
if rowIndex != -1 {
|
||||
if begrow >= rowIndex {
|
||||
beg = begcol + strconv.Itoa(begxAxis)
|
||||
}
|
||||
if endrow >= rowIndex {
|
||||
end = endcol + strconv.Itoa(endxAxis)
|
||||
}
|
||||
}
|
||||
|
||||
if column != -1 && endyAxis >= column {
|
||||
end = ToAlphaString(endyAxis+offset) + strconv.Itoa(endrow)
|
||||
}
|
||||
xlsx.AutoFilter.Ref = beg + ":" + end
|
||||
}
|
||||
}
|
||||
|
||||
// adjustAutoFilterHelper provides function to update the auto filter when
|
||||
// inserting or deleting rows or columns.
|
||||
func (f *File) adjustAutoFilterHelper(xlsx *xlsxWorksheet, column, rowIndex, offset int) {
|
||||
if xlsx.AutoFilter != nil {
|
||||
beg := strings.Split(xlsx.AutoFilter.Ref, ":")[0]
|
||||
end := strings.Split(xlsx.AutoFilter.Ref, ":")[1]
|
||||
|
||||
begcol := string(strings.Map(letterOnlyMapF, beg))
|
||||
begrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, beg))
|
||||
begyAxis := TitleToNumber(begcol)
|
||||
|
||||
endcol := string(strings.Map(letterOnlyMapF, end))
|
||||
endyAxis := TitleToNumber(endcol)
|
||||
endrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, end))
|
||||
|
||||
if (begrow == rowIndex && offset < 0) || (column == begyAxis && column == endyAxis) {
|
||||
xlsx.AutoFilter = nil
|
||||
for i, r := range xlsx.SheetData.Row {
|
||||
if begrow < r.R && r.R <= endrow {
|
||||
xlsx.SheetData.Row[i].Hidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -750,7 +750,88 @@ func TestAddChart(t *testing.T) {
|
|||
xlsx.AddChart("SHEET2", "P1", `{"type":"radar","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"top_right","show_legend_key":false},"title":{"name":"Fruit Radar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"span"}`)
|
||||
xlsx.AddChart("SHEET2", "X1", `{"type":"scatter","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit Scatter Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`)
|
||||
// Save xlsx file by the given path.
|
||||
err = xlsx.SaveAs("./test/Workbook_6.xlsx")
|
||||
err = xlsx.SaveAs("./test/Workbook_addchart.xlsx")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertCol(t *testing.T) {
|
||||
xlsx := NewFile()
|
||||
for j := 1; j <= 10; j++ {
|
||||
for i := 0; i <= 10; i++ {
|
||||
axis := ToAlphaString(i) + strconv.Itoa(j)
|
||||
xlsx.SetCellStr("Sheet1", axis, axis)
|
||||
}
|
||||
}
|
||||
xlsx.SetCellHyperLink("Sheet1", "A5", "https://github.com/xuri/excelize")
|
||||
xlsx.MergeCell("sheet1", "A1", "C3")
|
||||
err := xlsx.AutoFilter("Sheet1", "A2", "B2", `{"column":"B","expression":"x != blanks"}`)
|
||||
t.Log(err)
|
||||
xlsx.InsertCol("Sheet1", "A")
|
||||
err = xlsx.SaveAs("./test/Workbook_insertcol.xlsx")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveCol(t *testing.T) {
|
||||
xlsx := NewFile()
|
||||
for j := 1; j <= 10; j++ {
|
||||
for i := 0; i <= 10; i++ {
|
||||
axis := ToAlphaString(i) + strconv.Itoa(j)
|
||||
xlsx.SetCellStr("Sheet1", axis, axis)
|
||||
}
|
||||
}
|
||||
xlsx.SetCellHyperLink("Sheet1", "A5", "https://github.com/xuri/excelize")
|
||||
xlsx.SetCellHyperLink("Sheet1", "C5", "https://github.com")
|
||||
xlsx.MergeCell("sheet1", "A1", "B1")
|
||||
xlsx.MergeCell("sheet1", "A2", "B2")
|
||||
xlsx.RemoveCol("Sheet1", "A")
|
||||
xlsx.RemoveCol("Sheet1", "A")
|
||||
err := xlsx.SaveAs("./test/Workbook_removecol.xlsx")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsertRow(t *testing.T) {
|
||||
xlsx := NewFile()
|
||||
for j := 1; j <= 10; j++ {
|
||||
for i := 0; i <= 10; i++ {
|
||||
axis := ToAlphaString(i) + strconv.Itoa(j)
|
||||
xlsx.SetCellStr("Sheet1", axis, axis)
|
||||
}
|
||||
}
|
||||
xlsx.SetCellHyperLink("Sheet1", "A5", "https://github.com/xuri/excelize")
|
||||
xlsx.InsertRow("Sheet1", -1)
|
||||
xlsx.InsertRow("Sheet1", 4)
|
||||
err := xlsx.SaveAs("./test/Workbook_insertrow.xlsx")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveRow(t *testing.T) {
|
||||
xlsx := NewFile()
|
||||
for j := 1; j <= 10; j++ {
|
||||
for i := 0; i <= 10; i++ {
|
||||
axis := ToAlphaString(i) + strconv.Itoa(j)
|
||||
xlsx.SetCellStr("Sheet1", axis, axis)
|
||||
}
|
||||
}
|
||||
xlsx.SetCellHyperLink("Sheet1", "A5", "https://github.com/xuri/excelize")
|
||||
xlsx.RemoveRow("Sheet1", -1)
|
||||
xlsx.RemoveRow("Sheet1", 4)
|
||||
xlsx.MergeCell("sheet1", "B3", "B5")
|
||||
xlsx.RemoveRow("Sheet1", 2)
|
||||
xlsx.RemoveRow("Sheet1", 4)
|
||||
err := xlsx.AutoFilter("Sheet1", "A2", "A2", `{"column":"A","expression":"x != blanks"}`)
|
||||
t.Log(err)
|
||||
xlsx.RemoveRow("Sheet1", 0)
|
||||
xlsx.RemoveRow("Sheet1", 1)
|
||||
xlsx.RemoveRow("Sheet1", 0)
|
||||
err = xlsx.SaveAs("./test/Workbook_removerow.xlsx")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
|
17
picture.go
17
picture.go
|
@ -127,6 +127,23 @@ func (f *File) addSheetRelationships(sheet, relType, target, targetMode string)
|
|||
return rID
|
||||
}
|
||||
|
||||
// deleteSheetRelationships provides function to delete relationships in
|
||||
// xl/worksheets/_rels/sheet%d.xml.rels by given sheet name and relationship
|
||||
// index.
|
||||
func (f *File) deleteSheetRelationships(sheet, rID string) {
|
||||
var rels = "xl/worksheets/_rels/" + strings.ToLower(sheet) + ".xml.rels"
|
||||
var sheetRels xlsxWorkbookRels
|
||||
xml.Unmarshal([]byte(f.readXML(rels)), &sheetRels)
|
||||
for k, v := range sheetRels.Relationships {
|
||||
if v.ID != rID {
|
||||
continue
|
||||
}
|
||||
sheetRels.Relationships = append(sheetRels.Relationships[:k], sheetRels.Relationships[k+1:]...)
|
||||
}
|
||||
output, _ := xml.Marshal(sheetRels)
|
||||
f.saveFileList(rels, string(output))
|
||||
}
|
||||
|
||||
// addSheetLegacyDrawing provides function to add legacy drawing element to
|
||||
// xl/worksheets/sheet%d.xml by given sheet name and relationship index.
|
||||
func (f *File) addSheetLegacyDrawing(sheet string, rID int) {
|
||||
|
|
135
rows.go
135
rows.go
|
@ -1,7 +1,9 @@
|
|||
package excelize
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
@ -209,3 +211,136 @@ func (f *File) GetRowVisible(sheet string, rowIndex int) bool {
|
|||
completeRow(xlsx, rows, cells)
|
||||
return !xlsx.SheetData.Row[rowIndex].Hidden
|
||||
}
|
||||
|
||||
// RemoveRow provides function to remove single row by given worksheet index and
|
||||
// row index. For example, remove row 3 in Sheet1:
|
||||
//
|
||||
// xlsx.RemoveRow("Sheet1", 2)
|
||||
//
|
||||
func (f *File) RemoveRow(sheet string, row int) {
|
||||
if row < 0 {
|
||||
return
|
||||
}
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
row++
|
||||
for i, r := range xlsx.SheetData.Row {
|
||||
if r.R != row {
|
||||
continue
|
||||
}
|
||||
xlsx.SheetData.Row = append(xlsx.SheetData.Row[:i], xlsx.SheetData.Row[i+1:]...)
|
||||
f.adjustHelper(sheet, -1, row, -1)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// InsertRow provides function to insert a new row before given row index. For
|
||||
// example, create a new row before row 3 in Sheet1:
|
||||
//
|
||||
// xlsx.InsertRow("Sheet1", 2)
|
||||
//
|
||||
func (f *File) InsertRow(sheet string, row int) {
|
||||
if row < 0 {
|
||||
return
|
||||
}
|
||||
row++
|
||||
f.adjustHelper(sheet, -1, row, 1)
|
||||
}
|
||||
|
||||
// checkRow provides function to check and fill each column element for all rows
|
||||
// and make that is continuous in a worksheet of XML. For example:
|
||||
//
|
||||
// <row r="15" spans="1:22" x14ac:dyDescent="0.2">
|
||||
// <c r="A15" s="2" />
|
||||
// <c r="B15" s="2" />
|
||||
// <c r="F15" s="1" />
|
||||
// <c r="G15" s="1" />
|
||||
// </row>
|
||||
//
|
||||
// in this case, we should to change it to
|
||||
//
|
||||
// <row r="15" spans="1:22" x14ac:dyDescent="0.2">
|
||||
// <c r="A15" s="2" />
|
||||
// <c r="B15" s="2" />
|
||||
// <c r="C15" s="2" />
|
||||
// <c r="D15" s="2" />
|
||||
// <c r="E15" s="2" />
|
||||
// <c r="F15" s="1" />
|
||||
// <c r="G15" s="1" />
|
||||
// </row>
|
||||
//
|
||||
// Noteice: this method could be very slow for large spreadsheets (more than
|
||||
// 3000 rows one sheet).
|
||||
func checkRow(xlsx *xlsxWorksheet) {
|
||||
buffer := bytes.Buffer{}
|
||||
for k, v := range xlsx.SheetData.Row {
|
||||
lenCol := len(v.C)
|
||||
if lenCol < 1 {
|
||||
continue
|
||||
}
|
||||
endR := string(strings.Map(letterOnlyMapF, v.C[lenCol-1].R))
|
||||
endRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, v.C[lenCol-1].R))
|
||||
endCol := TitleToNumber(endR) + 1
|
||||
if lenCol < endCol {
|
||||
oldRow := xlsx.SheetData.Row[k].C
|
||||
xlsx.SheetData.Row[k].C = xlsx.SheetData.Row[k].C[:0]
|
||||
tmp := []xlsxC{}
|
||||
for i := 0; i <= endCol; i++ {
|
||||
buffer.WriteString(ToAlphaString(i))
|
||||
buffer.WriteString(strconv.Itoa(endRow))
|
||||
tmp = append(tmp, xlsxC{
|
||||
R: buffer.String(),
|
||||
})
|
||||
buffer.Reset()
|
||||
}
|
||||
xlsx.SheetData.Row[k].C = tmp
|
||||
for _, y := range oldRow {
|
||||
colAxis := TitleToNumber(string(strings.Map(letterOnlyMapF, y.R)))
|
||||
xlsx.SheetData.Row[k].C[colAxis] = y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// completeRow provides function to check and fill each column element for a
|
||||
// single row and make that is continuous in a worksheet of XML by given row
|
||||
// index and axis.
|
||||
func completeRow(xlsx *xlsxWorksheet, row, cell int) {
|
||||
currentRows := len(xlsx.SheetData.Row)
|
||||
if currentRows > 1 {
|
||||
lastRow := xlsx.SheetData.Row[currentRows-1].R
|
||||
if lastRow >= row {
|
||||
row = lastRow
|
||||
}
|
||||
}
|
||||
for i := currentRows; i < row; i++ {
|
||||
xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{
|
||||
R: i + 1,
|
||||
})
|
||||
}
|
||||
buffer := bytes.Buffer{}
|
||||
for ii := currentRows; ii < row; ii++ {
|
||||
start := len(xlsx.SheetData.Row[ii].C)
|
||||
if start == 0 {
|
||||
for iii := start; iii < cell; iii++ {
|
||||
buffer.WriteString(ToAlphaString(iii))
|
||||
buffer.WriteString(strconv.Itoa(ii + 1))
|
||||
xlsx.SheetData.Row[ii].C = append(xlsx.SheetData.Row[ii].C, xlsxC{
|
||||
R: buffer.String(),
|
||||
})
|
||||
buffer.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convertRowHeightToPixels provides function to convert the height of a cell
|
||||
// from user's units to pixels. If the height hasn't been set by the user we use
|
||||
// the default value. If the row is hidden it has a value of zero.
|
||||
func convertRowHeightToPixels(height float64) float64 {
|
||||
var pixels float64
|
||||
if height == 0 {
|
||||
return pixels
|
||||
}
|
||||
pixels = math.Ceil(4.0 / 3.0 * height)
|
||||
return pixels
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue