summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcharles.deng <cilendeng@gmail.com>2022-10-10 00:11:18 +0800
committerGitHub <noreply@github.com>2022-10-10 00:11:18 +0800
commit2f5704b114d033e81725f18459f9293a9adfee1e (patch)
tree0390794673f81669ce8a5d20571c2035c4691586
parentb1e776ee33ec78b7f6c2a0de8109009963dea521 (diff)
Stream writer support to set inline rich text cell (#1121)
Co-authored-by: zhengchao.deng <zhengchao.deng@meican.com>
-rw-r--r--cell.go42
-rw-r--r--excelize.go12
-rw-r--r--stream.go21
-rw-r--r--stream_test.go9
-rw-r--r--xmlSharedStrings.go5
-rw-r--r--xmlWorksheet.go17
6 files changed, 67 insertions, 39 deletions
diff --git a/cell.go b/cell.go
index 6beb3b2..80eb035 100644
--- a/cell.go
+++ b/cell.go
@@ -885,6 +885,28 @@ func newRpr(fnt *Font) *xlsxRPr {
return &rpr
}
+// setRichText provides a function to set rich text of a cell.
+func setRichText(runs []RichTextRun) ([]xlsxR, error) {
+ var (
+ textRuns []xlsxR
+ totalCellChars int
+ )
+ for _, textRun := range runs {
+ totalCellChars += len(textRun.Text)
+ if totalCellChars > TotalCellChars {
+ return textRuns, ErrCellCharsLength
+ }
+ run := xlsxR{T: &xlsxT{}}
+ _, run.T.Val, run.T.Space = setCellStr(textRun.Text)
+ fnt := textRun.Font
+ if fnt != nil {
+ run.RPr = newRpr(fnt)
+ }
+ textRuns = append(textRuns, run)
+ }
+ return textRuns, nil
+}
+
// SetCellRichText provides a function to set cell with rich text by given
// worksheet. For example, set rich text on the A1 cell of the worksheet named
// Sheet1:
@@ -1016,24 +1038,10 @@ func (f *File) SetCellRichText(sheet, cell string, runs []RichTextRun) error {
return err
}
c.S = f.prepareCellStyle(ws, col, row, c.S)
- si := xlsxSI{}
- sst := f.sharedStringsReader()
- var textRuns []xlsxR
- totalCellChars := 0
- for _, textRun := range runs {
- totalCellChars += len(textRun.Text)
- if totalCellChars > TotalCellChars {
- return ErrCellCharsLength
- }
- run := xlsxR{T: &xlsxT{}}
- _, run.T.Val, run.T.Space = setCellStr(textRun.Text)
- fnt := textRun.Font
- if fnt != nil {
- run.RPr = newRpr(fnt)
- }
- textRuns = append(textRuns, run)
+ si, sst := xlsxSI{}, f.sharedStringsReader()
+ if si.R, err = setRichText(runs); err != nil {
+ return err
}
- si.R = textRuns
for idx, strItem := range sst.SI {
if reflect.DeepEqual(strItem, si) {
c.T, c.V = "s", strconv.Itoa(idx)
diff --git a/excelize.go b/excelize.go
index ec7485b..94d1088 100644
--- a/excelize.go
+++ b/excelize.go
@@ -444,12 +444,12 @@ func (f *File) UpdateLinkedValue() error {
// AddVBAProject provides the method to add vbaProject.bin file which contains
// functions and/or macros. The file extension should be .xlsm. For example:
//
-// codeName := "Sheet1"
-// if err := f.SetSheetProps("Sheet1", &excelize.SheetPropsOptions{
-// CodeName: &codeName,
-// }); err != nil {
-// fmt.Println(err)
-// }
+// codeName := "Sheet1"
+// if err := f.SetSheetProps("Sheet1", &excelize.SheetPropsOptions{
+// CodeName: &codeName,
+// }); err != nil {
+// fmt.Println(err)
+// }
// if err := f.AddVBAProject("vbaProject.bin"); err != nil {
// fmt.Println(err)
// }
diff --git a/stream.go b/stream.go
index b99730d..66c0fda 100644
--- a/stream.go
+++ b/stream.go
@@ -56,7 +56,14 @@ type StreamWriter struct {
// if err != nil {
// fmt.Println(err)
// }
-// if err := streamWriter.SetRow("A1", []interface{}{excelize.Cell{StyleID: styleID, Value: "Data"}},
+// if err := streamWriter.SetRow("A1",
+// []interface{}{
+// excelize.Cell{StyleID: styleID, Value: "Data"},
+// []excelize.RichTextRun{
+// {Text: "Rich ", Font: &excelize.Font{Color: "2354e8"}},
+// {Text: "Text", Font: &excelize.Font{Color: "e83723"}},
+// },
+// },
// excelize.RowOpts{Height: 45, Hidden: false}); err != nil {
// fmt.Println(err)
// }
@@ -433,7 +440,8 @@ func setCellFormula(c *xlsxC, formula string) {
}
// setCellValFunc provides a function to set value of a cell.
-func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) (err error) {
+func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) error {
+ var err error
switch val := val.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
err = setCellIntFunc(c, val)
@@ -462,6 +470,9 @@ func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) (err error) {
c.T, c.V = setCellBool(val)
case nil:
c.T, c.V, c.XMLSpace = setCellStr("")
+ case []RichTextRun:
+ c.T, c.IS = "inlineStr", &xlsxSI{}
+ c.IS.R, err = setRichText(val)
default:
c.T, c.V, c.XMLSpace = setCellStr(fmt.Sprint(val))
}
@@ -519,6 +530,12 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
_ = xml.EscapeText(buf, []byte(c.V))
_, _ = buf.WriteString(`</v>`)
}
+ if c.IS != nil {
+ is, _ := xml.Marshal(c.IS.R)
+ _, _ = buf.WriteString(`<is>`)
+ _, _ = buf.Write(is)
+ _, _ = buf.WriteString(`</is>`)
+ }
_, _ = buf.WriteString(`</c>`)
}
diff --git a/stream_test.go b/stream_test.go
index 80875c7..3c2cc69 100644
--- a/stream_test.go
+++ b/stream_test.go
@@ -52,11 +52,14 @@ func TestStreamWriter(t *testing.T) {
row[0] = []byte("Word")
assert.NoError(t, streamWriter.SetRow("A3", row))
- // Test set cell with style.
+ // Test set cell with style and rich text.
styleID, err := file.NewStyle(&Style{Font: &Font{Color: "#777777"}})
assert.NoError(t, err)
assert.NoError(t, streamWriter.SetRow("A4", []interface{}{Cell{StyleID: styleID}, Cell{Formula: "SUM(A10,B10)"}}, RowOpts{Height: 45, StyleID: styleID}))
- assert.NoError(t, streamWriter.SetRow("A5", []interface{}{&Cell{StyleID: styleID, Value: "cell"}, &Cell{Formula: "SUM(A10,B10)"}}))
+ assert.NoError(t, streamWriter.SetRow("A5", []interface{}{&Cell{StyleID: styleID, Value: "cell"}, &Cell{Formula: "SUM(A10,B10)"}, []RichTextRun{
+ {Text: "Rich ", Font: &Font{Color: "2354e8"}},
+ {Text: "Text", Font: &Font{Color: "e83723"}},
+ }}))
assert.NoError(t, streamWriter.SetRow("A6", []interface{}{time.Now()}))
assert.NoError(t, streamWriter.SetRow("A7", nil, RowOpts{Height: 20, Hidden: true, StyleID: styleID}))
assert.EqualError(t, streamWriter.SetRow("A7", nil, RowOpts{Height: MaxRowHeight + 1}), ErrMaxRowHeight.Error())
@@ -128,7 +131,7 @@ func TestStreamWriter(t *testing.T) {
cells += len(row)
}
assert.NoError(t, rows.Close())
- assert.Equal(t, 2559558, cells)
+ assert.Equal(t, 2559559, cells)
// Save spreadsheet with password.
assert.NoError(t, file.SaveAs(filepath.Join("test", "EncryptionTestStreamWriter.xlsx"), Options{Password: "password"}))
assert.NoError(t, file.Close())
diff --git a/xmlSharedStrings.go b/xmlSharedStrings.go
index 683105e..3249eca 100644
--- a/xmlSharedStrings.go
+++ b/xmlSharedStrings.go
@@ -46,8 +46,9 @@ type xlsxSI struct {
// 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 *xlsxT `xml:"t"`
+ XMLName xml.Name `xml:"r"`
+ RPr *xlsxRPr `xml:"rPr"`
+ T *xlsxT `xml:"t"`
}
// xlsxT directly maps the t element in the run properties.
diff --git a/xmlWorksheet.go b/xmlWorksheet.go
index e55406c..24f5e4e 100644
--- a/xmlWorksheet.go
+++ b/xmlWorksheet.go
@@ -466,15 +466,14 @@ type xlsxC struct {
XMLName xml.Name `xml:"c"`
XMLSpace xml.Attr `xml:"space,attr,omitempty"`
R string `xml:"r,attr,omitempty"` // Cell ID, e.g. A1
- S int `xml:"s,attr,omitempty"` // Style reference.
- // Str string `xml:"str,attr,omitempty"` // Style reference.
- T string `xml:"t,attr,omitempty"` // Type.
- Cm *uint `xml:"cm,attr,omitempty"` //
- Vm *uint `xml:"vm,attr,omitempty"` //
- Ph *bool `xml:"ph,attr,omitempty"` //
- F *xlsxF `xml:"f,omitempty"` // Formula
- V string `xml:"v,omitempty"` // Value
- IS *xlsxSI `xml:"is"`
+ S int `xml:"s,attr,omitempty"` // Style reference
+ T string `xml:"t,attr,omitempty"` // Type
+ Cm *uint `xml:"cm,attr"`
+ Vm *uint `xml:"vm,attr"`
+ Ph *bool `xml:"ph,attr"`
+ F *xlsxF `xml:"f"` // Formula
+ V string `xml:"v,omitempty"` // Value
+ IS *xlsxSI `xml:"is"`
}
// xlsxF represents a formula for the cell. The formula expression is