Browse Source

Switched over to using xml marchaling for cells

DamianSzkuat 6 years ago
parent
commit
465ee6ba20
2 changed files with 30 additions and 86 deletions
  1. 23 80
      stream_file.go
  2. 7 6
      xmlWorksheet.go

+ 23 - 80
stream_file.go

@@ -164,35 +164,21 @@ func (sf *StreamFile) writeS(cells []StreamCell) error {
 	// Add cells one by one
 	for colIndex, cell := range cells {
 
-		cellParts, err := sf.marshallCell(cell, colIndex)
-		if err != nil{
-			return err
-		}
-
-		// Write the cell opening
-		if err := sf.currentSheet.write(cellParts["cellOpen"]); err != nil {
-			return err
-		}
-
-		// Write the cell contents opening
-		if err := sf.currentSheet.write(cellParts["cellContentsOpen"]); err != nil {
+		xlsxCell, err := sf.getXlsxCell(cell, colIndex)
+		if err != nil {
 			return err
 		}
 
-		// Write cell contents
-		if err := xml.EscapeText(sf.currentSheet.writer, []byte(cellParts["cellContents"])); err != nil {
-			return err
+		marshaledCell, err := xml.Marshal(xlsxCell)
+		if err != nil {
+			return nil
 		}
 
-		// Write cell contents ending
-		if err := sf.currentSheet.write(cellParts["cellContentsClose"]); err != nil {
+		// Write the cell
+		if _, err := sf.currentSheet.writer.Write(marshaledCell); err != nil {
 			return err
 		}
 
-		// Write the cell ending
-		if err := sf.currentSheet.write(cellParts["cellClose"]); err != nil {
-			return err
-		}
 	}
 	// Write the row ending
 	if err := sf.currentSheet.write(`</row>`); err != nil {
@@ -201,53 +187,24 @@ func (sf *StreamFile) writeS(cells []StreamCell) error {
 	return sf.zipWriter.Flush()
 }
 
-func (sf *StreamFile) marshallCell(cell StreamCell, colIndex int) (map[string]string, error) {
+func (sf *StreamFile) getXlsxCell(cell StreamCell, colIndex int) (xlsxC, error) {
 	// Get the cell reference (location)
 	cellCoordinate := GetCellIDStringFromCoords(colIndex, sf.currentSheet.rowCount-1)
 
-	// Get the cell type string
-	cellType, err := getCellTypeAsString(cell.cellType)
-	if err != nil {
-		return nil, err
-	}
-
-	cellParts := make(map[string]string)
+	var cellStyleId int
 
-	// Build the XML cell opening
-	cellOpen := `<c r="` + cellCoordinate + `" t="` + cellType + `"`
-	// Add in the style id of the stream cell. If the streamStyle is empty, don't add a style,
-	// default column style will be used
-	if cell.cellStyle != (StreamStyle{}){
+	if cell.cellStyle != (StreamStyle{}) {
 		if idx, ok := sf.styleIdMap[cell.cellStyle]; ok {
-			cellOpen += ` s="` + strconv.Itoa(idx) + `"`
+			cellStyleId = idx
 		} else {
-			return nil, errors.New("trying to make use of a style that has not been added")
+			return xlsxC{}, errors.New("trying to make use of a style that has not been added")
 		}
 	}
-	cellOpen += `>`
 
-	cellParts["cellOpen"] = cellOpen
-
-	// The XML cell contents
-	cellContentsOpen, cellContentsClose, err := getCellContentOpenAncCloseTags(cell.cellType)
-	if err != nil {
-		return nil, err
-	}
-
-	cellParts["cellContentsOpen"] = cellContentsOpen
-	cellParts["cellContentsClose"] = cellContentsClose
-
-	cellParts["cellContents"] = cell.cellData
-
-	// The XMl cell ending
-	cellClose := `</c>`
-
-	cellParts["cellClose"] = cellClose
-
-	return cellParts, nil
+	return makeXlsxCell(cell.cellType, cellCoordinate, cellStyleId, cell.cellData)
 }
 
-func getCellTypeAsString(cellType CellType) (string, error) {
+func makeXlsxCell(cellType CellType, cellCoordinate string, cellStyleId int, cellData string) (xlsxC, error) {
 	// documentation for the c.t (cell.Type) attribute:
 	// b (Boolean): Cell containing a boolean.
 	// d (Date): Cell contains a date in the ISO 8601 format.
@@ -259,38 +216,24 @@ func getCellTypeAsString(cellType CellType) (string, error) {
 	// str (String): Cell containing a formula string.
 	switch cellType {
 	case CellTypeBool:
-		return "b", nil
+		return xlsxC{XMLName: xml.Name{Local: "c"}, R: cellCoordinate, S: cellStyleId, T: "b", V: cellData}, nil
 	case CellTypeDate:
-		return "d", nil
+		return xlsxC{XMLName: xml.Name{Local: "c"}, R: cellCoordinate, S: cellStyleId, T: "d", V: cellData}, nil
 	case CellTypeError:
-		return "e", nil
+		return xlsxC{XMLName: xml.Name{Local: "c"}, R: cellCoordinate, S: cellStyleId, T: "e", V: cellData}, nil
 	case CellTypeInline:
-		return "inlineStr", nil
+		return xlsxC{XMLName: xml.Name{Local: "c"}, R: cellCoordinate, S: cellStyleId, T: "inlineStr", Is: &xlsxSI{T: cellData}}, nil
 	case CellTypeNumeric:
-		return "n", nil
+		return xlsxC{XMLName: xml.Name{Local: "c"}, R: cellCoordinate, S: cellStyleId, T: "n", V: cellData}, nil
 	case CellTypeString:
 		// TODO Currently shared strings are types as inline strings
-		return "inlineStr", nil
+		return xlsxC{XMLName: xml.Name{Local: "c"}, R: cellCoordinate, S: cellStyleId, T: "inlineStr", Is: &xlsxSI{T: cellData}}, nil
 		// return "s", nil
 	case CellTypeStringFormula:
-		return "str", nil
-	default:
-		return "", UnsupportedCellTypeError
-	}
-}
-
-func getCellContentOpenAncCloseTags(cellType CellType) (string, string, error) {
-	switch cellType {
-	case CellTypeString:
-		// TODO Currently shared strings are types as inline strings
-		return `<is><t>`, `</t></is>`, nil
-	case CellTypeInline:
-		return `<is><t>`, `</t></is>`, nil
-	case CellTypeStringFormula:
-		// Formulas are currently not supported
-		return ``, ``, UnsupportedCellTypeError
+		// TODO currently not supported
+		return xlsxC{}, UnsupportedCellTypeError
 	default:
-		return `<v>`, `</v>`, nil
+		return xlsxC{}, UnsupportedCellTypeError
 	}
 }
 

+ 7 - 6
xmlWorksheet.go

@@ -335,12 +335,13 @@ func (mc *xlsxMergeCells) getExtent(cellRef string) (int, int, error) {
 // currently I have not checked it for completeness - it does as much
 // as I need.
 type xlsxC struct {
-	R  string  `xml:"r,attr"`           // Cell ID, e.g. A1
-	S  int     `xml:"s,attr,omitempty"` // Style reference.
-	T  string  `xml:"t,attr,omitempty"` // Type.
-	F  *xlsxF  `xml:"f,omitempty"`      // Formula
-	V  string  `xml:"v,omitempty"`      // Value
-	Is *xlsxSI `xml:"is,omitempty"`     // Inline String.
+	XMLName xml.Name
+	R       string  `xml:"r,attr"`           // Cell ID, e.g. A1
+	S       int     `xml:"s,attr,omitempty"` // Style reference.
+	T       string  `xml:"t,attr,omitempty"` // Type.
+	F       *xlsxF  `xml:"f,omitempty"`      // Formula
+	V       string  `xml:"v,omitempty"`      // Value
+	Is      *xlsxSI `xml:"is,omitempty"`     // Inline String.
 }
 
 // xlsxF directly maps the f element in the namespace