From f44153ea4679247070d6f1e31bb0934a10bebb31 Mon Sep 17 00:00:00 2001
From: xuri <xuri.me@gmail.com>
Date: Tue, 25 Oct 2022 10:24:45 +0800
Subject: This closes #1377, stream writer writes inline string type for string
 cell value

- Add `CellTypeFormula`, `CellTypeInlineString`, `CellTypeSharedString` and remove `CellTypeString` in `CellType` enumeration
- Unit tests updated
---
 calc_test.go  |   4 +-
 cell.go       | 151 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 cell_test.go  |  23 ++++-----
 col_test.go   |   6 +--
 rows.go       |  77 ------------------------------
 rows_test.go  |   4 +-
 sheet_test.go |   6 +--
 stream.go     |  38 ++++++++++-----
 8 files changed, 172 insertions(+), 137 deletions(-)

diff --git a/calc_test.go b/calc_test.go
index 1a8b8c6..5d61712 100644
--- a/calc_test.go
+++ b/calc_test.go
@@ -5223,8 +5223,8 @@ func TestCalcXLOOKUP(t *testing.T) {
 		"=XLOOKUP(29,C2:H2,C3:H3,NA(),-1,1)":  "D3",
 	}
 	for formula, expected := range formulaList {
-		assert.NoError(t, f.SetCellFormula("Sheet1", "D3", formula))
-		result, err := f.CalcCellValue("Sheet1", "D3")
+		assert.NoError(t, f.SetCellFormula("Sheet1", "D4", formula))
+		result, err := f.CalcCellValue("Sheet1", "D4")
 		assert.NoError(t, err, formula)
 		assert.Equal(t, expected, result, formula)
 	}
