Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xuri
excelize
提交
66d0272f
excelize
项目概览
xuri
/
excelize
通知
13
Star
2
Fork
4
代码
文件
提交
分支
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,体验更适合开发者的 AI 搜索 >>
已验证
提交
66d0272f
编写于
4月 06, 2020
作者:
xurime
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Resolve #172, init rich text support
上级
0f2a9053
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
331 addition
and
32 deletion
+331
-32
cell.go
cell.go
+166
-0
cell_test.go
cell_test.go
+81
-0
comment.go
comment.go
+5
-3
file.go
file.go
+1
-0
picture.go
picture.go
+16
-14
styles.go
styles.go
+13
-1
styles_test.go
styles_test.go
+2
-0
xmlDrawing.go
xmlDrawing.go
+2
-0
xmlSharedStrings.go
xmlSharedStrings.go
+45
-14
未找到文件。
cell.go
浏览文件 @
66d0272f
...
...
@@ -457,6 +457,172 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) error {
return
nil
}
// SetCellRichText provides a function to set cell with rich text by given
// worksheet. For example:
//
// package main
//
// import (
// "fmt"
//
// "github.com/360EntSecGroup-Skylar/excelize"
// )
//
// func main() {
// f := excelize.NewFile()
// if err := f.SetRowHeight("Sheet1", 1, 35); err != nil {
// fmt.Println(err)
// return
// }
// if err := f.SetColWidth("Sheet1", "A", "A", 44); err != nil {
// fmt.Println(err)
// return
// }
// if err := f.SetCellRichText("Sheet1", "A1", []excelize.RichTextRun{
// {
// Text: "blod",
// Font: &excelize.Font{
// Bold: true,
// Color: "2354e8",
// Family: "Times New Roman",
// },
// },
// {
// Text: " and ",
// Font: &excelize.Font{
// Family: "Times New Roman",
// },
// },
// {
// Text: " italic",
// Font: &excelize.Font{
// Bold: true,
// Color: "e83723",
// Italic: true,
// Family: "Times New Roman",
// },
// },
// {
// Text: "text with color and font-family,",
// Font: &excelize.Font{
// Bold: true,
// Color: "2354e8",
// Family: "Times New Roman",
// },
// },
// {
// Text: "\r\nlarge text with ",
// Font: &excelize.Font{
// Size: 14,
// Color: "ad23e8",
// },
// },
// {
// Text: "strike",
// Font: &excelize.Font{
// Color: "e89923",
// Strike: true,
// },
// },
// {
// Text: " and ",
// Font: &excelize.Font{
// Size: 14,
// Color: "ad23e8",
// },
// },
// {
// Text: "underline.",
// Font: &excelize.Font{
// Color: "23e833",
// Underline: "single",
// },
// },
// }); err != nil {
// fmt.Println(err)
// return
// }
// style, err := f.NewStyle(&excelize.Style{
// Alignment: &excelize.Alignment{
// WrapText: true,
// },
// })
// if err != nil {
// fmt.Println(err)
// return
// }
// if err := f.SetCellStyle("Sheet1", "A1", "A1", style); err != nil {
// fmt.Println(err)
// return
// }
// if err := f.SaveAs("Book1.xlsx"); err != nil {
// fmt.Println(err)
// }
// }
//
func
(
f
*
File
)
SetCellRichText
(
sheet
,
cell
string
,
runs
[]
RichTextRun
)
error
{
ws
,
err
:=
f
.
workSheetReader
(
sheet
)
if
err
!=
nil
{
return
err
}
cellData
,
col
,
_
,
err
:=
f
.
prepareCell
(
ws
,
sheet
,
cell
)
if
err
!=
nil
{
return
err
}
cellData
.
S
=
f
.
prepareCellStyle
(
ws
,
col
,
cellData
.
S
)
si
:=
xlsxSI
{}
sst
:=
f
.
sharedStringsReader
()
textRuns
:=
[]
xlsxR
{}
for
_
,
textRun
:=
range
runs
{
run
:=
xlsxR
{
T
:
&
xlsxT
{
Val
:
textRun
.
Text
}}
if
strings
.
ContainsAny
(
textRun
.
Text
,
"
\r\n
"
)
{
run
.
T
.
Space
=
"preserve"
}
fnt
:=
textRun
.
Font
if
fnt
!=
nil
{
rpr
:=
xlsxRPr
{}
if
fnt
.
Bold
{
rpr
.
B
=
" "
}
if
fnt
.
Italic
{
rpr
.
I
=
" "
}
if
fnt
.
Strike
{
rpr
.
Strike
=
" "
}
if
fnt
.
Underline
!=
""
{
rpr
.
U
=
&
attrValString
{
Val
:
&
fnt
.
Underline
}
}
if
fnt
.
Family
!=
""
{
rpr
.
RFont
=
&
attrValString
{
Val
:
&
fnt
.
Family
}
}
if
fnt
.
Size
>
0.0
{
rpr
.
Sz
=
&
attrValFloat
{
Val
:
&
fnt
.
Size
}
}
if
fnt
.
Color
!=
""
{
rpr
.
Color
=
&
xlsxColor
{
RGB
:
getPaletteColor
(
fnt
.
Color
)}
}
run
.
RPr
=
&
rpr
}
textRuns
=
append
(
textRuns
,
run
)
}
si
.
R
=
textRuns
sst
.
SI
=
append
(
sst
.
SI
,
si
)
sst
.
Count
++
sst
.
UniqueCount
++
cellData
.
T
,
cellData
.
V
=
"s"
,
strconv
.
Itoa
(
len
(
sst
.
SI
)
-
1
)
f
.
addContentTypePart
(
0
,
"sharedStrings"
)
rels
:=
f
.
relsReader
(
"xl/_rels/workbook.xml.rels"
)
for
_
,
rel
:=
range
rels
.
Relationships
{
if
rel
.
Target
==
"sharedStrings.xml"
{
return
err
}
}
// Update xl/_rels/workbook.xml.rels
f
.
addRels
(
"xl/_rels/workbook.xml.rels"
,
SourceRelationshipSharedStrings
,
"sharedStrings.xml"
,
""
)
return
err
}
// SetSheetRow writes an array to row by given worksheet name, starting
// coordinate and a pointer to array type 'slice'. For example, writes an
// array to row 6 start with the cell B6 on Sheet1:
...
...
cell_test.go
浏览文件 @
66d0272f
...
...
@@ -141,3 +141,84 @@ func TestOverflowNumericCell(t *testing.T) {
// GOARCH=amd64 - all ok; GOARCH=386 - actual: "-2147483648"
assert
.
Equal
(
t
,
"8595602512225"
,
val
,
"A1 should be 8595602512225"
)
}
func
TestSetCellRichText
(
t
*
testing
.
T
)
{
f
:=
NewFile
()
assert
.
NoError
(
t
,
f
.
SetRowHeight
(
"Sheet1"
,
1
,
35
))
assert
.
NoError
(
t
,
f
.
SetColWidth
(
"Sheet1"
,
"A"
,
"A"
,
44
))
richTextRun
:=
[]
RichTextRun
{
{
Text
:
"blod"
,
Font
:
&
Font
{
Bold
:
true
,
Color
:
"2354e8"
,
Family
:
"Times New Roman"
,
},
},
{
Text
:
" and "
,
Font
:
&
Font
{
Family
:
"Times New Roman"
,
},
},
{
Text
:
"italic "
,
Font
:
&
Font
{
Bold
:
true
,
Color
:
"e83723"
,
Italic
:
true
,
Family
:
"Times New Roman"
,
},
},
{
Text
:
"text with color and font-family,"
,
Font
:
&
Font
{
Bold
:
true
,
Color
:
"2354e8"
,
Family
:
"Times New Roman"
,
},
},
{
Text
:
"
\r\n
large text with "
,
Font
:
&
Font
{
Size
:
14
,
Color
:
"ad23e8"
,
},
},
{
Text
:
"strike"
,
Font
:
&
Font
{
Color
:
"e89923"
,
Strike
:
true
,
},
},
{
Text
:
" and "
,
Font
:
&
Font
{
Size
:
14
,
Color
:
"ad23e8"
,
},
},
{
Text
:
"underline."
,
Font
:
&
Font
{
Color
:
"23e833"
,
Underline
:
"single"
,
},
},
}
assert
.
NoError
(
t
,
f
.
SetCellRichText
(
"Sheet1"
,
"A1"
,
richTextRun
))
assert
.
NoError
(
t
,
f
.
SetCellRichText
(
"Sheet1"
,
"A2"
,
richTextRun
))
style
,
err
:=
f
.
NewStyle
(
&
Style
{
Alignment
:
&
Alignment
{
WrapText
:
true
,
},
})
assert
.
NoError
(
t
,
err
)
assert
.
NoError
(
t
,
f
.
SetCellStyle
(
"Sheet1"
,
"A1"
,
"A1"
,
style
))
assert
.
NoError
(
t
,
f
.
SaveAs
(
filepath
.
Join
(
"test"
,
"TestSetCellRichText.xlsx"
)))
// Test set cell rich text on not exists worksheet
assert
.
EqualError
(
t
,
f
.
SetCellRichText
(
"SheetN"
,
"A1"
,
richTextRun
),
"sheet SheetN is not exist"
)
// Test set cell rich text with illegal cell coordinates
assert
.
EqualError
(
t
,
f
.
SetCellRichText
(
"Sheet1"
,
"A"
,
richTextRun
),
`cannot convert cell "A" to coordinates: invalid cell name "A"`
)
}
comment.go
浏览文件 @
66d0272f
...
...
@@ -50,7 +50,9 @@ func (f *File) GetComments() (comments map[string][]Comment) {
sheetComment
.
Text
+=
*
comment
.
Text
.
T
}
for
_
,
text
:=
range
comment
.
Text
.
R
{
sheetComment
.
Text
+=
text
.
T
if
text
.
T
!=
nil
{
sheetComment
.
Text
+=
text
.
T
.
Val
}
}
sheetComments
=
append
(
sheetComments
,
sheetComment
)
}
...
...
@@ -263,7 +265,7 @@ func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) {
RFont
:
&
attrValString
{
Val
:
stringPtr
(
defaultFont
)},
Family
:
&
attrValInt
{
Val
:
intPtr
(
2
)},
},
T
:
a
,
T
:
&
xlsxT
{
Val
:
a
}
,
},
{
RPr
:
&
xlsxRPr
{
...
...
@@ -274,7 +276,7 @@ func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) {
RFont
:
&
attrValString
{
Val
:
stringPtr
(
defaultFont
)},
Family
:
&
attrValInt
{
Val
:
intPtr
(
2
)},
},
T
:
t
,
T
:
&
xlsxT
{
Val
:
t
}
,
},
},
},
...
...
file.go
浏览文件 @
66d0272f
...
...
@@ -97,6 +97,7 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
f
.
workBookWriter
()
f
.
workSheetWriter
()
f
.
relsWriter
()
f
.
sharedStringsWriter
()
f
.
styleSheetWriter
()
for
path
,
content
:=
range
f
.
XLSX
{
...
...
picture.go
浏览文件 @
66d0272f
...
...
@@ -367,22 +367,24 @@ func (f *File) addContentTypePart(index int, contentType string) {
"drawings"
:
f
.
setContentTypePartImageExtensions
,
}
partNames
:=
map
[
string
]
string
{
"chart"
:
"/xl/charts/chart"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"chartsheet"
:
"/xl/chartsheets/sheet"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"comments"
:
"/xl/comments"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"drawings"
:
"/xl/drawings/drawing"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"table"
:
"/xl/tables/table"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"pivotTable"
:
"/xl/pivotTables/pivotTable"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"pivotCache"
:
"/xl/pivotCache/pivotCacheDefinition"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"chart"
:
"/xl/charts/chart"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"chartsheet"
:
"/xl/chartsheets/sheet"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"comments"
:
"/xl/comments"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"drawings"
:
"/xl/drawings/drawing"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"table"
:
"/xl/tables/table"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"pivotTable"
:
"/xl/pivotTables/pivotTable"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"pivotCache"
:
"/xl/pivotCache/pivotCacheDefinition"
+
strconv
.
Itoa
(
index
)
+
".xml"
,
"sharedStrings"
:
"/xl/sharedStrings.xml"
,
}
contentTypes
:=
map
[
string
]
string
{
"chart"
:
ContentTypeDrawingML
,
"chartsheet"
:
ContentTypeSpreadSheetMLChartsheet
,
"comments"
:
ContentTypeSpreadSheetMLComments
,
"drawings"
:
ContentTypeDrawing
,
"table"
:
ContentTypeSpreadSheetMLTable
,
"pivotTable"
:
ContentTypeSpreadSheetMLPivotTable
,
"pivotCache"
:
ContentTypeSpreadSheetMLPivotCacheDefinition
,
"chart"
:
ContentTypeDrawingML
,
"chartsheet"
:
ContentTypeSpreadSheetMLChartsheet
,
"comments"
:
ContentTypeSpreadSheetMLComments
,
"drawings"
:
ContentTypeDrawing
,
"table"
:
ContentTypeSpreadSheetMLTable
,
"pivotTable"
:
ContentTypeSpreadSheetMLPivotTable
,
"pivotCache"
:
ContentTypeSpreadSheetMLPivotCacheDefinition
,
"sharedStrings"
:
ContentTypeSpreadSheetMLSharedStrings
,
}
s
,
ok
:=
setContentType
[
contentType
]
if
ok
{
...
...
styles.go
浏览文件 @
66d0272f
...
...
@@ -13,6 +13,7 @@ import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io"
"log"
...
...
@@ -1022,6 +1023,15 @@ func (f *File) styleSheetWriter() {
}
}
// sharedStringsWriter provides a function to save xl/sharedStrings.xml after
// serialize structure.
func
(
f
*
File
)
sharedStringsWriter
()
{
if
f
.
SharedStrings
!=
nil
{
output
,
_
:=
xml
.
Marshal
(
f
.
SharedStrings
)
f
.
saveFileList
(
"xl/sharedStrings.xml"
,
replaceRelationshipsNameSpaceBytes
(
output
))
}
}
// parseFormatStyleSet provides a function to parse the format settings of the
// cells and conditional formats.
func
parseFormatStyleSet
(
style
string
)
(
*
Style
,
error
)
{
...
...
@@ -1033,7 +1043,7 @@ func parseFormatStyleSet(style string) (*Style, error) {
}
// NewStyle provides a function to create the style for cells by given JSON or
// structure. Note that the color field uses RGB color code.
// structure
pointer
. Note that the color field uses RGB color code.
//
// The following shows the border styles sorted by excelize index number:
//
...
...
@@ -1906,6 +1916,8 @@ func (f *File) NewStyle(style interface{}) (int, error) {
}
case
*
Style
:
fs
=
v
default
:
return
cellXfsID
,
errors
.
New
(
"invalid parameter type"
)
}
s
:=
f
.
stylesReader
()
numFmtID
:=
setNumFmt
(
s
,
fs
)
...
...
styles_test.go
浏览文件 @
66d0272f
...
...
@@ -193,6 +193,8 @@ func TestNewStyle(t *testing.T) {
assert
.
Equal
(
t
,
2
,
styles
.
CellXfs
.
Count
,
"Should have 2 styles"
)
_
,
err
=
f
.
NewStyle
(
&
Style
{})
assert
.
NoError
(
t
,
err
)
_
,
err
=
f
.
NewStyle
(
Style
{})
assert
.
EqualError
(
t
,
err
,
"invalid parameter type"
)
}
func
TestGetDefaultFont
(
t
*
testing
.
T
)
{
...
...
xmlDrawing.go
浏览文件 @
66d0272f
...
...
@@ -25,6 +25,7 @@ const (
SourceRelationshipChartsheet
=
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
SourceRelationshipPivotTable
=
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipPivotCache
=
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipSharedStrings
=
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
SourceRelationshipVBAProject
=
"http://schemas.microsoft.com/office/2006/relationships/vbaProject"
SourceRelationshipChart201506
=
"http://schemas.microsoft.com/office/drawing/2015/06/chart"
SourceRelationshipChart20070802
=
"http://schemas.microsoft.com/office/drawing/2007/8/2/chart"
...
...
@@ -55,6 +56,7 @@ const (
ContentTypeSpreadSheetMLComments
=
"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"
ContentTypeSpreadSheetMLPivotCacheDefinition
=
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"
ContentTypeSpreadSheetMLPivotTable
=
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"
ContentTypeSpreadSheetMLSharedStrings
=
"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"
ContentTypeSpreadSheetMLTable
=
"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
ContentTypeSpreadSheetMLWorksheet
=
"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"
ContentTypeVBA
=
"application/vnd.ms-office.vbaProject"
...
...
xmlSharedStrings.go
浏览文件 @
66d0272f
...
...
@@ -28,31 +28,46 @@ type xlsxSST struct {
SI
[]
xlsxSI
`xml:"si"`
}
// xlsxSI directly maps the si element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have
// not checked this for completeness - it does as much as I need.
// xlsxSI (String Item) is the representation of an individual string in the
// Shared String table. If the string is just a simple string with formatting
// applied at the cell level, then the String Item (si) should contain a
// single text element used to express the string. However, if the string in
// the cell is more complex - i.e., has formatting applied at the character
// level - then the string item shall consist of multiple rich text runs which
// collectively are used to express the string.
type
xlsxSI
struct
{
T
string
`xml:"t"`
T
string
`xml:"t
,omitempty
"`
R
[]
xlsxR
`xml:"r"`
}
// String extracts characters from a string item.
func
(
x
xlsxSI
)
String
()
string
{
if
len
(
x
.
R
)
>
0
{
var
rows
strings
.
Builder
for
_
,
s
:=
range
x
.
R
{
rows
.
WriteString
(
s
.
T
)
if
s
.
T
!=
nil
{
rows
.
WriteString
(
s
.
T
.
Val
)
}
}
return
rows
.
String
()
}
return
x
.
T
}
// xlsxR directly maps the r element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have
// not checked this for completeness - it does as much as I need.
// xlsxR represents a run of rich text. A rich text run is a region of text
// that share a common set of properties, such as formatting properties. The
// properties are defined in the rPr element, and the text displayed to the
// user is defined in the Text (t) element.
type
xlsxR
struct
{
RPr
*
xlsxRPr
`xml:"rPr"`
T
string
`xml:"t"`
T
*
xlsxT
`xml:"t"`
}
// xlsxT directly maps the t element in the run properties.
type
xlsxT
struct
{
XMLName
xml
.
Name
`xml:"t"`
Space
string
`xml:"xml:space,attr,omitempty"`
Val
string
`xml:",innerxml"`
}
// xlsxRPr (Run Properties) specifies a set of run properties which shall be
...
...
@@ -61,9 +76,25 @@ type xlsxR struct {
// they are directly applied to the run and supersede any formatting from
// styles.
type
xlsxRPr
struct
{
B
string
`xml:"b,omitempty"`
Sz
*
attrValFloat
`xml:"sz"`
Color
*
xlsxColor
`xml:"color"`
RFont
*
attrValString
`xml:"rFont"`
Family
*
attrValInt
`xml:"family"`
RFont
*
attrValString
`xml:"rFont"`
Charset
*
attrValInt
`xml:"charset"`
Family
*
attrValInt
`xml:"family"`
B
string
`xml:"b,omitempty"`
I
string
`xml:"i,omitempty"`
Strike
string
`xml:"strike,omitempty"`
Outline
string
`xml:"outline,omitempty"`
Shadow
string
`xml:"shadow,omitempty"`
Condense
string
`xml:"condense,omitempty"`
Extend
string
`xml:"extend,omitempty"`
Color
*
xlsxColor
`xml:"color"`
Sz
*
attrValFloat
`xml:"sz"`
U
*
attrValString
`xml:"u"`
VertAlign
*
attrValString
`xml:"vertAlign"`
Scheme
*
attrValString
`xml:"scheme"`
}
// RichTextRun directly maps the settings of the rich text run.
type
RichTextRun
struct
{
Font
*
Font
Text
string
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录