Skip to content

Commit 9c079e5

Browse files
committed
This fix qax-os#1665, supports getting formula string cell value
- Improve compatibility for absolute path drawing part - Fix incorrect table ID generated in the workbook which contains single table cells - Fix missing relationship parts in the content types in some cases - Upgrade number format parser to fix missing literal tokens in some cases - Update built-in zh-cn and zh-tw language number format - Ref qax-os#65, init new formula function: TEXT - Remove duplicate style-related variables - Update the unit tests
1 parent 744236b commit 9c079e5

14 files changed

+199
-163
lines changed

calc.go

+23
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ type formulaFuncs struct {
757757
// TBILLPRICE
758758
// TBILLYIELD
759759
// TDIST
760+
// TEXT
760761
// TEXTJOIN
761762
// TIME
762763
// TIMEVALUE
@@ -14035,6 +14036,28 @@ func (fn *formulaFuncs) SUBSTITUTE(argsList *list.List) formulaArg {
1403514036
return newStringFormulaArg(pre + targetText.Value() + post)
1403614037
}
1403714038

14039+
// TEXT function converts a supplied numeric value into text, in a
14040+
// user-specified format. The syntax of the function is:
14041+
//
14042+
// TEXT(value,format_text)
14043+
func (fn *formulaFuncs) TEXT(argsList *list.List) formulaArg {
14044+
if argsList.Len() != 2 {
14045+
return newErrorFormulaArg(formulaErrorVALUE, "TEXT requires 2 arguments")
14046+
}
14047+
value, fmtText := argsList.Front().Value.(formulaArg), argsList.Back().Value.(formulaArg)
14048+
if value.Type == ArgError {
14049+
return value
14050+
}
14051+
if fmtText.Type == ArgError {
14052+
return fmtText
14053+
}
14054+
cellType := CellTypeNumber
14055+
if num := value.ToNumber(); num.Type != ArgNumber {
14056+
cellType = CellTypeSharedString
14057+
}
14058+
return newStringFormulaArg(format(value.Value(), fmtText.Value(), false, cellType, nil))
14059+
}
14060+
1403814061
// TEXTJOIN function joins together a series of supplied text strings into one
1403914062
// combined text string. The user can specify a delimiter to add between the
1404014063
// individual text items, if required. The syntax of the function is:

calc_test.go

+13
Original file line numberDiff line numberDiff line change
@@ -1834,6 +1834,15 @@ func TestCalcCellValue(t *testing.T) {
18341834
"=SUBSTITUTE(\"abab\",\"x\",\"X\",2)": "abab",
18351835
"=SUBSTITUTE(\"John is 5 years old\",\"John\",\"Jack\")": "Jack is 5 years old",
18361836
"=SUBSTITUTE(\"John is 5 years old\",\"5\",\"6\")": "John is 6 years old",
1837+
// TEXT
1838+
"=TEXT(\"07/07/2015\",\"mm/dd/yyyy\")": "07/07/2015",
1839+
"=TEXT(42192,\"mm/dd/yyyy\")": "07/07/2015",
1840+
"=TEXT(42192,\"mmm dd yyyy\")": "Jul 07 2015",
1841+
"=TEXT(0.75,\"hh:mm\")": "18:00",
1842+
"=TEXT(36.363636,\"0.00\")": "36.36",
1843+
"=TEXT(567.9,\"$#,##0.00\")": "$567.90",
1844+
"=TEXT(-5,\"+ $#,##0.00;- $#,##0.00;$0.00\")": "- $5.00",
1845+
"=TEXT(5,\"+ $#,##0.00;- $#,##0.00;$0.00\")": "+ $5.00",
18371846
// TEXTJOIN
18381847
"=TEXTJOIN(\"-\",TRUE,1,2,3,4)": "1-2-3-4",
18391848
"=TEXTJOIN(A4,TRUE,A1:B2)": "1040205",
@@ -3866,6 +3875,10 @@ func TestCalcCellValue(t *testing.T) {
38663875
"=SUBSTITUTE()": {"#VALUE!", "SUBSTITUTE requires 3 or 4 arguments"},
38673876
"=SUBSTITUTE(\"\",\"\",\"\",\"\")": {"#VALUE!", "strconv.ParseFloat: parsing \"\": invalid syntax"},
38683877
"=SUBSTITUTE(\"\",\"\",\"\",0)": {"#VALUE!", "instance_num should be > 0"},
3878+
// TEXT
3879+
"=TEXT()": {"#VALUE!", "TEXT requires 2 arguments"},
3880+
"=TEXT(NA(),\"\")": {"#N/A", "#N/A"},
3881+
"=TEXT(0,NA())": {"#N/A", "#N/A"},
38693882
// TEXTJOIN
38703883
"=TEXTJOIN()": {"#VALUE!", "TEXTJOIN requires at least 3 arguments"},
38713884
"=TEXTJOIN(\"\",\"\",1)": {"#VALUE!", "#VALUE!"},

cell.go

+2
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) {
590590
}
591591
}
592592
return f.formattedValue(c, raw, CellTypeSharedString)
593+
case "str":
594+
return c.V, nil
593595
case "inlineStr":
594596
if c.IS != nil {
595597
return f.formattedValue(&xlsxC{S: c.S, V: c.IS.String()}, raw, CellTypeInlineString)

drawing.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ import (
2525
func (f *File) prepareDrawing(ws *xlsxWorksheet, drawingID int, sheet, drawingXML string) (int, string) {
2626
sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
2727
if ws.Drawing != nil {
28-
// The worksheet already has a picture or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
29-
sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID)
28+
// The worksheet already has a picture or chart relationships, use the
29+
// relationships drawing ../drawings/drawing%d.xml or /xl/drawings/drawing%d.xml.
30+
sheetRelationshipsDrawingXML = strings.ReplaceAll(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "/xl/drawings/", "../drawings/")
3031
drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
3132
drawingXML = strings.ReplaceAll(sheetRelationshipsDrawingXML, "..", "xl")
3233
} else {
@@ -1247,9 +1248,11 @@ func (f *File) drawingParser(path string) (*xlsxWsDr, int, error) {
12471248
)
12481249
_, ok = f.Drawings.Load(path)
12491250
if !ok {
1250-
content := xlsxWsDr{}
1251-
content.A = NameSpaceDrawingML.Value
1252-
content.Xdr = NameSpaceDrawingMLSpreadSheet.Value
1251+
content := xlsxWsDr{
1252+
NS: NameSpaceDrawingMLSpreadSheet.Value,
1253+
Xdr: NameSpaceDrawingMLSpreadSheet.Value,
1254+
A: NameSpaceDrawingML.Value,
1255+
}
12531256
if _, ok = f.Pkg.Load(path); ok { // Append Model
12541257
decodeWsDr := decodeWsDr{}
12551258
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(path)))).

go.mod

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ require (
88
github.com/richardlehane/msoleps v1.0.3 // indirect
99
github.com/stretchr/testify v1.8.0
1010
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca
11-
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a
12-
golang.org/x/crypto v0.12.0
11+
github.com/xuri/nfp v0.0.0-20230918160701-e5a3f5b24785
12+
golang.org/x/crypto v0.13.0
1313
golang.org/x/image v0.11.0
14-
golang.org/x/net v0.14.0
15-
golang.org/x/text v0.12.0
14+
golang.org/x/net v0.15.0
15+
golang.org/x/text v0.13.0
1616
)

go.sum

+10-9
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK
1717
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
1818
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca h1:uvPMDVyP7PXMMioYdyPH+0O+Ta/UO1WFfNYMO3Wz0eg=
1919
github.com/xuri/efp v0.0.0-20230802181842-ad255f2331ca/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
20-
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a h1:Mw2VNrNNNjDtw68VsEj2+st+oCSn4Uz7vZw6TbhcV1o=
21-
github.com/xuri/nfp v0.0.0-20230819163627-dc951e3ffe1a/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
20+
github.com/xuri/nfp v0.0.0-20230918160701-e5a3f5b24785 h1:FG9hcK7lhf3w/Y2NRUKy/mopsH0Oy6P1rib1KWXAie0=
21+
github.com/xuri/nfp v0.0.0-20230918160701-e5a3f5b24785/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
2222
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
2323
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
2424
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
25-
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
26-
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
25+
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
26+
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
2727
golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo=
2828
golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8=
2929
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -33,8 +33,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
3333
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
3434
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
3535
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
36-
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
37-
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
36+
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
37+
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
3838
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
3939
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
4040
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -45,19 +45,20 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
4545
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4646
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4747
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
48-
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
48+
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4949
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
5050
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
5151
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
5252
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
53-
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
53+
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
5454
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
5555
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
5656
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
5757
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
5858
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
59-
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
6059
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
60+
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
61+
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
6162
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
6263
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
6364
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

numfmt.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -108,16 +108,16 @@ var (
108108
31: "yyyy\"\"m\"\"d\"\"",
109109
32: "hh\"\"mm\"\"",
110110
33: "hh\"\"mm\"\"ss\"\"",
111-
34: "上午/下午 hh\"\"mm\"\"",
112-
35: "上午/下午 hh\"\"mm\"\"ss\"\"",
111+
34: "上午/下午hh\"\"mm\"\"",
112+
35: "上午/下午hh\"\"mm\"\"ss\"\"",
113113
36: "[$-404]e/m/d",
114114
50: "[$-404]e/m/d",
115115
51: "[$-404]e\"\"m\"\"d\"\"",
116-
52: "上午/下午 hh\"\"mm\"\"",
117-
53: "上午/下午 hh\"\"mm\"\"ss\"\"",
116+
52: "上午/下午hh\"\"mm\"\"",
117+
53: "上午/下午hh\"\"mm\"\"ss\"\"",
118118
54: "[$-404]e\"\"m\"\"d\"\"",
119-
55: "上午/下午 hh\"\"mm\"\"",
120-
56: "上午/下午 hh\"\"mm\"\"ss\"\"",
119+
55: "上午/下午hh\"\"mm\"\"",
120+
56: "上午/下午hh\"\"mm\"\"ss\"\"",
121121
57: "[$-404]e/m/d",
122122
58: "[$-404]e\"\"m\"\"d\"\"",
123123
},
@@ -129,16 +129,16 @@ var (
129129
31: "yyyy\"\"m\"\"d\"\"",
130130
32: "h\"\"mm\"\"",
131131
33: "h\"\"mm\"\"ss\"\"",
132-
34: "上午/下午 h\"\"mm\"\"",
133-
35: "上午/下午 h\"\"mm\"\"ss\"\"",
132+
34: "上午/下午h\"\"mm\"\"",
133+
35: "上午/下午h\"\"mm\"\"ss\"\"",
134134
36: "yyyy\"\"m\"\"",
135135
50: "yyyy\"\"m\"\"",
136136
51: "m\"\"d\"\"",
137137
52: "yyyy\"\"m\"\"",
138138
53: "m\"\"d\"\"",
139139
54: "m\"\"d\"\"",
140-
55: "上午/下午 h\"\"mm\"\"",
141-
56: "上午/下午 h\"\"mm\"\"ss\"\"",
140+
55: "上午/下午h\"\"mm\"\"",
141+
56: "上午/下午h\"\"mm\"\"ss\"\"",
142142
57: "yyyy\"\"m\"\"",
143143
58: "m\"\"d\"\"",
144144
},

numfmt_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ func TestNumFmt(t *testing.T) {
7272
{"43528", "[$-111]MM/DD/YYYY", "43528"},
7373
{"43528", "[$US-409]MM/DD/YYYY", "US03/04/2019"},
7474
{"43543.586539351854", "AM/PM h h:mm", "PM 14 2:04"},
75+
{"45186", "DD.MM.YYYY", "17.09.2023"},
7576
{"text", "AM/PM h h:mm", "text"},
7677
{"43466.189571759256", "[$-404]aaa;@", "週二"},
7778
{"43466.189571759256", "[$-404]aaaa;@", "星期二"},

slicer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import (
3636
// Caption specifies the caption of the slicer, this setting is optional.
3737
//
3838
// Macro used for set macro for the slicer, the workbook extension should be
39-
// XLSM or XLTM
39+
// XLSM or XLTM.
4040
//
4141
// Width specifies the width of the slicer, this setting is optional.
4242
//

0 commit comments

Comments
 (0)