diff --git a/cell.go b/cell.go
index 3fcbb7b..6ed7f48 100644
--- a/cell.go
+++ b/cell.go
@@ -30,8 +30,10 @@ const (
 	CellTypeBool
 	CellTypeDate
 	CellTypeError
+	CellTypeFormula
+	CellTypeInlineString
 	CellTypeNumber
-	CellTypeString
+	CellTypeSharedString
 )
 
 const (
@@ -51,9 +53,9 @@ var cellTypes = map[string]CellType{
 	"d":         CellTypeDate,
 	"n":         CellTypeNumber,
 	"e":         CellTypeError,
-	"s":         CellTypeString,
-	"str":       CellTypeString,
-	"inlineStr": CellTypeString,
+	"s":         CellTypeSharedString,
+	"str":       CellTypeFormula,
+	"inlineStr": CellTypeInlineString,
 }
 
 // GetCellValue provides a function to get formatted value from cell by given
@@ -235,8 +237,7 @@ func (f *File) setCellTimeFunc(sheet, cell string, value time.Time) error {
 		date1904 = wb.WorkbookPr.Date1904
 	}
 	var isNum bool
-	c.T, c.V, isNum, err = setCellTime(value, date1904)
-	if err != nil {
+	if isNum, err = c.setCellTime(value, date1904); err != nil {
 		return err
 	}
 	if isNum {
@@ -247,7 +248,7 @@ func (f *File) setCellTimeFunc(sheet, cell string, value time.Time) error {
 
 // setCellTime prepares cell type and Excel time by given Go time.Time type
 // timestamp.
-func setCellTime(value time.Time, date1904 bool) (t string, b string, isNum bool, err error) {
+func (c *xlsxC) setCellTime(value time.Time, date1904 bool) (isNum bool, err error) {
 	var excelTime float64
 	_, offset := value.In(value.Location()).Zone()
 	value = value.Add(time.Duration(offset) * time.Second)
@@ -256,9 +257,9 @@ func setCellTime(value time.Time, date1904 bool) (t string, b string, isNum bool
 	}
 	isNum = excelTime > 0
 	if isNum {
-		t, b = setCellDefault(strconv.FormatFloat(excelTime, 'f', -1, 64))
+		c.setCellDefault(strconv.FormatFloat(excelTime, 'f', -1, 64))
 	} else {
-		t, b = setCellDefault(value.Format(time.RFC3339Nano))
+		c.setCellDefault(value.Format(time.RFC3339Nano))
 	}
 	return
 }
@@ -435,14 +436,14 @@ func (f *File) setSharedString(val string) (int, error) {
 	sst.Count++
 	sst.UniqueCount++
 	t := xlsxT{Val: val}
-	_, val, t.Space = setCellStr(val)
+	val, t.Space = trimCellValue(val)
 	sst.SI = append(sst.SI, xlsxSI{T: &t})
 	f.sharedStringsMap[val] = sst.UniqueCount - 1
 	return sst.UniqueCount - 1, nil
 }
 
-// setCellStr provides a function to set string type to cell.
-func setCellStr(value string) (t string, v string, ns xml.Attr) {
+// trimCellValue provides a function to set string type to cell.
+func trimCellValue(value string) (v string, ns xml.Attr) {
 	if len(value) > TotalCellChars {
 		value = value[:TotalCellChars]
 	}
@@ -458,10 +459,117 @@ func setCellStr(value string) (t string, v string, ns xml.Attr) {
 			}
 		}
 	}
-	t, v = "str", bstrMarshal(value)
+	v = bstrMarshal(value)
 	return
 }
 
+// setCellValue set cell data type and value for (inline) rich string cell or
+// formula cell.
+func (c *xlsxC) setCellValue(val string) {
+	if c.F != nil {
+		c.setStr(val)
+		return
+	}
+	c.setInlineStr(val)
+}
+
+// setInlineStr set cell data type and value which containing an (inline) rich
+// string.
+func (c *xlsxC) setInlineStr(val string) {
+	c.T, c.V, c.IS = "inlineStr", "", &xlsxSI{T: &xlsxT{}}
+	c.IS.T.Val, c.IS.T.Space = trimCellValue(val)
+}
+
+// setStr set cell data type and value which containing a formula string.
+func (c *xlsxC) setStr(val string) {
+	c.T, c.IS = "str", nil
+	c.V, c.XMLSpace = trimCellValue(val)
+}
+
+// getCellDate parse cell value which containing a boolean.
+func (c *xlsxC) getCellBool(f *File, raw bool) (string, error) {
+	if !raw {
+		if c.V == "1" {
+			return "TRUE", nil
+		}
+		if c.V == "0" {
+			return "FALSE", nil
+		}
+	}
+	return f.formattedValue(c.S, c.V, raw), nil
+}
+
+// setCellDefault prepares cell type and string type cell value by a given
+// string.
+func (c *xlsxC) setCellDefault(value string) {
+	if ok, _, _ := isNumeric(value); !ok {
+		c.setInlineStr(value)
+		c.IS.T.Val = value
+		return
+	}
+	c.V = value
+}
+
+// getCellDate parse cell value which contains a date in the ISO 8601 format.
+func (c *xlsxC) getCellDate(f *File, raw bool) (string, error) {
+	if !raw {
+		layout := "20060102T150405.999"
+		if strings.HasSuffix(c.V, "Z") {
+			layout = "20060102T150405Z"
+			if strings.Contains(c.V, "-") {
+				layout = "2006-01-02T15:04:05Z"
+			}
+		} else if strings.Contains(c.V, "-") {
+			layout = "2006-01-02 15:04:05Z"
+		}
+		if timestamp, err := time.Parse(layout, strings.ReplaceAll(c.V, ",", ".")); err == nil {
+			excelTime, _ := timeToExcelTime(timestamp, false)
+			c.V = strconv.FormatFloat(excelTime, 'G', 15, 64)
+		}
+	}
+	return f.formattedValue(c.S, c.V, raw), nil
+}
+
+// getValueFrom return a value from a column/row cell, this function is
+// intended to be used with for range on rows an argument with the spreadsheet
+// opened file.
+func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) {
+	f.Lock()
+	defer f.Unlock()
+	switch c.T {
+	case "b":
+		return c.getCellBool(f, raw)
+	case "d":
+		return c.getCellDate(f, raw)
+	case "s":
+		if c.V != "" {
+			xlsxSI := 0
+			xlsxSI, _ = strconv.Atoi(c.V)
+			if _, ok := f.tempFiles.Load(defaultXMLPathSharedStrings); ok {
+				return f.formattedValue(c.S, f.getFromStringItem(xlsxSI), raw), nil
+			}
+			if len(d.SI) > xlsxSI {
+				return f.formattedValue(c.S, d.SI[xlsxSI].String(), raw), nil
+			}
+		}
+		return f.formattedValue(c.S, c.V, raw), nil
+	case "inlineStr":
+		if c.IS != nil {
+			return f.formattedValue(c.S, c.IS.String(), raw), nil
+		}
+		return f.formattedValue(c.S, c.V, raw), nil
+	default:
+		if isNum, precision, decimal := isNumeric(c.V); isNum && !raw {
+			if precision > 15 {
+				c.V = strconv.FormatFloat(decimal, 'G', 15, 64)
+			} else {
+				c.V = strconv.FormatFloat(decimal, 'f', -1, 64)
+			}
+		}
+		return f.formattedValue(c.S, c.V, raw), nil
+	}
+}
+
 // SetCellDefault provides a function to set string type value of a cell as
 // default format without escaping the cell.
 func (f *File) SetCellDefault(sheet, cell, value string) error {
@@ -476,22 +584,11 @@ func (f *File) SetCellDefault(sheet, cell, value string) error {
 	ws.Lock()
 	defer ws.Unlock()
 	c.S = f.prepareCellStyle(ws, col, row, c.S)
-	c.T, c.V = setCellDefault(value)
-	c.IS = nil
+	c.setCellDefault(value)
 	f.removeFormula(c, ws, sheet)
 	return err
 }
 
-// setCellDefault prepares cell type and string type cell value by a given
-// string.
-func setCellDefault(value string) (t string, v string) {
-	if ok, _, _ := isNumeric(value); !ok {
-		t = "str"
-	}
-	v = value
-	return
-}
-
 // GetCellFormula provides a function to get formula from cell by given
 // worksheet name and cell reference in spreadsheet.
 func (f *File) GetCellFormula(sheet, cell string) (string, error) {
@@ -625,7 +722,7 @@ func (f *File) SetCellFormula(sheet, cell, formula string, opts ...FormulaOpts)
 			c.F.Ref = *opt.Ref
 		}
 	}
-	c.IS = nil
+	c.T, c.IS = "str", nil
 	return err
 }
 
@@ -900,7 +997,7 @@ func setRichText(runs []RichTextRun) ([]xlsxR, error) {
 			return textRuns, ErrCellCharsLength
 		}
 		run := xlsxR{T: &xlsxT{}}
-		_, run.T.Val, run.T.Space = setCellStr(textRun.Text)
+		run.T.Val, run.T.Space = trimCellValue(textRun.Text)
 		fnt := textRun.Font
 		if fnt != nil {
 			run.RPr = newRpr(fnt)
diff --git a/cell_test.go b/cell_test.go
index 980058a..f741211 100644
--- a/cell_test.go
+++ b/cell_test.go
@@ -224,10 +224,11 @@ func TestSetCellTime(t *testing.T) {
 	} {
 		timezone, err := time.LoadLocation(location)
 		assert.NoError(t, err)
-		_, b, isNum, err := setCellTime(date.In(timezone), false)
+		c := &xlsxC{}
+		isNum, err := c.setCellTime(date.In(timezone), false)
 		assert.NoError(t, err)
 		assert.Equal(t, true, isNum)
-		assert.Equal(t, expected, b)
+		assert.Equal(t, expected, c.V)
 	}
 }
 
@@ -237,7 +238,7 @@ func TestGetCellValue(t *testing.T) {
 	sheetData := `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData>%s</sheetData></worksheet>`
 
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="3"><c t="str"><v>A3</v></c></row><row><c t="str"><v>A4</v></c><c t="str"><v>B4</v></c></row><row r="7"><c t="str"><v>A7</v></c><c t="str"><v>B7</v></c></row><row><c t="str"><v>A8</v></c><c t="str"><v>B8</v></c></row>`)))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="3"><c t="inlineStr"><is><t>A3</t></is></c></row><row><c t="inlineStr"><is><t>A4</t></is></c><c t="inlineStr"><is><t>B4</t></is></c></row><row r="7"><c t="inlineStr"><is><t>A7</t></is></c><c t="inlineStr"><is><t>B7</t></is></c></row><row><c t="inlineStr"><is><t>A8</t></is></c><c t="inlineStr"><is><t>B8</t></is></c></row>`)))
 	f.checked = nil
 	cells := []string{"A3", "A4", "B4", "A7", "B7"}
 	rows, err := f.GetRows("Sheet1")
