Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
此号慢热型
excelize
提交
6aa59a1a
excelize
项目概览
此号慢热型
/
excelize
与 Fork 源项目一致
Fork自
xuri / excelize
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
excelize
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
已验证
提交
6aa59a1a
编写于
7月 24, 2017
作者:
xurime
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
- Init insert/remove column/row support. Relate issue #77 and #82;
- Readme and go test updated
上级
3b2c80dd
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
671 addition
and
283 deletion
+671
-283
README.md
README.md
+2
-2
cell.go
cell.go
+157
-0
col.go
col.go
+57
-12
excelize.go
excelize.go
+221
-268
excelize_test.go
excelize_test.go
+82
-1
picture.go
picture.go
+17
-0
rows.go
rows.go
+135
-0
未找到文件。
README.md
浏览文件 @
6aa59a1a
...
...
@@ -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)
...
...
cell.go
浏览文件 @
6aa59a1a
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
{
...
...
col.go
浏览文件 @
6aa59a1a
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
}
excelize.go
浏览文件 @
6aa59a1a
...
...
@@ -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
}
}
}
}
}
excelize_test.go
浏览文件 @
6aa59a1a
...
...
@@ -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
)
}
...
...
picture.go
浏览文件 @
6aa59a1a
...
...
@@ -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
)
{
...
...
rows.go
浏览文件 @
6aa59a1a
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
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录