Skip to content

Commit

Permalink
feat: add NumFmtIdToCodeHook support user defined numFmtId to code ma…
Browse files Browse the repository at this point in the history
…pping
  • Loading branch information
fudali113 committed Apr 19, 2023
1 parent fb6ce60 commit 845d6d6
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 5 deletions.
4 changes: 4 additions & 0 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -1350,6 +1350,10 @@ func (f *File) formattedValue(c *xlsxC, raw bool, cellType CellType) (string, er
if wb != nil && wb.WorkbookPr != nil {
date1904 = wb.WorkbookPr.Date1904
}
numFmtCode, ok := runNumFmtIdToCodeHook(f, numFmtID)
if ok {
return format(c.V, numFmtCode, date1904, cellType), err
}
if ok := builtInNumFmtFunc[numFmtID]; ok != nil {
return ok(c.V, builtInNumFmt[numFmtID], date1904, cellType), err
}
Expand Down
69 changes: 69 additions & 0 deletions cell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,75 @@ func TestFormattedValue(t *testing.T) {
}
}

func TestFormattedValueWithWpsFile(t *testing.T) {

testWpsIdCodeMap := map[int]string{
14: "yyyy/m/d",
31: "yyyy\"\"m\"\"d\"\"",
}

testWpsIdCodeMapHook := func(info NumFmtIdToCodeHookInfo, numFmtId int) (code string, ok bool) {
isWps := false
allAttrs:
for _, attrs := range info.XmlAttr {
for _, attr := range attrs {
if strings.Contains(attr.Value, "wps") {
isWps = true
break allAttrs
}
}
}
if !isWps {
return
}
code, ok = testWpsIdCodeMap[numFmtId]
return
}

testCases := []struct {
name string
cellName string
v string
numFmtIdCodeHook NumFmtIdToCodeHook
}{
{
name: "yy/m/d cell",
cellName: "A1",
v: "23/1/1",
},
{
name: "yyyy/m/d cell",
cellName: "A2",
v: "01-01-23",
},
{
name: "yyyy/m/d cell has hook",
cellName: "A2",
v: "2023/1/1",
numFmtIdCodeHook: testWpsIdCodeMapHook,
},
{
name: "yyyy\"\"m\"\"d\"\" cell",
cellName: "A3",
v: "2023年1月1日",
numFmtIdCodeHook: testWpsIdCodeMapHook,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "NumFmtCases.xlsx"), Options{
NumFmtIdToCodeHook: testCase.numFmtIdCodeHook,
})
if !assert.NoError(t, err) {
t.FailNow()
}
val, err := f.GetCellValue("Sheet1", testCase.cellName)
assert.NoError(t, err)
assert.Equal(t, testCase.v, val)
})
}
}

func TestFormattedValueNilXfs(t *testing.T) {
// Set the CellXfs to nil and verify that the formattedValue function does not crash
f := NewFile()
Expand Down
14 changes: 9 additions & 5 deletions excelize.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,16 @@ type charsetTranscoderFn func(charset string, input io.Reader) (rdr io.Reader, e
// temporary directory when the file size is over this value, this value
// should be less than or equal to UnzipSizeLimit, the default value is
// 16MB.
//
// NumFmtIdToCodeHook User-defined mapping function for numFmtId to numFmtCode
// if NumFmtIdToCodeHook function is nil will use default mapping
type Options struct {
MaxCalcIterations uint
Password string
RawCellValue bool
UnzipSizeLimit int64
UnzipXMLSizeLimit int64
MaxCalcIterations uint
Password string
RawCellValue bool
UnzipSizeLimit int64
UnzipXMLSizeLimit int64
NumFmtIdToCodeHook NumFmtIdToCodeHook
}

// OpenFile take the name of an spreadsheet file and returns a populated
Expand Down
23 changes: 23 additions & 0 deletions hooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package excelize

import "encoding/xml"

type NumFmtIdToCodeHookInfo struct {
XmlAttr map[string][]xml.Attr
NumFmt []*xlsxNumFmt
}

// NumFmtIdToCodeHook User-defined mapping function for numFmtId to numFmtCode
// if return ok is false, will use default mapping
type NumFmtIdToCodeHook func(info NumFmtIdToCodeHookInfo, numFmtId int) (numFmtCode string, ok bool)

func runNumFmtIdToCodeHook(file *File, numFmtId int) (numFmtCode string, ok bool) {
if file == nil || file.options == nil || file.options.NumFmtIdToCodeHook == nil {
return
}
hookInfo := NumFmtIdToCodeHookInfo{XmlAttr: file.xmlAttr}
if file.Styles != nil && file.Styles.NumFmts != nil {
hookInfo.NumFmt = file.Styles.NumFmts.NumFmt
}
return file.options.NumFmtIdToCodeHook(NumFmtIdToCodeHookInfo{XmlAttr: file.xmlAttr}, numFmtId)
}
Binary file added test/NumFmtCases.xlsx
Binary file not shown.

0 comments on commit 845d6d6

Please sign in to comment.