@@ -253,35 +254,35 @@ func TestGetCellValue(t *testing.T) {
 	assert.NoError(t, err)
 
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="2"><c r="A2" t="str"><v>A2</v></c></row><row r="2"><c r="B2" t="str"><v>B2</v></c></row>`)))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="2"><c r="A2" t="inlineStr"><is><t>A2</t></is></c></row><row r="2"><c r="B2" t="inlineStr"><is><t>B2</t></is></c></row>`)))
 	f.checked = nil
 	cell, err := f.GetCellValue("Sheet1", "A2")
 	assert.Equal(t, "A2", cell)
 	assert.NoError(t, err)
 
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="2"><c r="A2" t="str"><v>A2</v></c></row><row r="2"><c r="B2" t="str"><v>B2</v></c></row>`)))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="2"><c r="A2" t="inlineStr"><is><t>A2</t></is></c></row><row r="2"><c r="B2" t="inlineStr"><is><t>B2</t></is></c></row>`)))
 	f.checked = nil
 	rows, err = f.GetRows("Sheet1")
 	assert.Equal(t, [][]string{nil, {"A2", "B2"}}, rows)
 	assert.NoError(t, err)
 
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="1"><c r="A1" t="str"><v>A1</v></c></row><row r="1"><c r="B1" t="str"><v>B1</v></c></row>`)))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="1"><c r="A1" t="inlineStr"><is><t>A1</t></is></c></row><row r="1"><c r="B1" t="inlineStr"><is><t>B1</t></is></c></row>`)))
 	f.checked = nil
 	rows, err = f.GetRows("Sheet1")
 	assert.Equal(t, [][]string{{"A1", "B1"}}, rows)
 	assert.NoError(t, err)
 
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row><c t="str"><v>A3</v></c></row><row><c t="str"><v>A4</v></c><c t="str"><v>B4</v></c></row><row r="7"><c t="str"><v>A7</v></c><c t="str"><v>B7</v></c></row><row><c t="str"><v>A8</v></c><c t="str"><v>B8</v></c></row>`)))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row><c t="inlineStr"><is><t>A3</t></is></c></row><row><c t="inlineStr"><is><t>A4</t></is></c><c t="inlineStr"><is><t>B4</t></is></c></row><row r="7"><c t="inlineStr"><is><t>A7</t></is></c><c t="inlineStr"><is><t>B7</t></is></c></row><row><c t="inlineStr"><is><t>A8</t></is></c><c t="inlineStr"><is><t>B8</t></is></c></row>`)))
 	f.checked = nil
 	rows, err = f.GetRows("Sheet1")
 	assert.Equal(t, [][]string{{"A3"}, {"A4", "B4"}, nil, nil, nil, nil, {"A7", "B7"}, {"A8", "B8"}}, rows)
 	assert.NoError(t, err)
 
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="0"><c r="H6" t="str"><v>H6</v></c><c r="A1" t="str"><v>r0A6</v></c><c r="F4" t="str"><v>F4</v></c></row><row><c r="A1" t="str"><v>A6</v></c><c r="B1" t="str"><v>B6</v></c><c r="C1" t="str"><v>C6</v></c></row><row r="3"><c r="A3"><v>100</v></c><c r="B3" t="str"><v>B3</v></c></row>`)))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(sheetData, `<row r="0"><c r="H6" t="inlineStr"><is><t>H6</t></is></c><c r="A1" t="inlineStr"><is><t>r0A6</t></is></c><c r="F4" t="inlineStr"><is><t>F4</t></is></c></row><row><c r="A1" t="inlineStr"><is><t>A6</t></is></c><c r="B1" t="inlineStr"><is><t>B6</t></is></c><c r="C1" t="inlineStr"><is><t>C6</t></is></c></row><row r="3"><c r="A3"><v>100</v></c><c r="B3" t="inlineStr"><is><t>B3</t></is></c></row>`)))
 	f.checked = nil
 	cell, err = f.GetCellValue("Sheet1", "H6")
 	assert.Equal(t, "H6", cell)
@@ -326,8 +327,8 @@ func TestGetCellValue(t *testing.T) {
 	<row r="25"><c r="A25"><v>275.39999999999998</v></c></row>
 	<row r="26"><c r="A26"><v>68.900000000000006</v></c></row>
 	<row r="27"><c r="A27"><v>1.1000000000000001</v></c></row>
-	<row r="28"><c r="A28" t="str"><v>1234567890123_4</v></c></row>
-	<row r="29"><c r="A29" t="str"><v>123456789_0123_4</v></c></row>
+	<row r="28"><c r="A28" t="inlineStr"><is><t>1234567890123_4</t></is></c></row>
+	<row r="29"><c r="A29" t="inlineStr"><is><t>123456789_0123_4</t></is></c></row>
 	<row r="30"><c r="A30"><v>+0.0000000000000000002399999999999992E-4</v></c></row>
 	<row r="31"><c r="A31"><v>7.2399999999999992E-2</v></c></row>
 	<row r="32"><c r="A32" t="d"><v>20200208T080910.123</v></c></row>
@@ -386,7 +387,7 @@ func TestGetCellType(t *testing.T) {
 	assert.NoError(t, f.SetCellValue("Sheet1", "A1", "A1"))
 	cellType, err = f.GetCellType("Sheet1", "A1")
 	assert.NoError(t, err)
-	assert.Equal(t, CellTypeString, cellType)
+	assert.Equal(t, CellTypeSharedString, cellType)
 	_, err = f.GetCellType("Sheet1", "A")
 	assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
 }
diff --git a/col_test.go b/col_test.go
index 75c191b..f786335 100644
--- a/col_test.go
+++ b/col_test.go
@@ -109,12 +109,12 @@ func TestGetColsError(t *testing.T) {
 
 	f = NewFile()
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="A"><c r="2" t="str"><v>B</v></c></row></sheetData></worksheet>`))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="A"><c r="2" t="inlineStr"><is><t>B</t></is></c></row></sheetData></worksheet>`))
 	f.checked = nil
 	_, err = f.GetCols("Sheet1")
 	assert.EqualError(t, err, `strconv.Atoi: parsing "A": invalid syntax`)
 
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="2"><c r="A" t="str"><v>B</v></c></row></sheetData></worksheet>`))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="2"><c r="A" t="inlineStr"><is><t>B</t></is></c></row></sheetData></worksheet>`))
 	_, err = f.GetCols("Sheet1")
 	assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
 
@@ -124,7 +124,7 @@ func TestGetColsError(t *testing.T) {
 	cols.totalRows = 2
 	cols.totalCols = 2
 	cols.curCol = 1
-	cols.sheetXML = []byte(`<worksheet><sheetData><row r="1"><c r="A" t="str"><v>A</v></c></row></sheetData></worksheet>`)
+	cols.sheetXML = []byte(`<worksheet><sheetData><row r="1"><c r="A" t="inlineStr"><is><t>A</t></is></c></row></sheetData></worksheet>`)
 	_, err = cols.Rows()
 	assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
 
diff --git a/rows.go b/rows.go
index 9f791cb..4f05f24 100644
--- a/rows.go
+++ b/rows.go
@@ -20,8 +20,6 @@ import (
 	"math"
 	"os"
 	"strconv"
-	"strings"
-	"time"
 
 	"github.com/mohae/deepcopy"
 )
@@ -449,81 +447,6 @@ func (f *File) sharedStringsReader() *xlsxSST {
 	return f.SharedStrings
 }
 
-// getCellDate parse cell value which containing a boolean.
-func (c *xlsxC) getCellBool(f *File, raw bool) (string, error) {
-	if !raw {
-		if c.V == "1" {
-			return "TRUE", nil
-		}
-		if c.V == "0" {
-			return "FALSE", nil
-		}
-	}
-	return f.formattedValue(c.S, c.V, raw), nil
-}
-
-// getCellDate parse cell value which contains a date in the ISO 8601 format.
-func (c *xlsxC) getCellDate(f *File, raw bool) (string, error) {
-	if !raw {
-		layout := "20060102T150405.999"
-		if strings.HasSuffix(c.V, "Z") {
-			layout = "20060102T150405Z"
-			if strings.Contains(c.V, "-") {
-				layout = "2006-01-02T15:04:05Z"
-			}
-		} else if strings.Contains(c.V, "-") {
-			layout = "2006-01-02 15:04:05Z"
-		}
-		if timestamp, err := time.Parse(layout, strings.ReplaceAll(c.V, ",", ".")); err == nil {
-			excelTime, _ := timeToExcelTime(timestamp, false)
-			c.V = strconv.FormatFloat(excelTime, 'G', 15, 64)
-		}
-	}
-	return f.formattedValue(c.S, c.V, raw), nil
-}
-
-// getValueFrom return a value from a column/row cell, this function is
-// intended to be used with for range on rows an argument with the spreadsheet
-// opened file.
-func (c *xlsxC) getValueFrom(f *File, d *xlsxSST, raw bool) (string, error) {
-	f.Lock()
-	defer f.Unlock()
-	switch c.T {
-	case "b":
-		return c.getCellBool(f, raw)
-	case "d":
-		return c.getCellDate(f, raw)
-	case "s":
-		if c.V != "" {
-			xlsxSI := 0
-			xlsxSI, _ = strconv.Atoi(c.V)
-			if _, ok := f.tempFiles.Load(defaultXMLPathSharedStrings); ok {
-				return f.formattedValue(c.S, f.getFromStringItem(xlsxSI), raw), nil
-			}
-			if len(d.SI) > xlsxSI {
-				return f.formattedValue(c.S, d.SI[xlsxSI].String(), raw), nil
-			}
-		}
-		return f.formattedValue(c.S, c.V, raw), nil
-	case "str":
-		return f.formattedValue(c.S, c.V, raw), nil
-	case "inlineStr":
-		if c.IS != nil {
-			return f.formattedValue(c.S, c.IS.String(), raw), nil
-		}
-		return f.formattedValue(c.S, c.V, raw), nil
-	default:
-		if isNum, precision, decimal := isNumeric(c.V); isNum && !raw {
-			if precision > 15 {
-				c.V = strconv.FormatFloat(decimal, 'G', 15, 64)
-			} else {
-				c.V = strconv.FormatFloat(decimal, 'f', -1, 64)
-			}
-		}
-		return f.formattedValue(c.S, c.V, raw), nil
-	}
-}
-
 // SetRowVisible provides a function to set visible of a single row by given
 // worksheet name and Excel row number. For example, hide row 2 in Sheet1:
 //
diff --git a/rows_test.go b/rows_test.go
index 423932f..81572e1 100644
--- a/rows_test.go
+++ b/rows_test.go
@@ -203,12 +203,12 @@ func TestColumns(t *testing.T) {
 	_, err = rows.Columns()
 	assert.NoError(t, err)
 
-	rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`<worksheet><sheetData><row r="A"><c r="A1" t="s"><v>1</v></c></row><row r="A"><c r="2" t="str"><v>B</v></c></row></sheetData></worksheet>`)))
+	rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`<worksheet><sheetData><row r="A"><c r="A1" t="s"><v>1</v></c></row><row r="A"><c r="2" t="inlineStr"><is><t>B</t></is></c></row></sheetData></worksheet>`)))
 	assert.True(t, rows.Next())
 	_, err = rows.Columns()
 	assert.EqualError(t, err, `strconv.Atoi: parsing "A": invalid syntax`)
 
-	rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`<worksheet><sheetData><row r="1"><c r="A1" t="s"><v>1</v></c></row><row r="A"><c r="2" t="str"><v>B</v></c></row></sheetData></worksheet>`)))
+	rows.decoder = f.xmlNewDecoder(bytes.NewReader([]byte(`<worksheet><sheetData><row r="1"><c r="A1" t="s"><v>1</v></c></row><row r="A"><c r="2" t="inlineStr"><is><t>B</t></is></c></row></sheetData></worksheet>`)))
 	_, err = rows.Columns()
 	assert.NoError(t, err)
 
diff --git a/sheet_test.go b/sheet_test.go
index 6e87de9..4e1e448 100644
--- a/sheet_test.go
+++ b/sheet_test.go
@@ -76,18 +76,18 @@ func TestSearchSheet(t *testing.T) {
 
 	f = NewFile()
 	f.Sheet.Delete("xl/worksheets/sheet1.xml")
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="A"><c r="2" t="str"><v>A</v></c></row></sheetData></worksheet>`))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="A"><c r="2" t="inlineStr"><is><t>A</t></is></c></row></sheetData></worksheet>`))
 	f.checked = nil
 	result, err = f.SearchSheet("Sheet1", "A")
 	assert.EqualError(t, err, "strconv.Atoi: parsing \"A\": invalid syntax")
 	assert.Equal(t, []string(nil), result)
 
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="2"><c r="A" t="str"><v>A</v></c></row></sheetData></worksheet>`))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="2"><c r="A" t="inlineStr"><is><t>A</t></is></c></row></sheetData></worksheet>`))
 	result, err = f.SearchSheet("Sheet1", "A")
 	assert.EqualError(t, err, newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
 	assert.Equal(t, []string(nil), result)
 
-	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="0"><c r="A1" t="str"><v>A</v></c></row></sheetData></worksheet>`))
+	f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<worksheet><sheetData><row r="0"><c r="A1" t="inlineStr"><is><t>A</t></is></c></row></sheetData></worksheet>`))
 	result, err = f.SearchSheet("Sheet1", "A")
 	assert.EqualError(t, err, "invalid cell reference [1, 0]")
 	assert.Equal(t, []string(nil), result)
diff --git a/stream.go b/stream.go
index aaa4589..fa78d8b 100644
--- a/stream.go
+++ b/stream.go
@@ -263,7 +263,7 @@ func (sw *StreamWriter) getRowValues(hRow, hCol, vCol int) (res []string, err er
 			if col < hCol || col > vCol {
 				continue
 			}
-			res[col-hCol] = c.V
+			res[col-hCol], _ = c.getValueFrom(sw.File, nil, false)
 		}
 		return res, nil
 	}
@@ -462,7 +462,7 @@ func (sw *StreamWriter) MergeCell(hCell, vCell string) error {
 // setCellFormula provides a function to set formula of a cell.
 func setCellFormula(c *xlsxC, formula string) {
 	if formula != "" {
-		c.F = &xlsxF{Content: formula}
+		c.T, c.F = "str", &xlsxF{Content: formula}
 	}
 }
 
@@ -477,9 +477,9 @@ func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) error {
 	case float64:
 		c.T, c.V = setCellFloat(val, -1, 64)
 	case string:
-		c.T, c.V, c.XMLSpace = setCellStr(val)
+		c.setCellValue(val)
 	case []byte:
-		c.T, c.V, c.XMLSpace = setCellStr(string(val))
+		c.setCellValue(string(val))
 	case time.Duration:
 		c.T, c.V = setCellDuration(val)
 	case time.Time:
@@ -488,20 +488,19 @@ func (sw *StreamWriter) setCellValFunc(c *xlsxC, val interface{}) error {
 		if wb != nil && wb.WorkbookPr != nil {
 			date1904 = wb.WorkbookPr.Date1904
 		}
-		c.T, c.V, isNum, err = setCellTime(val, date1904)
-		if isNum && c.S == 0 {
+		if isNum, err = c.setCellTime(val, date1904); isNum && c.S == 0 {
 			style, _ := sw.File.NewStyle(&Style{NumFmt: 22})
 			c.S = style
 		}
 	case bool:
 		c.T, c.V = setCellBool(val)
 	case nil:
-		c.T, c.V, c.XMLSpace = setCellStr("")
+		c.setCellValue("")
 	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))
+		c.setCellValue(fmt.Sprint(val))
 	}
 	return err
 }
@@ -569,10 +568,25 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
 		_, _ = buf.WriteString(`</v>`)
 	}
 	if c.IS != nil {
-		is, _ := xml.Marshal(c.IS.R)
-		_, _ = buf.WriteString(`<is>`)
-		_, _ = buf.Write(is)
-		_, _ = buf.WriteString(`</is>`)
+		if len(c.IS.R) > 0 {
+			is, _ := xml.Marshal(c.IS.R)
+			_, _ = buf.WriteString(`<is>`)
+			_, _ = buf.Write(is)
+			_, _ = buf.WriteString(`</is>`)
+		}
+		if c.IS.T != nil {
+			_, _ = buf.WriteString(`<is><t`)
+			if c.IS.T.Space.Value != "" {
+				_, _ = buf.WriteString(` xml:`)
+				_, _ = buf.WriteString(c.IS.T.Space.Name.Local)
+				_, _ = buf.WriteString(`="`)
+				_, _ = buf.WriteString(c.IS.T.Space.Value)
+				_, _ = buf.WriteString(`"`)
+			}
+			_, _ = buf.WriteString(`>`)
+			_, _ = buf.Write([]byte(c.IS.T.Val))
+			_, _ = buf.WriteString(`</t></is>`)
+		}
 	}
 	_, _ = buf.WriteString(`</c>`)
 }
-- 
cgit v1.2.1