forked from p30928647/excelize
Stream writer support to set inline rich text cell (#1121)
Co-authored-by: zhengchao.deng <zhengchao.deng@meican.com>
This commit is contained in:
parent
b1e776ee33
commit
2f5704b114
42
cell.go
42
cell.go
|
@ -885,6 +885,28 @@ func newRpr(fnt *Font) *xlsxRPr {
|
||||||
return &rpr
|
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
|
// 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
|
// worksheet. For example, set rich text on the A1 cell of the worksheet named
|
||||||
// Sheet1:
|
// Sheet1:
|
||||||
|
@ -1016,24 +1038,10 @@ func (f *File) SetCellRichText(sheet, cell string, runs []RichTextRun) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
c.S = f.prepareCellStyle(ws, col, row, c.S)
|
||||||
si := xlsxSI{}
|
si, sst := xlsxSI{}, f.sharedStringsReader()
|
||||||
sst := f.sharedStringsReader()
|
if si.R, err = setRichText(runs); err != nil {
|
||||||
var textRuns []xlsxR
|
return err
|
||||||
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.R = textRuns
|
|
||||||
for idx, strItem := range sst.SI {
|
for idx, strItem := range sst.SI {
|
||||||
if reflect.DeepEqual(strItem, si) {
|
if reflect.DeepEqual(strItem, si) {
|
||||||
c.T, c.V = "s", strconv.Itoa(idx)
|
c.T, c.V = "s", strconv.Itoa(idx)
|
||||||
|
|
12
excelize.go
12
excelize.go
|
@ -444,12 +444,12 @@ func (f *File) UpdateLinkedValue() error {
|
||||||
// AddVBAProject provides the method to add vbaProject.bin file which contains
|
// AddVBAProject provides the method to add vbaProject.bin file which contains
|
||||||
// functions and/or macros. The file extension should be .xlsm. For example:
|
// functions and/or macros. The file extension should be .xlsm. For example:
|
||||||
//
|
//
|
||||||
// codeName := "Sheet1"
|
// codeName := "Sheet1"
|
||||||
// if err := f.SetSheetProps("Sheet1", &excelize.SheetPropsOptions{
|
// if err := f.SetSheetProps("Sheet1", &excelize.SheetPropsOptions{
|
||||||
// CodeName: &codeName,
|
// CodeName: &codeName,
|
||||||
// }); err != nil {
|
// }); err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
// if err := f.AddVBAProject("vbaProject.bin"); err != nil {
|
// if err := f.AddVBAProject("vbaProject.bin"); err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
|
|
21
stream.go
21
stream.go
|
@ -56,7 +56,14 @@ type StreamWriter struct {
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// 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 {
|
// excelize.RowOpts{Height: 45, Hidden: false}); err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// }
|
// }
|
||||||
|
@ -433,7 +440,8 @@ func setCellFormula(c *xlsxC, formula string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// setCellValFunc provides a function to set value of a cell.
|
// 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) {
|
switch val := val.(type) {
|
||||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||||
err = setCellIntFunc(c, val)
|
err = setCellIntFunc(c, val)
|
||||||
|
@ -462,6 +470,9 @@ func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) (err error) {
|
||||||
c.T, c.V = setCellBool(val)
|
c.T, c.V = setCellBool(val)
|
||||||
case nil:
|
case nil:
|
||||||
c.T, c.V, c.XMLSpace = setCellStr("")
|
c.T, c.V, c.XMLSpace = setCellStr("")
|
||||||
|
case []RichTextRun:
|
||||||
|
c.T, c.IS = "inlineStr", &xlsxSI{}
|
||||||
|
c.IS.R, err = setRichText(val)
|
||||||
default:
|
default:
|
||||||
c.T, c.V, c.XMLSpace = setCellStr(fmt.Sprint(val))
|
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))
|
_ = xml.EscapeText(buf, []byte(c.V))
|
||||||
_, _ = buf.WriteString(`</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>`)
|
_, _ = buf.WriteString(`</c>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,11 +52,14 @@ func TestStreamWriter(t *testing.T) {
|
||||||
row[0] = []byte("Word")
|
row[0] = []byte("Word")
|
||||||
assert.NoError(t, streamWriter.SetRow("A3", row))
|
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"}})
|
styleID, err := file.NewStyle(&Style{Font: &Font{Color: "#777777"}})
|
||||||
assert.NoError(t, err)
|
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("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("A6", []interface{}{time.Now()}))
|
||||||
assert.NoError(t, streamWriter.SetRow("A7", nil, RowOpts{Height: 20, Hidden: true, StyleID: styleID}))
|
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())
|
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)
|
cells += len(row)
|
||||||
}
|
}
|
||||||
assert.NoError(t, rows.Close())
|
assert.NoError(t, rows.Close())
|
||||||
assert.Equal(t, 2559558, cells)
|
assert.Equal(t, 2559559, cells)
|
||||||
// Save spreadsheet with password.
|
// Save spreadsheet with password.
|
||||||
assert.NoError(t, file.SaveAs(filepath.Join("test", "EncryptionTestStreamWriter.xlsx"), Options{Password: "password"}))
|
assert.NoError(t, file.SaveAs(filepath.Join("test", "EncryptionTestStreamWriter.xlsx"), Options{Password: "password"}))
|
||||||
assert.NoError(t, file.Close())
|
assert.NoError(t, file.Close())
|
||||||
|
|
|
@ -46,8 +46,9 @@ type xlsxSI struct {
|
||||||
// properties are defined in the rPr element, and the text displayed to the
|
// properties are defined in the rPr element, and the text displayed to the
|
||||||
// user is defined in the Text (t) element.
|
// user is defined in the Text (t) element.
|
||||||
type xlsxR struct {
|
type xlsxR struct {
|
||||||
RPr *xlsxRPr `xml:"rPr"`
|
XMLName xml.Name `xml:"r"`
|
||||||
T *xlsxT `xml:"t"`
|
RPr *xlsxRPr `xml:"rPr"`
|
||||||
|
T *xlsxT `xml:"t"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxT directly maps the t element in the run properties.
|
// xlsxT directly maps the t element in the run properties.
|
||||||
|
|
|
@ -466,15 +466,14 @@ type xlsxC struct {
|
||||||
XMLName xml.Name `xml:"c"`
|
XMLName xml.Name `xml:"c"`
|
||||||
XMLSpace xml.Attr `xml:"space,attr,omitempty"`
|
XMLSpace xml.Attr `xml:"space,attr,omitempty"`
|
||||||
R string `xml:"r,attr,omitempty"` // Cell ID, e.g. A1
|
R string `xml:"r,attr,omitempty"` // Cell ID, e.g. A1
|
||||||
S int `xml:"s,attr,omitempty"` // Style reference.
|
S int `xml:"s,attr,omitempty"` // Style reference
|
||||||
// Str string `xml:"str,attr,omitempty"` // Style reference.
|
T string `xml:"t,attr,omitempty"` // Type
|
||||||
T string `xml:"t,attr,omitempty"` // Type.
|
Cm *uint `xml:"cm,attr"`
|
||||||
Cm *uint `xml:"cm,attr,omitempty"` //
|
Vm *uint `xml:"vm,attr"`
|
||||||
Vm *uint `xml:"vm,attr,omitempty"` //
|
Ph *bool `xml:"ph,attr"`
|
||||||
Ph *bool `xml:"ph,attr,omitempty"` //
|
F *xlsxF `xml:"f"` // Formula
|
||||||
F *xlsxF `xml:"f,omitempty"` // Formula
|
V string `xml:"v,omitempty"` // Value
|
||||||
V string `xml:"v,omitempty"` // Value
|
IS *xlsxSI `xml:"is"`
|
||||||
IS *xlsxSI `xml:"is"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxF represents a formula for the cell. The formula expression is
|
// xlsxF represents a formula for the cell. The formula expression is
|
||||||
|
|
Loading…
Reference in New Issue