forked from tealeg/xlsx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
xmlSharedStrings.go
164 lines (149 loc) · 4.7 KB
/
xmlSharedStrings.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package xlsx
import (
"encoding/xml"
"errors"
"strings"
)
// xlsxSST directly maps the sst 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.
type xlsxSST struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main sst"`
Count int `xml:"count,attr"`
UniqueCount int `xml:"uniqueCount,attr"`
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.
type xlsxSI struct {
T *xlsxT `xml:"t"`
R []xlsxR `xml:"r"`
}
// 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.
type xlsxR struct {
RPr *xlsxRunProperties `xml:"rPr"`
T xlsxT `xml:"t"`
}
// xlsxRunProperties directly maps the rPr element from the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main
type xlsxRunProperties struct {
RFont *xlsxVal `xml:"rFont"`
Charset *xlsxIntVal `xml:"charset"`
Family *xlsxIntVal `xml:"family"`
B xlsxBoolProp `xml:"b"`
I xlsxBoolProp `xml:"i"`
Strike xlsxBoolProp `xml:"strike"`
Outline xlsxBoolProp `xml:"outline"`
Shadow xlsxBoolProp `xml:"shadow"`
Condense xlsxBoolProp `xml:"condense"`
Extend xlsxBoolProp `xml:"extend"`
Color *xlsxColor `xml:"color"`
Sz *xlsxFloatVal `xml:"sz"`
U *xlsxVal `xml:"u"`
VertAlign *xlsxVal `xml:"vertAlign"`
Scheme *xlsxVal `xml:"scheme"`
}
// xlsxBoolProp handles "CT_BooleanProperty" type which is declared in the XML Schema of Office Open XML.
// XML attribute "val" is optional. If "val" was omitted, the property value becomes "true".
// On the serialization, the struct which has "true" will be serialized an empty XML tag without "val" attributes,
// and the struct which has "false" will not be serialized.
type xlsxBoolProp struct {
Val bool `xml:"val,attr"`
}
// MarshalXML implements xml.Marshaler interface for xlsxBoolProp
func (b *xlsxBoolProp) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if b.Val {
if err := e.EncodeToken(start); err != nil {
return err
}
if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil {
return err
}
}
return nil
}
// UnmarshalXML implements xml.Unmarshaler interface for xlsxBoolProp
func (b *xlsxBoolProp) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
boolVal := true
for _, attr := range start.Attr {
if attr.Name.Space == "" && attr.Name.Local == "val" {
// supports xsd:boolean
switch attr.Value {
case "true", "1":
boolVal = true
case "false", "0":
boolVal = false
default:
return errors.New(
"Cannot unmarshal into xlsxBoolProp: \"" +
attr.Value + "\" is not a valid boolean value")
}
}
}
b.Val = boolVal
return d.Skip()
}
// xlsxIntVal is like xlsxVal, except it has an int value
type xlsxIntVal struct {
Val int `xml:"val,attr"`
}
// xlsxFloatVal is like xlsxVal, except it has a float value
type xlsxFloatVal struct {
Val float64 `xml:"val,attr"`
}
// xlsxT represents a text. It will be serialized as a XML tag which has character data.
// Attribute xml:space="preserve" will be added to the XML tag if needed.
type xlsxT struct {
Text string `xml:",chardata"`
}
// MarshalXML implements xml.Marshaler interface for xlsxT
func (t *xlsxT) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if needPreserve(t.Text) {
attr := xml.Attr{
Name: xml.Name{Local: "xml:space"},
Value: "preserve",
}
start.Attr = append(start.Attr, attr)
}
if err := e.EncodeToken(start); err != nil {
return err
}
if err := e.EncodeToken(xml.CharData(t.Text)); err != nil {
return err
}
if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil {
return err
}
return nil
}
// getText is a nil-safe utility function that gets a string from xlsxT.
// If the pointer of xlsxT was nil, returns an empty string.
func (t *xlsxT) getText() string {
if t == nil {
return ""
}
return t.Text
}
// needPreserve determines whether xml:space="preserve" is needed.
func needPreserve(s string) bool {
if len(s) == 0 {
return false
}
// Note:
// xml:space="preserve" is not needed for CR and TAB
// because they are serialized as "
" and "	".
c := s[0]
if c <= 32 && c != 9 && c != 13 {
return true
}
c = s[len(s)-1]
if c <= 32 && c != 9 && c != 13 {
return true
}
return strings.ContainsRune(s, '\u000a')
}