Просмотр исходного кода

Cell type and style extension

Added support for:
- Bold font
- Italic font
- Different Data types (Only numeric and string tested so far)
DamianSzkuat 6 лет назад
Родитель
Сommit
e1a2afdffa
3 измененных файлов с 162 добавлено и 120 удалено
  1. 8 64
      stream_file.go
  2. 51 11
      stream_file_builder.go
  3. 103 45
      stream_test.go

+ 8 - 64
stream_file.go

@@ -43,11 +43,11 @@ var (
 // same number of cells as the header provided when the sheet was created or an error will be returned. This function
 // same number of cells as the header provided when the sheet was created or an error will be returned. This function
 // will always trigger a flush on success. Currently the only supported data type is string data.
 // will always trigger a flush on success. Currently the only supported data type is string data.
 // TODO update comment
 // TODO update comment
-func (sf *StreamFile) Write(cells []interface{}, cellTypes []*CellType) error {
+func (sf *StreamFile) Write(cells []string, cellTypes []*CellType, cellStyles []int) error {
 	if sf.err != nil {
 	if sf.err != nil {
 		return sf.err
 		return sf.err
 	}
 	}
-	err := sf.write(cells, cellTypes)
+	err := sf.write(cells, cellTypes, cellStyles)
 	if err != nil {
 	if err != nil {
 		sf.err = err
 		sf.err = err
 		return err
 		return err
@@ -56,12 +56,12 @@ func (sf *StreamFile) Write(cells []interface{}, cellTypes []*CellType) error {
 }
 }
 
 
 //TODO Add comment
 //TODO Add comment
-func (sf *StreamFile) WriteAll(records [][]interface{}, cellTypes []*CellType) error {
+func (sf *StreamFile) WriteAll(records [][]string, cellTypes []*CellType, cellStyles []int) error {
 	if sf.err != nil {
 	if sf.err != nil {
 		return sf.err
 		return sf.err
 	}
 	}
 	for _, row := range records {
 	for _, row := range records {
-		err := sf.write(row, cellTypes)
+		err := sf.write(row, cellTypes, cellStyles)
 		if err != nil {
 		if err != nil {
 			sf.err = err
 			sf.err = err
 			return err
 			return err
@@ -71,7 +71,7 @@ func (sf *StreamFile) WriteAll(records [][]interface{}, cellTypes []*CellType) e
 }
 }
 
 
 // TODO Add comment
 // TODO Add comment
-func (sf *StreamFile) write(cells []interface{}, cellTypes []*CellType) error {
+func (sf *StreamFile) write(cells []string, cellTypes []*CellType, cellStyles []int) error {
 	if sf.currentSheet == nil {
 	if sf.currentSheet == nil {
 		return NoCurrentSheetError
 		return NoCurrentSheetError
 	}
 	}
@@ -102,9 +102,8 @@ func (sf *StreamFile) write(cells []interface{}, cellTypes []*CellType) error {
 		// Build the XML cell opening
 		// Build the XML cell opening
 		cellOpen := `<c r="` + cellCoordinate + `" t="` + cellType + `"`
 		cellOpen := `<c r="` + cellCoordinate + `" t="` + cellType + `"`
 		// Add in the style id if the cell isn't using the default style
 		// Add in the style id if the cell isn't using the default style
-		if colIndex < len(sf.currentSheet.styleIds) && sf.currentSheet.styleIds[colIndex] != 0 {
-			cellOpen += ` s="` + strconv.Itoa(sf.currentSheet.styleIds[colIndex]) + `"`
-		}
+		cellOpen += ` s="` + strconv.Itoa(cellStyles[colIndex]) + `"`
+
 		cellOpen += `>`
 		cellOpen += `>`
 
 
 		// The XML cell contents
 		// The XML cell contents
@@ -127,7 +126,7 @@ func (sf *StreamFile) write(cells []interface{}, cellTypes []*CellType) error {
 		}
 		}
 
 
 		// Write cell contents
 		// Write cell contents
-		if err := sf.WriteCellContents(cellData, cellTypes[colIndex]); err != nil {
+		if err:= xml.EscapeText(sf.currentSheet.writer, []byte(cellData)); err != nil {
 			return err
 			return err
 		}
 		}
 
 
@@ -206,61 +205,6 @@ func GetCellContentOpenAncCloseTags(cellType *CellType) (string, string, error)
 	}
 	}
 }
 }
 
 
-// TODO make sure to test shared strings
-func (sf *StreamFile) WriteCellContents(cellContents interface{}, cellType *CellType) error {
-	if cellType == nil {
-		// TODO should default be inline string?
-		cellStringData := cellContents.(string)
-		return xml.EscapeText(sf.currentSheet.writer, []byte(cellStringData))
-	}
-	// TODO currently shared strings are assigned the ContentTypeString in tests instead of ContentTypeInline
-	// TODO Remove once test have been changed.
-	if *cellType == CellTypeString {
-		cellStringData := cellContents.(string)
-		return xml.EscapeText(sf.currentSheet.writer, []byte(cellStringData))
-	}
-	XMLEncoder := xml.NewEncoder(sf.currentSheet.writer)
-	switch cellType {
-	case CellTypeInline.Ptr():
-		cellStringData := cellContents.(string)
-		return xml.EscapeText(sf.currentSheet.writer, []byte(cellStringData))
-	case CellTypeStringFormula.Ptr():
-		// Formulas are currently not supported
-		return UnsupportedCellTypeError
-	default:
-		switch cellContents.(type) {
-		case bool:
-			return XMLEncoder.Encode(cellContents.(bool))
-		case int:
-			return XMLEncoder.Encode(cellContents.(int))
-		case int8:
-			return XMLEncoder.Encode(cellContents.(int8))
-		case int16:
-			return XMLEncoder.Encode(cellContents.(int16))
-		case int32:
-			return XMLEncoder.Encode(cellContents.(int32))
-		case int64:
-			return XMLEncoder.Encode(cellContents.(int64))
-		case uint:
-			return XMLEncoder.Encode(cellContents.(uint))
-		case uint8:
-			return XMLEncoder.Encode(cellContents.(uint8))
-		case uint16:
-			return XMLEncoder.Encode(cellContents.(uint16))
-		case uint32:
-			return XMLEncoder.Encode(cellContents.(uint32))
-		case uint64:
-			return XMLEncoder.Encode(cellContents.(uint64))
-		case float32:
-			return XMLEncoder.Encode(cellContents.(float32))
-		case float64:
-			return XMLEncoder.Encode(cellContents.(float64))
-		default:
-			return UnsupportedDataTypeError
-		}
-	}
-}
-
 // Error reports any error that has occurred during a previous Write or Flush.
 // Error reports any error that has occurred during a previous Write or Flush.
 func (sf *StreamFile) Error() error {
 func (sf *StreamFile) Error() error {
 	return sf.err
 	return sf.err

+ 51 - 11
stream_file_builder.go

@@ -36,7 +36,7 @@ type StreamFileBuilder struct {
 	built              bool
 	built              bool
 	xlsxFile           *File
 	xlsxFile           *File
 	zipWriter          *zip.Writer
 	zipWriter          *zip.Writer
-	cellTypeToStyleIds map[CellType]int
+	// cellTypeToStyleIds map[CellType]int
 	maxStyleId         int
 	maxStyleId         int
 	styleIds           [][]int
 	styleIds           [][]int
 }
 }
@@ -59,7 +59,7 @@ func NewStreamFileBuilder(writer io.Writer) *StreamFileBuilder {
 	return &StreamFileBuilder{
 	return &StreamFileBuilder{
 		zipWriter:          zip.NewWriter(writer),
 		zipWriter:          zip.NewWriter(writer),
 		xlsxFile:           NewFile(),
 		xlsxFile:           NewFile(),
-		cellTypeToStyleIds: make(map[CellType]int),
+		// cellTypeToStyleIds: make(map[CellType]int),
 		maxStyleId:         initMaxStyleId,
 		maxStyleId:         initMaxStyleId,
 	}
 	}
 }
 }
@@ -77,7 +77,7 @@ func NewStreamFileBuilderForPath(path string) (*StreamFileBuilder, error) {
 // AddSheet will add sheets with the given name with the provided headers. The headers cannot be edited later, and all
 // AddSheet will add sheets with the given name with the provided headers. The headers cannot be edited later, and all
 // rows written to the sheet must contain the same number of cells as the header. Sheet names must be unique, or an
 // rows written to the sheet must contain the same number of cells as the header. Sheet names must be unique, or an
 // error will be thrown.
 // error will be thrown.
-func (sb *StreamFileBuilder) AddSheet(name string, headers []interface{}, cellTypes []*CellType) error {
+func (sb *StreamFileBuilder) AddSheet(name string, headers []string, cellStyles []int, cellTypes []*CellType) error {
 	if sb.built {
 	if sb.built {
 		return BuiltStreamFileBuilderError
 		return BuiltStreamFileBuilderError
 	}
 	}
@@ -98,20 +98,20 @@ func (sb *StreamFileBuilder) AddSheet(name string, headers []interface{}, cellTy
 		return errors.New("failed to write headers")
 		return errors.New("failed to write headers")
 	}
 	}
 	for i, cellType := range cellTypes {
 	for i, cellType := range cellTypes {
-		var cellStyleIndex int
-		var ok bool
+		cellStyleIndex := cellStyles[i]
+		//var ok bool
 		if cellType != nil {
 		if cellType != nil {
 			// The cell type is one of the attributes of a Style.
 			// The cell type is one of the attributes of a Style.
 			// Since it is the only attribute of Style that we use, we can assume that cell types
 			// Since it is the only attribute of Style that we use, we can assume that cell types
 			// map one to one with Styles and their Style ID.
 			// map one to one with Styles and their Style ID.
 			// If a new cell type is used, a new style gets created with an increased id, if an existing cell type is
 			// If a new cell type is used, a new style gets created with an increased id, if an existing cell type is
 			// used, the pre-existing style will also be used.
 			// used, the pre-existing style will also be used.
-			cellStyleIndex, ok = sb.cellTypeToStyleIds[*cellType]
-			if !ok {
-				sb.maxStyleId++
-				cellStyleIndex = sb.maxStyleId
-				sb.cellTypeToStyleIds[*cellType] = sb.maxStyleId
-			}
+			//cellStyleIndex, ok = sb.cellTypeToStyleIds[*cellType]
+			//if !ok {
+			//	sb.maxStyleId++
+			//	cellStyleIndex = sb.maxStyleId
+			//	sb.cellTypeToStyleIds[*cellType] = sb.maxStyleId
+			//}
 			sheet.Cols[i].SetType(*cellType)
 			sheet.Cols[i].SetType(*cellType)
 		}
 		}
 		sb.styleIds[len(sb.styleIds)-1] = append(sb.styleIds[len(sb.styleIds)-1], cellStyleIndex)
 		sb.styleIds[len(sb.styleIds)-1] = append(sb.styleIds[len(sb.styleIds)-1], cellStyleIndex)
@@ -126,10 +126,16 @@ func (sb *StreamFileBuilder) Build() (*StreamFile, error) {
 		return nil, BuiltStreamFileBuilderError
 		return nil, BuiltStreamFileBuilderError
 	}
 	}
 	sb.built = true
 	sb.built = true
+
 	parts, err := sb.xlsxFile.MarshallParts()
 	parts, err := sb.xlsxFile.MarshallParts()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+	parts, err = sb.addDefaultStyles(parts)
+	if err != nil {
+		return nil, err
+	}
+
 	es := &StreamFile{
 	es := &StreamFile{
 		zipWriter:      sb.zipWriter,
 		zipWriter:      sb.zipWriter,
 		xlsxFile:       sb.xlsxFile,
 		xlsxFile:       sb.xlsxFile,
@@ -162,6 +168,40 @@ func (sb *StreamFileBuilder) Build() (*StreamFile, error) {
 	return es, nil
 	return es, nil
 }
 }
 
 
+func (sb *StreamFileBuilder) addDefaultStyles(parts map[string]string) (map[string]string, error) {
+	var err error
+
+	// Default style - Bold
+	style := NewStyle()
+	style.Font.Bold = true
+	if style != nil {
+		xNumFmtId := 0 // GENERAL FORMATTING
+		_ = handleStyleForXLSX(style, xNumFmtId, sb.xlsxFile.styles)
+		// fmt.Print(XfId)
+	}
+
+	//parts["xl/styles.xml"], err = sb.xlsxFile.styles.Marshal()
+	//if err!=nil {
+	//	return nil, err
+	//}
+
+	// Default style - Italic
+	style = NewStyle()
+	style.Font.Italic = true
+	if style != nil {
+		xNumFmtId := 0 // GENERAL FORMATTING
+		_ = handleStyleForXLSX(style, xNumFmtId, sb.xlsxFile.styles)
+		//fmt.Print(XfId)
+	}
+
+	parts["xl/styles.xml"], err = sb.xlsxFile.styles.Marshal()
+	if err!=nil {
+		return nil, err
+	}
+
+	return parts, nil
+}
+
 // processEmptySheetXML will take in the path and XML data of an empty sheet, and will save the beginning and end of the
 // processEmptySheetXML will take in the path and XML data of an empty sheet, and will save the beginning and end of the
 // XML file so that these can be written at the right time.
 // XML file so that these can be written at the right time.
 func (sb *StreamFileBuilder) processEmptySheetXML(sf *StreamFile, path, data string) error {
 func (sb *StreamFileBuilder) processEmptySheetXML(sf *StreamFile, path, data string) error {

+ 103 - 45
stream_test.go

@@ -32,38 +32,51 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 	testCases := []struct {
 	testCases := []struct {
 		testName      string
 		testName      string
 		sheetNames    []string
 		sheetNames    []string
-		workbookData  [][][]interface{}
-		headerTypes   [][]*CellType
+		workbookData  [][][]string
+		cellStyles    [][][]int
+		cellTypes     [][][]*CellType
 		expectedError error
 		expectedError error
 	}{
 	}{
-		//{
-		//	testName: "Number Row",
-		//	sheetNames: []string{
-		//		"Sheet1",
-		//	},
-		//	workbookData: [][][]interface{}{
-		//		{
-		//			{"1", "25"},
-		//			{123, 98},
-		//		},
-		//	},
-		//	headerTypes: [][]*CellType{
-		//		{CellTypeNumeric.Ptr(), CellTypeNumeric.Ptr()},
-		//	},
-		//},
+		{
+			testName: "Number Row",
+			sheetNames: []string{
+				"Sheet1",
+			},
+			workbookData: [][][]string{
+				{
+					{"1", "25", "A", "B"},
+					{"1234", "98", "34", "34"},
+				},
+			},
+			cellStyles: [][][]int{
+				{
+					{0,0,0,0},
+					{0,2,3,0},
+				},
+			},
+			cellTypes: [][][]*CellType{
+				{
+					{CellTypeString.Ptr(),  CellTypeString.Ptr(),  CellTypeString.Ptr(),  CellTypeString.Ptr()},
+					{CellTypeNumeric.Ptr(), CellTypeNumeric.Ptr(), CellTypeNumeric.Ptr(), CellTypeNumeric.Ptr()},
+				},
+			},
+		},
 		{
 		{
 			testName: "One Sheet",
 			testName: "One Sheet",
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet1",
 				"Sheet1",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300", "0000000123"},
 					{"123", "Taco", "300", "0000000123"},
 				},
 				},
 			},
 			},
-			headerTypes: [][]*CellType{
-				{nil, CellTypeString.Ptr(), nil, CellTypeString.Ptr()},
+			cellTypes: [][][]*CellType{
+				{
+					{CellTypeString.Ptr(),  CellTypeString.Ptr(),  CellTypeString.Ptr(),  CellTypeString.Ptr()},
+					{CellTypeNumeric.Ptr(), CellTypeString.Ptr(),  nil,                   CellTypeString.Ptr()},
+				},
 			},
 			},
 		},
 		},
 		{
 		{
@@ -71,7 +84,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet1",
 				"Sheet1",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token"},
 					{"Token"},
 					{"123"},
 					{"123"},
@@ -83,7 +96,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet 1", "Sheet 2", "Sheet3",
 				"Sheet 1", "Sheet 2", "Sheet3",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300", "0000000123"},
 					{"123", "Taco", "300", "0000000123"},
@@ -105,7 +118,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet 1", "Sheet 1",
 				"Sheet 1", "Sheet 1",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300", "0000000123"},
 					{"123", "Taco", "300", "0000000123"},
@@ -123,7 +136,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet 1",
 				"Sheet 1",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300", "0000000123"},
 					{"123", "Taco", "300", "0000000123"},
@@ -140,7 +153,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet 1",
 				"Sheet 1",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300", "0000000123", "asdf"},
 					{"123", "Taco", "300", "0000000123", "asdf"},
@@ -153,7 +166,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet 1",
 				"Sheet 1",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300"},
 					{"123", "Taco", "300"},
@@ -166,7 +179,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet 1", "Sheet 2", "Sheet 3", "Sheet 4", "Sheet 5", "Sheet 6",
 				"Sheet 1", "Sheet 2", "Sheet 3", "Sheet 4", "Sheet 5", "Sheet 6",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300", "0000000123"},
 					{"123", "Taco", "300", "0000000123"},
@@ -183,7 +196,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet 1", "Sheet 2",
 				"Sheet 1", "Sheet 2",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300", "0000000123"},
 					{"123", "Taco", "300", "0000000123"},
@@ -196,7 +209,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet 1",
 				"Sheet 1",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					{"Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU"},
 					{"Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU", "Token", "Name", "Price", "SKU"},
 					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
 					{"123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123", "123", "Taco", "300", "0000000123"},
@@ -231,7 +244,7 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 			sheetNames: []string{
 			sheetNames: []string{
 				"Sheet1",
 				"Sheet1",
 			},
 			},
-			workbookData: [][][]interface{}{
+			workbookData: [][][]string{
 				{
 				{
 					// String courtesy of https://github.com/minimaxir/big-list-of-naughty-strings/
 					// String courtesy of https://github.com/minimaxir/big-list-of-naughty-strings/
 					// Header row contains the tags that I am filtering on
 					// Header row contains the tags that I am filtering on
@@ -249,12 +262,43 @@ func (s *StreamSuite) TestXlsxStreamWrite(t *C) {
 		},
 		},
 	}
 	}
 	for i, testCase := range testCases {
 	for i, testCase := range testCases {
+		fmt.Print("Current Test case: ")
+		fmt.Println(testCase.testName)
 		var filePath string
 		var filePath string
 		var buffer bytes.Buffer
 		var buffer bytes.Buffer
 		if TestsShouldMakeRealFiles {
 		if TestsShouldMakeRealFiles {
 			filePath = fmt.Sprintf("Workbook%d.xlsx", i)
 			filePath = fmt.Sprintf("Workbook%d.xlsx", i)
 		}
 		}
-		err := writeStreamFile(filePath, &buffer, testCase.sheetNames, testCase.workbookData, testCase.headerTypes, TestsShouldMakeRealFiles)
+
+		if testCase.cellStyles == nil {
+			testCase.cellStyles = [][][]int{}
+			//testCase.cellStyles = append(testCase.cellStyles, [][]int{})
+			for j,_ := range testCase.workbookData{
+				testCase.cellStyles = append(testCase.cellStyles, [][]int{})
+				for k,_ := range testCase.workbookData[j]{
+					testCase.cellStyles[j] = append(testCase.cellStyles[j], []int{})
+					for  _,_ = range testCase.workbookData[j][k]{
+						testCase.cellStyles[j][k] = append(testCase.cellStyles[j][k], 0)
+					}
+				}
+			}
+		}
+
+		if testCase.cellTypes == nil {
+			testCase.cellTypes = [][][]*CellType{}
+			//testCase.cellTypes = append(testCase.cellTypes, [][]*CellType{})
+			for j,_ := range testCase.workbookData{
+				testCase.cellTypes = append(testCase.cellTypes, [][]*CellType{})
+				for k,_ := range testCase.workbookData[j]{
+					testCase.cellTypes[j] = append(testCase.cellTypes[j], []*CellType{})
+					for  _,_ = range testCase.workbookData[j][k]{
+						testCase.cellTypes[j][k] = append(testCase.cellTypes[j][k], CellTypeString.Ptr())
+					}
+				}
+			}
+		}
+
+		err := writeStreamFile(filePath, &buffer, testCase.sheetNames, testCase.workbookData, testCase.cellStyles, testCase.cellTypes, TestsShouldMakeRealFiles)
 		if err != testCase.expectedError && err.Error() != testCase.expectedError.Error() {
 		if err != testCase.expectedError && err.Error() != testCase.expectedError.Error() {
 			t.Fatalf("Error differs from expected error. Error: %v, Expected Error: %v ", err, testCase.expectedError)
 			t.Fatalf("Error differs from expected error. Error: %v, Expected Error: %v ", err, testCase.expectedError)
 		}
 		}
@@ -332,7 +376,7 @@ func (s *StreamSuite) TestXlsxStyleBehavior(t *C) {
 }
 }
 
 
 // writeStreamFile will write the file using this stream package
 // writeStreamFile will write the file using this stream package
-func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string, workbookData [][][]interface{}, headerTypes [][]*CellType, shouldMakeRealFiles bool) error {
+func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string, workbookData [][][]string, cellStyles [][][]int, cellTypes [][][]*CellType, shouldMakeRealFiles bool) error {
 	var file *StreamFileBuilder
 	var file *StreamFileBuilder
 	var err error
 	var err error
 	if shouldMakeRealFiles {
 	if shouldMakeRealFiles {
@@ -343,13 +387,15 @@ func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string,
 	} else {
 	} else {
 		file = NewStreamFileBuilder(fileBuffer)
 		file = NewStreamFileBuilder(fileBuffer)
 	}
 	}
+
 	for i, sheetName := range sheetNames {
 	for i, sheetName := range sheetNames {
 		header := workbookData[i][0]
 		header := workbookData[i][0]
+		headerCellStyles := cellStyles[i][0]
 		var sheetHeaderTypes []*CellType
 		var sheetHeaderTypes []*CellType
-		if i < len(headerTypes) {
-			sheetHeaderTypes = headerTypes[i]
+		if i < len(cellTypes) {
+			sheetHeaderTypes = cellTypes[i][0]
 		}
 		}
-		err := file.AddSheet(sheetName, header, sheetHeaderTypes)
+		err := file.AddSheet(sheetName, header, headerCellStyles, sheetHeaderTypes)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
@@ -359,7 +405,9 @@ func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string,
 		return err
 		return err
 	}
 	}
 	for i, sheetData := range workbookData {
 	for i, sheetData := range workbookData {
-		currentHeaderTypes := headerTypes[i]
+
+		currentSheetCellTypes := cellTypes[i]
+		currentSheetCellStyles := cellStyles[i]
 		if i != 0 {
 		if i != 0 {
 			err = streamFile.NextSheet()
 			err = streamFile.NextSheet()
 			if err != nil {
 			if err != nil {
@@ -370,7 +418,9 @@ func writeStreamFile(filePath string, fileBuffer io.Writer, sheetNames []string,
 			if i == 0 {
 			if i == 0 {
 				continue
 				continue
 			}
 			}
-			err = streamFile.Write(row, currentHeaderTypes)
+			currentCellStyles := currentSheetCellStyles[i]
+			currentCellTypes := currentSheetCellTypes[i]
+			err = streamFile.Write(row, currentCellTypes, currentCellStyles)
 			if err != nil {
 			if err != nil {
 				return err
 				return err
 			}
 			}
@@ -422,11 +472,11 @@ func readXLSXFile(t *C, filePath string, fileBuffer io.ReaderAt, size int64, sho
 func (s *StreamSuite) TestAddSheetErrorsAfterBuild(t *C) {
 func (s *StreamSuite) TestAddSheetErrorsAfterBuild(t *C) {
 	file := NewStreamFileBuilder(bytes.NewBuffer(nil))
 	file := NewStreamFileBuilder(bytes.NewBuffer(nil))
 
 
-	err := file.AddSheet("Sheet1", []interface{}{"Header"}, nil)
+	err := file.AddSheet("Sheet1", []string{"Header"}, []int{0}, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	err = file.AddSheet("Sheet2", []interface{}{"Header2"}, nil)
+	err = file.AddSheet("Sheet2", []string{"Header2"}, []int{0}, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -435,7 +485,7 @@ func (s *StreamSuite) TestAddSheetErrorsAfterBuild(t *C) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	err = file.AddSheet("Sheet3", []interface{}{"Header3"}, nil)
+	err = file.AddSheet("Sheet3", []string{"Header3"}, []int{0}, nil)
 	if err != BuiltStreamFileBuilderError {
 	if err != BuiltStreamFileBuilderError {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -444,11 +494,11 @@ func (s *StreamSuite) TestAddSheetErrorsAfterBuild(t *C) {
 func (s *StreamSuite) TestBuildErrorsAfterBuild(t *C) {
 func (s *StreamSuite) TestBuildErrorsAfterBuild(t *C) {
 	file := NewStreamFileBuilder(bytes.NewBuffer(nil))
 	file := NewStreamFileBuilder(bytes.NewBuffer(nil))
 
 
-	err := file.AddSheet("Sheet1", []interface{}{"Header"}, nil)
+	err := file.AddSheet("Sheet1", []string{"Header"}, []int{0}, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	err = file.AddSheet("Sheet2", []interface{}{"Header2"}, nil)
+	err = file.AddSheet("Sheet2", []string{"Header2"}, []int{0}, nil)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -468,15 +518,23 @@ func (s *StreamSuite) TestCloseWithNothingWrittenToSheets(t *C) {
 	file := NewStreamFileBuilder(buffer)
 	file := NewStreamFileBuilder(buffer)
 
 
 	sheetNames := []string{"Sheet1", "Sheet2"}
 	sheetNames := []string{"Sheet1", "Sheet2"}
-	workbookData := [][][]interface{}{
+	workbookData := [][][]string{
 		{{"Header1", "Header2"}},
 		{{"Header1", "Header2"}},
 		{{"Header3", "Header4"}},
 		{{"Header3", "Header4"}},
 	}
 	}
-	err := file.AddSheet(sheetNames[0], workbookData[0][0], nil)
+	cellStyles := [][][]int{
+		{{0, 0}},
+		{{0, 0}},
+	}
+	cellTypes := [][][]*CellType{
+		{{CellTypeString.Ptr(), CellTypeString.Ptr()}},
+		{{CellTypeString.Ptr(), CellTypeString.Ptr()}},
+	}
+	err := file.AddSheet(sheetNames[0], workbookData[0][0], cellStyles[0][0], cellTypes[0][0])
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	err = file.AddSheet(sheetNames[1], workbookData[1][0], nil)
+	err = file.AddSheet(sheetNames[1], workbookData[1][0], cellStyles[1][0], cellTypes[1][0])
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}