ソースを参照

Custom marshalling of styles, including NumFmts.

Geoffrey J. Teale 11 年 前
コミット
26d82a72a2
9 ファイル変更415 行追加118 行削除
  1. 3 2
      cell.go
  2. 4 4
      cell_test.go
  3. 3 2
      file.go
  4. 1 1
      file_test.go
  5. 3 3
      row.go
  6. 6 2
      sheet.go
  7. 4 1
      style.go
  8. 3 1
      style_test.go
  9. 388 102
      xmlStyle.go

+ 3 - 2
cell.go

@@ -9,6 +9,7 @@ import (
 // Cell is a high level structure intended to provide user access to
 // Cell is a high level structure intended to provide user access to
 // the contents of Cell within an xlsx.Row.
 // the contents of Cell within an xlsx.Row.
 type Cell struct {
 type Cell struct {
+	Row      Row
 	Value    string
 	Value    string
 	style    Style
 	style    Style
 	numFmt   string
 	numFmt   string
@@ -22,8 +23,8 @@ type CellInterface interface {
 	FormattedValue() string
 	FormattedValue() string
 }
 }
 
 
-func NewCell() *Cell {
-	return &Cell{style: *NewStyle()}
+func NewCell(r Row) *Cell {
+	return &Cell{style: *NewStyle(), Row: r}
 }
 }
 
 
 // String returns the value of a Cell as a string.
 // String returns the value of a Cell as a string.

+ 4 - 4
cell_test.go

@@ -43,7 +43,7 @@ func (s *CellSuite) TestSetStyleWithFonts(c *C) {
 	style.Font = *font
 	style.Font = *font
 	cell.SetStyle(style)
 	cell.SetStyle(style)
 	style = cell.GetStyle()
 	style = cell.GetStyle()
-	xFont, _, _, _, _ := style.makeXLSXStyleElements()
+	_, xFont, _, _, _, _ := style.makeXLSXStyleElements()
 	c.Assert(xFont.Sz.Val, Equals, "12")
 	c.Assert(xFont.Sz.Val, Equals, "12")
 	c.Assert(xFont.Name.Val, Equals, "Calibra")
 	c.Assert(xFont.Name.Val, Equals, "Calibra")
 }
 }
@@ -55,7 +55,7 @@ func (s *CellSuite) TestGetStyleWithFills(c *C) {
 	style.Fill = fill
 	style.Fill = fill
 	cell := &Cell{Value: "123", style: style}
 	cell := &Cell{Value: "123", style: style}
 	style = cell.GetStyle()
 	style = cell.GetStyle()
-	_, xFill, _, _, _ := style.makeXLSXStyleElements()
+	_, _, xFill, _, _, _ := style.makeXLSXStyleElements()
 	c.Assert(xFill.PatternFill.PatternType, Equals, "solid")
 	c.Assert(xFill.PatternFill.PatternType, Equals, "solid")
 	c.Assert(xFill.PatternFill.BgColor.RGB, Equals, "00FF0000")
 	c.Assert(xFill.PatternFill.BgColor.RGB, Equals, "00FF0000")
 	c.Assert(xFill.PatternFill.FgColor.RGB, Equals, "FF000000")
 	c.Assert(xFill.PatternFill.FgColor.RGB, Equals, "FF000000")
@@ -72,7 +72,7 @@ func (s *CellSuite) TestSetStyleWithFills(c *C) {
 	style.Fill = *fill
 	style.Fill = *fill
 	cell.SetStyle(style)
 	cell.SetStyle(style)
 	style = cell.GetStyle()
 	style = cell.GetStyle()
-	_, xFill, _, _, _ := style.makeXLSXStyleElements()
+	_, _, xFill, _, _, _ := style.makeXLSXStyleElements()
 	xPatternFill := xFill.PatternFill
 	xPatternFill := xFill.PatternFill
 	c.Assert(xPatternFill.PatternType, Equals, "solid")
 	c.Assert(xPatternFill.PatternType, Equals, "solid")
 	c.Assert(xPatternFill.FgColor.RGB, Equals, "00FF0000")
 	c.Assert(xPatternFill.FgColor.RGB, Equals, "00FF0000")
@@ -86,7 +86,7 @@ func (s *CellSuite) TestGetStyleWithBorders(c *C) {
 	style.Border = border
 	style.Border = border
 	cell := Cell{Value: "123", style: style}
 	cell := Cell{Value: "123", style: style}
 	style = cell.GetStyle()
 	style = cell.GetStyle()
-	_, _, xBorder, _, _ := style.makeXLSXStyleElements()
+	_, _, _, xBorder, _, _ := style.makeXLSXStyleElements()
 	c.Assert(xBorder.Left.Style, Equals, "thin")
 	c.Assert(xBorder.Left.Style, Equals, "thin")
 	c.Assert(xBorder.Right.Style, Equals, "thin")
 	c.Assert(xBorder.Right.Style, Equals, "thin")
 	c.Assert(xBorder.Top.Style, Equals, "thin")
 	c.Assert(xBorder.Top.Style, Equals, "thin")

+ 3 - 2
file.go

@@ -13,7 +13,7 @@ import (
 // to the user.
 // to the user.
 type File struct {
 type File struct {
 	worksheets     map[string]*zip.File
 	worksheets     map[string]*zip.File
-	numFmtRefTable map[int]xlsxNumFmt
+	numFmtRefTable NumFmtRefTable
 	referenceTable *RefTable
 	referenceTable *RefTable
 	Date1904       bool
 	Date1904       bool
 	styles         *xlsxStyleSheet
 	styles         *xlsxStyleSheet
@@ -24,6 +24,7 @@ type File struct {
 // Create a new File
 // Create a new File
 func NewFile() (file *File) {
 func NewFile() (file *File) {
 	file = &File{}
 	file = &File{}
+	file.numFmtRefTable = make(NumFmtRefTable)
 	file.Sheet = make(map[string]*Sheet)
 	file.Sheet = make(map[string]*Sheet)
 	file.Sheets = make([]*Sheet, 0)
 	file.Sheets = make([]*Sheet, 0)
 	return
 	return
@@ -101,7 +102,7 @@ func (f *File) Save(path string) (err error) {
 
 
 // Add a new Sheet, with the provided name, to a File
 // Add a new Sheet, with the provided name, to a File
 func (f *File) AddSheet(sheetName string) (sheet *Sheet) {
 func (f *File) AddSheet(sheetName string) (sheet *Sheet) {
-	sheet = &Sheet{Name: sheetName}
+	sheet = &Sheet{Name: sheetName, File: *f}
 	f.Sheet[sheetName] = sheet
 	f.Sheet[sheetName] = sheet
 	f.Sheets = append(f.Sheets, sheet)
 	f.Sheets = append(f.Sheets, sheet)
 	return sheet
 	return sheet

+ 1 - 1
file_test.go

@@ -650,7 +650,7 @@ func (l *FileSuite) TestMarshalFile(c *C) {
 	// For now we only allow simple string data in the
 	// For now we only allow simple string data in the
 	// spreadsheet.  Style support will follow.
 	// spreadsheet.  Style support will follow.
 	expectedStyles := `<?xml version="1.0" encoding="UTF-8"?>
 	expectedStyles := `<?xml version="1.0" encoding="UTF-8"?>
-<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><fonts count="2"><font><sz val="12"></sz><name val="Verdana"></name><family val="0"></family><charset val="0"></charset><color></color></font><font><sz val="12"></sz><name val="Verdana"></name><family val="0"></family><charset val="0"></charset><color></color></font></fonts><fills count="2"><fill><patternFill><fgColor></fgColor><bgColor></bgColor></patternFill></fill><fill><patternFill><fgColor></fgColor><bgColor></bgColor></patternFill></fill></fills><borders count="2"><border><left></left><right></right><top></top><bottom></bottom></border><border><left></left><right></right><top></top><bottom></bottom></border></borders><cellStyleXfs count="2"><xf applyAlignment="false" applyBorder="false" applyFont="false" applyFill="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"></xf><xf applyAlignment="false" applyBorder="false" applyFont="false" applyFill="false" applyProtection="false" borderId="1" fillId="1" fontId="1" numFmtId="0"></xf></cellStyleXfs><cellXfs count="2"><xf applyAlignment="false" applyBorder="false" applyFont="false" applyFill="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"></xf><xf applyAlignment="false" applyBorder="false" applyFont="false" applyFill="false" applyProtection="false" borderId="1" fillId="1" fontId="1" numFmtId="0"></xf></cellXfs><numFmts count="0"></numFmts></styleSheet>`
+<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><numFmts count="1"><numFmt numFmtId="164" formatCode="GENERAL"/></numFmts><fonts count="2"><font><sz val="12"/><name val="Verdana"/><family val="0"/><charset val="0"/></font><font><sz val="12"/><name val="Verdana"/><family val="0"/><charset val="0"/></font></fonts><cellStyleXfs count="2"><xf applyAlignment="false" applyBorder="false" applyFont="false" applyFill="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="164"><alignment horizontal="" indent="0" shrinkToFit="false" textRotation="0" vertical="" wrapText="false"/></xf><xf applyAlignment="false" applyBorder="false" applyFont="false" applyFill="false" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="164"><alignment horizontal="" indent="0" shrinkToFit="false" textRotation="0" vertical="" wrapText="false"/></xf></cellStyleXfs><cellXfs count="2"><xf applyAlignment="false" applyBorder="false" applyFont="false" applyFill="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="164"><alignment horizontal="" indent="0" shrinkToFit="false" textRotation="0" vertical="" wrapText="false"/></xf><xf applyAlignment="false" applyBorder="false" applyFont="false" applyFill="false" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="164"><alignment horizontal="" indent="0" shrinkToFit="false" textRotation="0" vertical="" wrapText="false"/></xf></cellXfs></styleSheet>`
 	c.Assert(parts["xl/styles.xml"], Equals, expectedStyles)
 	c.Assert(parts["xl/styles.xml"], Equals, expectedStyles)
 }
 }
 
 

+ 3 - 3
row.go

@@ -3,12 +3,12 @@ package xlsx
 type Row struct {
 type Row struct {
 	Cells  []*Cell
 	Cells  []*Cell
 	Hidden bool
 	Hidden bool
-	sheet  *Sheet
+	Sheet  *Sheet
 }
 }
 
 
 func (r *Row) AddCell() *Cell {
 func (r *Row) AddCell() *Cell {
-	cell := NewCell()
+	cell := NewCell(*r)
 	r.Cells = append(r.Cells, cell)
 	r.Cells = append(r.Cells, cell)
-	r.sheet.maybeAddCol(len(r.Cells))
+	r.Sheet.maybeAddCol(len(r.Cells))
 	return cell
 	return cell
 }
 }

+ 6 - 2
sheet.go

@@ -9,6 +9,7 @@ import (
 // the contents of a particular sheet within an XLSX file.
 // the contents of a particular sheet within an XLSX file.
 type Sheet struct {
 type Sheet struct {
 	Name   string
 	Name   string
+	File   File
 	Rows   []*Row
 	Rows   []*Row
 	Cols   []*Col
 	Cols   []*Col
 	MaxRow int
 	MaxRow int
@@ -18,7 +19,7 @@ type Sheet struct {
 
 
 // Add a new Row to a Sheet
 // Add a new Row to a Sheet
 func (s *Sheet) AddRow() *Row {
 func (s *Sheet) AddRow() *Row {
-	row := &Row{sheet: s}
+	row := &Row{Sheet: s}
 	s.Rows = append(s.Rows, row)
 	s.Rows = append(s.Rows, row)
 	if len(s.Rows) > s.MaxRow {
 	if len(s.Rows) > s.MaxRow {
 		s.MaxRow = len(s.Rows)
 		s.MaxRow = len(s.Rows)
@@ -72,16 +73,19 @@ func (s *Sheet) makeXLSXSheet(refTable *RefTable, styles *xlsxStyleSheet) *xlsxW
 		xRow.R = r + 1
 		xRow.R = r + 1
 		for c, cell := range row.Cells {
 		for c, cell := range row.Cells {
 			style := cell.GetStyle()
 			style := cell.GetStyle()
-			xFont, xFill, xBorder, xCellStyleXf, xCellXf := style.makeXLSXStyleElements()
+			xNumFmt, xFont, xFill, xBorder, xCellStyleXf, xCellXf := style.makeXLSXStyleElements()
 			fontId := styles.addFont(xFont)
 			fontId := styles.addFont(xFont)
 			fillId := styles.addFill(xFill)
 			fillId := styles.addFill(xFill)
 			borderId := styles.addBorder(xBorder)
 			borderId := styles.addBorder(xBorder)
+			styles.addNumFmt(xNumFmt, s.File.numFmtRefTable)
 			xCellStyleXf.FontId = fontId
 			xCellStyleXf.FontId = fontId
 			xCellStyleXf.FillId = fillId
 			xCellStyleXf.FillId = fillId
 			xCellStyleXf.BorderId = borderId
 			xCellStyleXf.BorderId = borderId
+			xCellStyleXf.NumFmtId = xNumFmt.NumFmtId
 			xCellXf.FontId = fontId
 			xCellXf.FontId = fontId
 			xCellXf.FillId = fillId
 			xCellXf.FillId = fillId
 			xCellXf.BorderId = borderId
 			xCellXf.BorderId = borderId
+			xCellXf.NumFmtId = xNumFmt.NumFmtId
 			styleXfId := styles.addCellStyleXf(xCellStyleXf)
 			styleXfId := styles.addCellStyleXf(xCellStyleXf)
 			XfId := styles.addCellXf(xCellXf)
 			XfId := styles.addCellXf(xCellXf)
 			if styleXfId != XfId {
 			if styleXfId != XfId {

+ 4 - 1
style.go

@@ -19,7 +19,10 @@ func NewStyle() *Style {
 }
 }
 
 
 // Generate the underlying XLSX style elements that correspond to the Style.
 // Generate the underlying XLSX style elements that correspond to the Style.
-func (style *Style) makeXLSXStyleElements() (xFont xlsxFont, xFill xlsxFill, xBorder xlsxBorder, xCellStyleXf xlsxXf, xCellXf xlsxXf) {
+func (style *Style) makeXLSXStyleElements() (xNumFmt xlsxNumFmt, xFont xlsxFont, xFill xlsxFill, xBorder xlsxBorder, xCellStyleXf xlsxXf, xCellXf xlsxXf) {
+	// We always set the general numberformat for now.
+	xNumFmt = xlsxNumFmt{NumFmtId: 164, FormatCode: "GENERAL"}
+
 	xFont = xlsxFont{}
 	xFont = xlsxFont{}
 	xFill = xlsxFill{}
 	xFill = xlsxFill{}
 	xBorder = xlsxBorder{}
 	xBorder = xlsxBorder{}

+ 3 - 1
style_test.go

@@ -24,7 +24,9 @@ func (s *StyleSuite) TestMakeXLSXStyleElements(c *C) {
 	style.ApplyBorder = true
 	style.ApplyBorder = true
 	style.ApplyFill = true
 	style.ApplyFill = true
 	style.ApplyFont = true
 	style.ApplyFont = true
-	xFont, xFill, xBorder, xCellStyleXf, xCellXf := style.makeXLSXStyleElements()
+	xNumFmt, xFont, xFill, xBorder, xCellStyleXf, xCellXf := style.makeXLSXStyleElements()
+	c.Assert(xNumFmt.NumFmtId, Equals, 164)
+	c.Assert(xNumFmt.FormatCode, Equals, "GENERAL")
 	c.Assert(xFont.Sz.Val, Equals, "12")
 	c.Assert(xFont.Sz.Val, Equals, "12")
 	c.Assert(xFont.Name.Val, Equals, "Verdana")
 	c.Assert(xFont.Name.Val, Equals, "Verdana")
 	c.Assert(xFill.PatternFill.PatternType, Equals, "solid")
 	c.Assert(xFill.PatternFill.PatternType, Equals, "solid")

+ 388 - 102
xmlStyle.go

@@ -9,10 +9,13 @@ package xlsx
 
 
 import (
 import (
 	"encoding/xml"
 	"encoding/xml"
+	"fmt"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 )
 )
 
 
+type NumFmtRefTable map[int]xlsxNumFmt
+
 // xlsxStyle directly maps the styleSheet element in the namespace
 // xlsxStyle directly maps the styleSheet element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -28,6 +31,171 @@ type xlsxStyleSheet struct {
 	NumFmts      xlsxNumFmts      `xml:"numFmts,omitempty"`
 	NumFmts      xlsxNumFmts      `xml:"numFmts,omitempty"`
 }
 }
 
 
+func (styles *xlsxStyleSheet) getStyle(styleIndex int) (style Style) {
+	var styleXf xlsxXf
+	style = Style{}
+	style.Border = Border{}
+	style.Fill = Fill{}
+	style.Font = Font{}
+
+	xfCount := styles.CellXfs.Count
+	if styleIndex > -1 && xfCount > 0 && styleIndex <= xfCount {
+		xf := styles.CellXfs.Xf[styleIndex]
+
+		// Google docs can produce output that has fewer
+		// CellStyleXfs than CellXfs - this copes with that.
+		if styleIndex < styles.CellStyleXfs.Count {
+			styleXf = styles.CellStyleXfs.Xf[styleIndex]
+		} else {
+			styleXf = xlsxXf{}
+		}
+
+		style.ApplyBorder = xf.ApplyBorder || styleXf.ApplyBorder
+		style.ApplyFill = xf.ApplyFill || styleXf.ApplyFill
+		style.ApplyFont = xf.ApplyFont || styleXf.ApplyFont
+
+		if xf.BorderId > -1 && xf.BorderId < styles.Borders.Count {
+			style.Border.Left = styles.Borders.Border[xf.BorderId].Left.Style
+			style.Border.Right = styles.Borders.Border[xf.BorderId].Right.Style
+			style.Border.Top = styles.Borders.Border[xf.BorderId].Top.Style
+			style.Border.Bottom = styles.Borders.Border[xf.BorderId].Bottom.Style
+		}
+
+		if xf.FillId > -1 && xf.FillId < styles.Fills.Count {
+			xFill := styles.Fills.Fill[xf.FillId]
+			style.Fill.PatternType = xFill.PatternFill.PatternType
+			style.Fill.FgColor = xFill.PatternFill.FgColor.RGB
+			style.Fill.BgColor = xFill.PatternFill.BgColor.RGB
+		}
+
+		if xf.FontId > -1 && xf.FontId < styles.Fonts.Count {
+			xfont := styles.Fonts.Font[xf.FontId]
+			style.Font.Size, _ = strconv.Atoi(xfont.Sz.Val)
+			style.Font.Name = xfont.Name.Val
+			style.Font.Family, _ = strconv.Atoi(xfont.Family.Val)
+			style.Font.Charset, _ = strconv.Atoi(xfont.Charset.Val)
+		}
+	}
+	return style
+
+}
+
+func (styles *xlsxStyleSheet) getNumberFormat(styleIndex int, numFmtRefTable map[int]xlsxNumFmt) string {
+	if styles.CellXfs.Xf == nil {
+		return ""
+	}
+	var numberFormat string = ""
+	if styleIndex > -1 && styleIndex <= styles.CellXfs.Count {
+		xf := styles.CellXfs.Xf[styleIndex]
+		numFmt := numFmtRefTable[xf.NumFmtId]
+		numberFormat = numFmt.FormatCode
+	}
+	return strings.ToLower(numberFormat)
+}
+
+func (styles *xlsxStyleSheet) addFont(xFont xlsxFont) (index int) {
+	styles.Fonts.Font = append(styles.Fonts.Font, xFont)
+	index = styles.Fonts.Count
+	styles.Fonts.Count += 1
+	return
+}
+
+func (styles *xlsxStyleSheet) addFill(xFill xlsxFill) (index int) {
+	styles.Fills.Fill = append(styles.Fills.Fill, xFill)
+	index = styles.Fills.Count
+	styles.Fills.Count += 1
+	return
+}
+
+func (styles *xlsxStyleSheet) addBorder(xBorder xlsxBorder) (index int) {
+	styles.Borders.Border = append(styles.Borders.Border, xBorder)
+	index = styles.Borders.Count
+	styles.Borders.Count += 1
+	return
+}
+
+func (styles *xlsxStyleSheet) addCellStyleXf(xCellStyleXf xlsxXf) (index int) {
+	styles.CellStyleXfs.Xf = append(styles.CellStyleXfs.Xf, xCellStyleXf)
+	index = styles.CellStyleXfs.Count
+	styles.CellStyleXfs.Count += 1
+	return
+}
+
+func (styles *xlsxStyleSheet) addCellXf(xCellXf xlsxXf) (index int) {
+	styles.CellXfs.Xf = append(styles.CellXfs.Xf, xCellXf)
+	index = styles.CellXfs.Count
+	styles.CellXfs.Count += 1
+	return
+}
+
+func (styles *xlsxStyleSheet) addNumFmt(xNumFmt xlsxNumFmt, numFmtRefTable NumFmtRefTable) (index int) {
+	numFmt, ok := numFmtRefTable[xNumFmt.NumFmtId]
+	if !ok {
+		styles.NumFmts.NumFmt = append(styles.NumFmts.NumFmt, xNumFmt)
+		numFmtRefTable[xNumFmt.NumFmtId] = xNumFmt
+		index = styles.NumFmts.Count
+		styles.NumFmts.Count += 1
+		return
+	}
+	numFmt.FormatCode = xNumFmt.FormatCode
+	return
+}
+
+func (styles *xlsxStyleSheet) Marshal() (result string, err error) {
+	var xNumFmts string
+	var xfonts string
+	var xfills string
+	var xborders string
+	var xcellStyleXfs string
+	var xcellXfs string
+
+	var outputFontMap map[int]int = make(map[int]int)
+	var outputFillMap map[int]int = make(map[int]int)
+	var outputBorderMap map[int]int = make(map[int]int)
+
+	result = xml.Header
+	result += `<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`
+
+	xNumFmts, err = styles.NumFmts.Marshal()
+	if err != nil {
+		return
+	}
+	result += xNumFmts
+
+	xfonts, err = styles.Fonts.Marshal(outputFontMap)
+	if err != nil {
+		return
+	}
+	result += xfonts
+
+	xfills, err = styles.Fills.Marshal(outputFillMap)
+	if err != nil {
+		return
+	}
+	result += xfills
+
+	xborders, err = styles.Borders.Marshal(outputBorderMap)
+	if err != nil {
+		return
+	}
+	result += xborders
+
+	xcellStyleXfs, err = styles.CellStyleXfs.Marshal(outputBorderMap, outputFillMap, outputFontMap)
+	if err != nil {
+		return
+	}
+	result += xcellStyleXfs
+
+	xcellXfs, err = styles.CellXfs.Marshal(outputBorderMap, outputFillMap, outputFontMap)
+	if err != nil {
+		return
+	}
+	result += xcellXfs
+
+	result += `</styleSheet>`
+	return
+}
+
 // xlsxNumFmts directly maps the numFmts element in the namespace
 // xlsxNumFmts directly maps the numFmts element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -37,6 +205,22 @@ type xlsxNumFmts struct {
 	NumFmt []xlsxNumFmt `xml:"numFmt,omitempty"`
 	NumFmt []xlsxNumFmt `xml:"numFmt,omitempty"`
 }
 }
 
 
+func (numFmts *xlsxNumFmts) Marshal() (result string, err error) {
+	if numFmts.Count > 0 {
+		result = fmt.Sprintf(`<numFmts count="%d">`, numFmts.Count)
+		for _, numFmt := range numFmts.NumFmt {
+			var xNumFmt string
+			xNumFmt, err = numFmt.Marshal()
+			if err != nil {
+				return
+			}
+			result += xNumFmt
+		}
+		result += `</numFmts>`
+	}
+	return
+}
+
 // xlsxNumFmt directly maps the numFmt element in the namespace
 // xlsxNumFmt directly maps the numFmt element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -46,15 +230,45 @@ type xlsxNumFmt struct {
 	FormatCode string `xml:"formatCode,omitempty"`
 	FormatCode string `xml:"formatCode,omitempty"`
 }
 }
 
 
+func (numFmt *xlsxNumFmt) Marshal() (result string, err error) {
+	return fmt.Sprintf(`<numFmt numFmtId="%d" formatCode="%s"/>`, numFmt.NumFmtId, numFmt.FormatCode), nil
+}
+
 // xlsxFonts directly maps the fonts element in the namespace
 // xlsxFonts directly maps the fonts element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
 // as I need.
 // as I need.
 type xlsxFonts struct {
 type xlsxFonts struct {
+	XMLName xml.Name `xml:"fonts"`
+
 	Count int        `xml:"count,attr"`
 	Count int        `xml:"count,attr"`
 	Font  []xlsxFont `xml:"font,omitempty"`
 	Font  []xlsxFont `xml:"font,omitempty"`
 }
 }
 
 
+func (fonts *xlsxFonts) Marshal(outputFontMap map[int]int) (result string, err error) {
+	emittedCount := 0
+	subparts := ""
+
+	for i, font := range fonts.Font {
+		var xfont string
+		xfont, err = font.Marshal()
+		if err != nil {
+			return
+		}
+		if xfont != "" {
+			outputFontMap[i] = emittedCount
+			emittedCount += 1
+			subparts += xfont
+		}
+	}
+	if emittedCount > 0 {
+		result = fmt.Sprintf(`<fonts count="%d">`, fonts.Count)
+		result += subparts
+		result += `</fonts>`
+	}
+	return
+}
+
 // xlsxFont directly maps the font element in the namespace
 // xlsxFont directly maps the font element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -67,6 +281,27 @@ type xlsxFont struct {
 	Color   xlsxColor `xml:"color,omitempty"`
 	Color   xlsxColor `xml:"color,omitempty"`
 }
 }
 
 
+func (font *xlsxFont) Marshal() (result string, err error) {
+	result = `<font>`
+	if font.Sz.Val != "" {
+		result += fmt.Sprintf(`<sz val="%s"/>`, font.Sz.Val)
+	}
+	if font.Name.Val != "" {
+		result += fmt.Sprintf(`<name val="%s"/>`, font.Name.Val)
+	}
+	if font.Family.Val != "" {
+		result += fmt.Sprintf(`<family val="%s"/>`, font.Family.Val)
+	}
+	if font.Charset.Val != "" {
+		result += fmt.Sprintf(`<charset val="%s"/>`, font.Charset.Val)
+	}
+	if font.Color.RGB != "" {
+		result += fmt.Sprintf(`<color rgb="%s"/>`, font.Color.RGB)
+	}
+	result += `</font>`
+	return
+}
+
 // xlsxVal directly maps the val element in the namespace
 // xlsxVal directly maps the val element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -84,6 +319,29 @@ type xlsxFills struct {
 	Fill  []xlsxFill `xml:"fill,omitempty"`
 	Fill  []xlsxFill `xml:"fill,omitempty"`
 }
 }
 
 
+func (fills *xlsxFills) Marshal(outputFillMap map[int]int) (result string, err error) {
+	emittedCount := 0
+	subparts := ""
+	for i, fill := range fills.Fill {
+		var xfill string
+		xfill, err = fill.Marshal()
+		if err != nil {
+			return
+		}
+		if xfill != "" {
+			outputFillMap[i] = emittedCount
+			emittedCount += 1
+			subparts += xfill
+		}
+	}
+	if emittedCount > 0 {
+		result = fmt.Sprintf(`<fills count="%d">`, emittedCount)
+		result += subparts
+		result += `</fills>`
+	}
+	return
+}
+
 // xlsxFill directly maps the fill element in the namespace
 // xlsxFill directly maps the fill element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -92,6 +350,21 @@ type xlsxFill struct {
 	PatternFill xlsxPatternFill `xml:"patternFill,omitempty"`
 	PatternFill xlsxPatternFill `xml:"patternFill,omitempty"`
 }
 }
 
 
+func (fill *xlsxFill) Marshal() (result string, err error) {
+	if fill.PatternFill.PatternType != "" {
+		var xpatternFill string
+		result = `<fill>`
+
+		xpatternFill, err = fill.PatternFill.Marshal()
+		if err != nil {
+			return
+		}
+		result += xpatternFill
+		result += `</fill>`
+	}
+	return
+}
+
 // xlsxPatternFill directly maps the patternFill element in the namespace
 // xlsxPatternFill directly maps the patternFill element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -102,6 +375,24 @@ type xlsxPatternFill struct {
 	BgColor     xlsxColor `xml:"bgColor,omitempty"`
 	BgColor     xlsxColor `xml:"bgColor,omitempty"`
 }
 }
 
 
+func (patternFill *xlsxPatternFill) Marshal() (result string, err error) {
+	result = fmt.Sprintf(`<patternFill patternType="%s"`, patternFill.PatternType)
+	ending := `/>`
+	subparts := ""
+	if patternFill.FgColor.RGB != "" {
+		ending = `>`
+		subparts += fmt.Sprintf(`<fgColor rgb="%s"/>`, patternFill.FgColor.RGB)
+	}
+	if patternFill.BgColor.RGB != "" {
+		ending = `>`
+		subparts += fmt.Sprintf(`<bgColor rgb="%s"/>`, patternFill.BgColor.RGB)
+	}
+	result += ending
+	result += subparts
+	result += `</patternFill>`
+	return
+}
+
 // xlsxColor is a common mapping used for both the fgColor and bgColor
 // xlsxColor is a common mapping used for both the fgColor and bgColor
 // elements in the namespace
 // elements in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
@@ -120,6 +411,30 @@ type xlsxBorders struct {
 	Border []xlsxBorder `xml:"border,omitempty"`
 	Border []xlsxBorder `xml:"border,omitempty"`
 }
 }
 
 
+func (borders *xlsxBorders) Marshal(outputBorderMap map[int]int) (result string, err error) {
+	result = ""
+	emittedCount := 0
+	subparts := ""
+	for i, border := range borders.Border {
+		var xborder string
+		xborder, err = border.Marshal()
+		if err != nil {
+			return
+		}
+		if xborder != "" {
+			outputBorderMap[i] = emittedCount
+			emittedCount += 1
+			subparts += xborder
+		}
+	}
+	if emittedCount > 0 {
+		result += fmt.Sprintf(`<borders count="%d">`, emittedCount)
+		result += subparts
+		result += `</borders>`
+	}
+	return
+}
+
 // xlsxBorder directly maps the border element in the namespace
 // xlsxBorder directly maps the border element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -131,6 +446,33 @@ type xlsxBorder struct {
 	Bottom xlsxLine `xml:"bottom,omitempty"`
 	Bottom xlsxLine `xml:"bottom,omitempty"`
 }
 }
 
 
+func (border *xlsxBorder) Marshal() (result string, err error) {
+	emit := false
+	subparts := ""
+	if border.Left.Style != "" {
+		emit = true
+		subparts += fmt.Sprintf(`<left style="%s"/>`, border.Left.Style)
+	}
+	if border.Right.Style != "" {
+		emit = true
+		subparts += fmt.Sprintf(`<right style="%s"/>`, border.Right.Style)
+	}
+	if border.Top.Style != "" {
+		emit = true
+		subparts += fmt.Sprintf(`<top style="%s"/>`, border.Top.Style)
+	}
+	if border.Bottom.Style != "" {
+		emit = true
+		subparts += fmt.Sprintf(`<bottom style="%s"/>`, border.Bottom.Style)
+	}
+	if emit {
+		result += `<border>`
+		result += subparts
+		result += `</border>`
+	}
+	return
+}
+
 // xlsxLine directly maps the line style element in the namespace
 // xlsxLine directly maps the line style element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -148,6 +490,22 @@ type xlsxCellStyleXfs struct {
 	Xf    []xlsxXf `xml:"xf,omitempty"`
 	Xf    []xlsxXf `xml:"xf,omitempty"`
 }
 }
 
 
+func (cellStyleXfs *xlsxCellStyleXfs) Marshal(outputBorderMap, outputFillMap, outputFontMap map[int]int) (result string, err error) {
+	if cellStyleXfs.Count > 0 {
+		result = fmt.Sprintf(`<cellStyleXfs count="%d">`, cellStyleXfs.Count)
+		for _, xf := range cellStyleXfs.Xf {
+			var xxf string
+			xxf, err = xf.Marshal(outputBorderMap, outputFillMap, outputFontMap)
+			if err != nil {
+				return
+			}
+			result += xxf
+		}
+		result += `</cellStyleXfs>`
+	}
+	return
+}
+
 // xlsxCellXfs directly maps the cellXfs element in the namespace
 // xlsxCellXfs directly maps the cellXfs element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -157,6 +515,22 @@ type xlsxCellXfs struct {
 	Xf    []xlsxXf `xml:"xf,omitempty"`
 	Xf    []xlsxXf `xml:"xf,omitempty"`
 }
 }
 
 
+func (cellXfs *xlsxCellXfs) Marshal(outputBorderMap, outputFillMap, outputFontMap map[int]int) (result string, err error) {
+	if cellXfs.Count > 0 {
+		result = fmt.Sprintf(`<cellXfs count="%d">`, cellXfs.Count)
+		for _, xf := range cellXfs.Xf {
+			var xxf string
+			xxf, err = xf.Marshal(outputBorderMap, outputFillMap, outputFontMap)
+			if err != nil {
+				return
+			}
+			result += xxf
+		}
+		result += `</cellXfs>`
+	}
+	return
+}
+
 // xlsxXf directly maps the xf element in the namespace
 // xlsxXf directly maps the xf element in the namespace
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // http://schemas.openxmlformats.org/spreadsheetml/2006/main -
 // currently I have not checked it for completeness - it does as much
 // currently I have not checked it for completeness - it does as much
@@ -174,6 +548,18 @@ type xlsxXf struct {
 	alignment       xlsxAlignment `xml:"alignment"`
 	alignment       xlsxAlignment `xml:"alignment"`
 }
 }
 
 
+func (xf *xlsxXf) Marshal(outputBorderMap, outputFillMap, outputFontMap map[int]int) (result string, err error) {
+	var xalignment string
+	result = fmt.Sprintf(`<xf applyAlignment="%t" applyBorder="%t" applyFont="%t" applyFill="%t" applyProtection="%t" borderId="%d" fillId="%d" fontId="%d" numFmtId="%d">`, xf.ApplyAlignment, xf.ApplyBorder, xf.ApplyFont, xf.ApplyFill, xf.ApplyProtection, outputBorderMap[xf.BorderId], outputFillMap[xf.FillId], outputFontMap[xf.FontId], xf.NumFmtId)
+	xalignment, err = xf.alignment.Marshal()
+	if err != nil {
+		return
+	}
+	result += xalignment
+	result += `</xf>`
+	return
+}
+
 type xlsxAlignment struct {
 type xlsxAlignment struct {
 	Horizontal   string `xml:"horizontal,attr"`
 	Horizontal   string `xml:"horizontal,attr"`
 	Indent       int    `xml:"indent,attr"`
 	Indent       int    `xml:"indent,attr"`
@@ -183,107 +569,7 @@ type xlsxAlignment struct {
 	WrapText     bool   `xml:"wrapText,attr"`
 	WrapText     bool   `xml:"wrapText,attr"`
 }
 }
 
 
-func (styles *xlsxStyleSheet) getStyle(styleIndex int) (style Style) {
-	var styleXf xlsxXf
-	style = Style{}
-	style.Border = Border{}
-	style.Fill = Fill{}
-	style.Font = Font{}
-
-	xfCount := styles.CellXfs.Count
-	if styleIndex > -1 && xfCount > 0 && styleIndex <= xfCount {
-		xf := styles.CellXfs.Xf[styleIndex]
-
-		// Google docs can produce output that has fewer
-		// CellStyleXfs than CellXfs - this copes with that.
-		if styleIndex < styles.CellStyleXfs.Count {
-			styleXf = styles.CellStyleXfs.Xf[styleIndex]
-		} else {
-			styleXf = xlsxXf{}
-		}
-
-		style.ApplyBorder = xf.ApplyBorder || styleXf.ApplyBorder
-		style.ApplyFill = xf.ApplyFill || styleXf.ApplyFill
-		style.ApplyFont = xf.ApplyFont || styleXf.ApplyFont
-
-		if xf.BorderId > -1 && xf.BorderId < styles.Borders.Count {
-			style.Border.Left = styles.Borders.Border[xf.BorderId].Left.Style
-			style.Border.Right = styles.Borders.Border[xf.BorderId].Right.Style
-			style.Border.Top = styles.Borders.Border[xf.BorderId].Top.Style
-			style.Border.Bottom = styles.Borders.Border[xf.BorderId].Bottom.Style
-		}
-
-		if xf.FillId > -1 && xf.FillId < styles.Fills.Count {
-			xFill := styles.Fills.Fill[xf.FillId]
-			style.Fill.PatternType = xFill.PatternFill.PatternType
-			style.Fill.FgColor = xFill.PatternFill.FgColor.RGB
-			style.Fill.BgColor = xFill.PatternFill.BgColor.RGB
-		}
-
-		if xf.FontId > -1 && xf.FontId < styles.Fonts.Count {
-			xfont := styles.Fonts.Font[xf.FontId]
-			style.Font.Size, _ = strconv.Atoi(xfont.Sz.Val)
-			style.Font.Name = xfont.Name.Val
-			style.Font.Family, _ = strconv.Atoi(xfont.Family.Val)
-			style.Font.Charset, _ = strconv.Atoi(xfont.Charset.Val)
-		}
-	}
-	return style
-
-}
-
-func (styles *xlsxStyleSheet) getNumberFormat(styleIndex int, numFmtRefTable map[int]xlsxNumFmt) string {
-	if styles.CellXfs.Xf == nil {
-		return ""
-	}
-	var numberFormat string = ""
-	if styleIndex > -1 && styleIndex <= styles.CellXfs.Count {
-		xf := styles.CellXfs.Xf[styleIndex]
-		numFmt := numFmtRefTable[xf.NumFmtId]
-		numberFormat = numFmt.FormatCode
-	}
-	return strings.ToLower(numberFormat)
-}
-
-func (styles *xlsxStyleSheet) addFont(xFont xlsxFont) (index int) {
-	styles.Fonts.Font = append(styles.Fonts.Font, xFont)
-	index = styles.Fonts.Count
-	styles.Fonts.Count += 1
-	return
-}
-
-func (styles *xlsxStyleSheet) addFill(xFill xlsxFill) (index int) {
-	styles.Fills.Fill = append(styles.Fills.Fill, xFill)
-	index = styles.Fills.Count
-	styles.Fills.Count += 1
-	return
-}
-
-func (styles *xlsxStyleSheet) addBorder(xBorder xlsxBorder) (index int) {
-	styles.Borders.Border = append(styles.Borders.Border, xBorder)
-	index = styles.Borders.Count
-	styles.Borders.Count += 1
-	return
-}
-
-func (styles *xlsxStyleSheet) addCellStyleXf(xCellStyleXf xlsxXf) (index int) {
-	styles.CellStyleXfs.Xf = append(styles.CellStyleXfs.Xf, xCellStyleXf)
-	index = styles.CellStyleXfs.Count
-	styles.CellStyleXfs.Count += 1
-	return
-}
-
-func (styles *xlsxStyleSheet) addCellXf(xCellXf xlsxXf) (index int) {
-	styles.CellXfs.Xf = append(styles.CellXfs.Xf, xCellXf)
-	index = styles.CellXfs.Count
-	styles.CellXfs.Count += 1
-	return
-}
-
-func (styles *xlsxStyleSheet) Marshal() (result string, err error) {
-	result = xml.Header
-	result += `<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
-`
-	result += `</styleSheet>`
+func (alignment *xlsxAlignment) Marshal() (result string, err error) {
+	result = fmt.Sprintf(`<alignment horizontal="%s" indent="%d" shrinkToFit="%t" textRotation="%d" vertical="%s" wrapText="%t"/>`, alignment.Horizontal, alignment.Indent, alignment.ShrinkToFit, alignment.TextRotation, alignment.Vertical, alignment.WrapText)
 	return
 	return
 }
 }