forked from p30928647/excelize
This closes #1519, escape XML characters after checking cell value length
This commit is contained in:
parent
635ec33576
commit
17c029494a
17
cell.go
17
cell.go
|
@ -451,17 +451,22 @@ func (f *File) setSharedString(val string) (int, error) {
|
||||||
sst.Count++
|
sst.Count++
|
||||||
sst.UniqueCount++
|
sst.UniqueCount++
|
||||||
t := xlsxT{Val: val}
|
t := xlsxT{Val: val}
|
||||||
val, t.Space = trimCellValue(val)
|
val, t.Space = trimCellValue(val, false)
|
||||||
sst.SI = append(sst.SI, xlsxSI{T: &t})
|
sst.SI = append(sst.SI, xlsxSI{T: &t})
|
||||||
f.sharedStringsMap[val] = sst.UniqueCount - 1
|
f.sharedStringsMap[val] = sst.UniqueCount - 1
|
||||||
return sst.UniqueCount - 1, nil
|
return sst.UniqueCount - 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// trimCellValue provides a function to set string type to cell.
|
// trimCellValue provides a function to set string type to cell.
|
||||||
func trimCellValue(value string) (v string, ns xml.Attr) {
|
func trimCellValue(value string, escape bool) (v string, ns xml.Attr) {
|
||||||
if utf8.RuneCountInString(value) > TotalCellChars {
|
if utf8.RuneCountInString(value) > TotalCellChars {
|
||||||
value = string([]rune(value)[:TotalCellChars])
|
value = string([]rune(value)[:TotalCellChars])
|
||||||
}
|
}
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
if escape {
|
||||||
|
_ = xml.EscapeText(buf, []byte(value))
|
||||||
|
value = buf.String()
|
||||||
|
}
|
||||||
if len(value) > 0 {
|
if len(value) > 0 {
|
||||||
prefix, suffix := value[0], value[len(value)-1]
|
prefix, suffix := value[0], value[len(value)-1]
|
||||||
for _, ascii := range []byte{9, 10, 13, 32} {
|
for _, ascii := range []byte{9, 10, 13, 32} {
|
||||||
|
@ -492,15 +497,13 @@ func (c *xlsxC) setCellValue(val string) {
|
||||||
// string.
|
// string.
|
||||||
func (c *xlsxC) setInlineStr(val string) {
|
func (c *xlsxC) setInlineStr(val string) {
|
||||||
c.T, c.V, c.IS = "inlineStr", "", &xlsxSI{T: &xlsxT{}}
|
c.T, c.V, c.IS = "inlineStr", "", &xlsxSI{T: &xlsxT{}}
|
||||||
buf := &bytes.Buffer{}
|
c.IS.T.Val, c.IS.T.Space = trimCellValue(val, true)
|
||||||
_ = xml.EscapeText(buf, []byte(val))
|
|
||||||
c.IS.T.Val, c.IS.T.Space = trimCellValue(buf.String())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// setStr set cell data type and value which containing a formula string.
|
// setStr set cell data type and value which containing a formula string.
|
||||||
func (c *xlsxC) setStr(val string) {
|
func (c *xlsxC) setStr(val string) {
|
||||||
c.T, c.IS = "str", nil
|
c.T, c.IS = "str", nil
|
||||||
c.V, c.XMLSpace = trimCellValue(val)
|
c.V, c.XMLSpace = trimCellValue(val, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCellDate parse cell value which containing a boolean.
|
// getCellDate parse cell value which containing a boolean.
|
||||||
|
@ -1031,7 +1034,7 @@ func setRichText(runs []RichTextRun) ([]xlsxR, error) {
|
||||||
return textRuns, ErrCellCharsLength
|
return textRuns, ErrCellCharsLength
|
||||||
}
|
}
|
||||||
run := xlsxR{T: &xlsxT{}}
|
run := xlsxR{T: &xlsxT{}}
|
||||||
run.T.Val, run.T.Space = trimCellValue(textRun.Text)
|
run.T.Val, run.T.Space = trimCellValue(textRun.Text, false)
|
||||||
fnt := textRun.Font
|
fnt := textRun.Font
|
||||||
if fnt != nil {
|
if fnt != nil {
|
||||||
run.RPr = newRpr(fnt)
|
run.RPr = newRpr(fnt)
|
||||||
|
|
34
cell_test.go
34
cell_test.go
|
@ -177,16 +177,36 @@ func TestSetCellFloat(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetCellValuesMultiByte(t *testing.T) {
|
func TestSetCellValuesMultiByte(t *testing.T) {
|
||||||
value := strings.Repeat("\u042B", TotalCellChars+1)
|
|
||||||
|
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
err := f.SetCellValue("Sheet1", "A1", value)
|
row := []interface{}{
|
||||||
|
// Test set cell value with multi byte characters value
|
||||||
|
strings.Repeat("\u4E00", TotalCellChars+1),
|
||||||
|
// Test set cell value with XML escape characters
|
||||||
|
strings.Repeat("<>", TotalCellChars/2),
|
||||||
|
strings.Repeat(">", TotalCellChars-1),
|
||||||
|
strings.Repeat(">", TotalCellChars+1),
|
||||||
|
}
|
||||||
|
assert.NoError(t, f.SetSheetRow("Sheet1", "A1", &row))
|
||||||
|
// Test set cell value with XML escape characters in stream writer
|
||||||
|
_, err := f.NewSheet("Sheet2")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
streamWriter, err := f.NewStreamWriter("Sheet2")
|
||||||
v, err := f.GetCellValue("Sheet1", "A1")
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEqual(t, value, v)
|
assert.NoError(t, streamWriter.SetRow("A1", row))
|
||||||
assert.Equal(t, TotalCellChars, len([]rune(v)))
|
assert.NoError(t, streamWriter.Flush())
|
||||||
|
for _, sheetName := range []string{"Sheet1", "Sheet2"} {
|
||||||
|
for cell, expected := range map[string]int{
|
||||||
|
"A1": TotalCellChars,
|
||||||
|
"B1": TotalCellChars - 1,
|
||||||
|
"C1": TotalCellChars - 1,
|
||||||
|
"D1": TotalCellChars,
|
||||||
|
} {
|
||||||
|
result, err := f.GetCellValue(sheetName, cell)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, []rune(result), expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetCellValuesMultiByte.xlsx")))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetCellValue(t *testing.T) {
|
func TestSetCellValue(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue