func (border *xlsxBorder) Marshal() (result string, err error) {
	subparts := ""
	subparts += fmt.Sprintf(`<left style="%s">`, border.Left.Style)
	if border.Left.Color.RGB != "" {
		subparts += fmt.Sprintf(`<color rgb="%s"/>`, border.Left.Color.RGB)
	}
	subparts += `</left>`
	subparts += fmt.Sprintf(`<right style="%s">`, border.Right.Style)
	if border.Right.Color.RGB != "" {
		subparts += fmt.Sprintf(`<color rgb="%s"/>`, border.Right.Color.RGB)
	}
	subparts += `</right>`
	subparts += fmt.Sprintf(`<top style="%s">`, border.Top.Style)
	if border.Top.Color.RGB != "" {
		subparts += fmt.Sprintf(`<color rgb="%s"/>`, border.Top.Color.RGB)
	}
	subparts += `</top>`
	subparts += fmt.Sprintf(`<bottom style="%s">`, border.Bottom.Style)
	if border.Bottom.Color.RGB != "" {
		subparts += fmt.Sprintf(`<color rgb="%s"/>`, border.Bottom.Color.RGB)
	}
	subparts += `</bottom>`
	result += `<border>`
	result += subparts
	result += `</border>`
	return
}
To get borders to work correctly in Excel, you have to always start with an
empty set of borders. There was logic in this function that would strip out
empty elements, but unfortunately that would cause the border to fail.
package xlsx
import (
	"bytes"
	"encoding/xml"
	"fmt"
	"strconv"
	"strings"
	"sync"
)
const builtinNumFmtsCount = 163
var builtInNumFmt = map[int]string{
	0:  "general",
	1:  "0",
	2:  "0.00",
	3:  "#,##0",
	4:  "#,##0.00",
	9:  "0%",
	10: "0.00%",
	11: "0.00e+00",
	12: "# ?/?",
	13: "# ??/??",
	14: "mm-dd-yy",
	15: "d-mmm-yy",
	16: "d-mmm",
	17: "mmm-yy",
	18: "h:mm am/pm",
	19: "h:mm:ss am/pm",
	20: "h:mm",
	21: "h:mm:ss",
	22: "m/d/yy h:mm",
	37: "#,##0 ;(#,##0)",
	38: "#,##0 ;[red](#,##0)",
	39: "#,##0.00;(#,##0.00)",
	40: "#,##0.00;[red](#,##0.00)",
	41: `_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)`,
	42: `_("$"* #,##0_);_("$* \(#,##0\);_("$"* "-"_);_(@_)`,
	43: `_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)`,
	44: `_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)`,
	45: "mm:ss",
	46: "[h]:mm:ss",
	47: "mmss.0",
	48: "##0.0e+0",
	49: "@",
}
var builtInNumFmtInv = make(map[string]int, 40)
func init() {
	for k, v := range builtInNumFmt {
		builtInNumFmtInv[v] = k
	}
}
const (
	builtInNumFmtIndex_GENERAL = int(0)
	builtInNumFmtIndex_INT     = int(1)
	builtInNumFmtIndex_FLOAT   = int(2)
	builtInNumFmtIndex_DATE    = int(14)
	builtInNumFmtIndex_STRING  = int(49)
)
// xlsxStyle directly maps the styleSheet element in the namespace
// http://schemas.openxmlformats.org/spreadsheetml/2006/main -
// currently I have not checked it for completeness - it does as much
// as I need.
type xlsxStyleSheet struct {
	XMLName xml.Name `xml:"http: 
	Fonts        xlsxFonts         `xml:"fonts,omitempty"`
	Fills        xlsxFills         `xml:"fills,omitempty"`
	Borders      xlsxBorders       `xml:"borders,omitempty"`
	CellStyles   *xlsxCellStyles   `xml:"cellStyles,omitempty"`
	CellStyleXfs *xlsxCellStyleXfs `xml:"cellStyleXfs,omitempty"`
	CellXfs      xlsxCellXfs       `xml:"cellXfs,omitempty"`
	NumFmts      xlsxNumFmts       `xml:"numFmts,omitempty"`
	theme *theme
	sync.RWMutex    
	styleCache     map[int]*Style
	numFmtRefTable map[int]xlsxNumFmt
}
func newXlsxStyleSheet(t *theme) *xlsxStyleSheet {
	return &xlsxStyleSheet{
		theme:      t,
		styleCache: make(map[int]*Style),
	}
}
func (styles *xlsxStyleSheet) reset() {
	styles.Fonts = xlsxFonts{}
	styles.Fills = xlsxFills{}
	styles.Borders = xlsxBorders{}
	styles.addBorder(
		xlsxBorder{
			Left:   xlsxLine{Style: "none"},
			Right:  xlsxLine{Style: "none"},
			Top:    xlsxLine{Style: "none"},
			Bottom: xlsxLine{Style: "none"},
		})
	styles.CellStyleXfs = &xlsxCellStyleXfs{}
	styles.CellXfs = xlsxCellXfs{Count: 1, Xf: []xlsxXf{{}}}
	styles.NumFmts = xlsxNumFmts{}
}
func (styles *xlsxStyleSheet) getStyle(styleIndex int) *Style {
	styles.RLock()
	style, ok := styles.styleCache[styleIndex]
	styles.RUnlock()
	if ok {
		return style
	}
	style = new(Style)
	var namedStyleXf xlsxXf
	xfCount := styles.CellXfs.Count
	if styleIndex > -1 && xfCount > 0 && styleIndex <= xfCount {
		xf := styles.CellXfs.Xf[styleIndex]
		if xf.XfId != nil && styles.CellStyleXfs != nil {
			namedStyleXf = styles.CellStyleXfs.Xf[*xf.XfId]
			style.NamedStyleIndex = xf.XfId
		} else {
			namedStyleXf = xlsxXf{}
		}
		style.ApplyBorder = xf.ApplyBorder || namedStyleXf.ApplyBorder
		style.ApplyFill = xf.ApplyFill || namedStyleXf.ApplyFill
		style.ApplyFont = xf.ApplyFont || namedStyleXf.ApplyFont
		style.ApplyAlignment = xf.ApplyAlignment || namedStyleXf.ApplyAlignment
		if xf.BorderId > -1 && xf.BorderId < styles.Borders.Count {
			var border xlsxBorder
			border = styles.Borders.Border[xf.BorderId]
			style.Border.Left = border.Left.Style
			style.Border.LeftColor = border.Left.Color.RGB
			style.Border.Right = border.Right.Style
			style.Border.RightColor = border.Right.Color.RGB
			style.Border.Top = border.Top.Style
			style.Border.TopColor = border.Top.Color.RGB
			style.Border.Bottom = border.Bottom.Style
			style.Border.BottomColor = border.Bottom.Color.RGB
		}
		if xf.FillId > -1 && xf.FillId < styles.Fills.Count {
			xFill := styles.Fills.Fill[xf.FillId]
			style.Fill.PatternType = xFill.PatternFill.PatternType
			style.Fill.FgColor = styles.argbValue(xFill.PatternFill.FgColor)
			style.Fill.BgColor = styles.argbValue(xFill.PatternFill.BgColor)
		}
		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)
			style.Font.Color = styles.argbValue(xfont.Color)
			if bold := xfont.B; bold != nil && bold.Val != "0" {
				style.Font.Bold = true
			}
			if italic := xfont.I; italic != nil && italic.Val != "0" {
				style.Font.Italic = true
			}
			if underline := xfont.U; underline != nil && underline.Val != "0" {
				style.Font.Underline = true
			}
		}
		if xf.Alignment.Horizontal != "" {
			style.Alignment.Horizontal = xf.Alignment.Horizontal
		}
		if xf.Alignment.Vertical != "" {
			style.Alignment.Vertical = xf.Alignment.Vertical
		}
		style.Alignment.WrapText = xf.Alignment.WrapText
		styles.Lock()
		styles.styleCache[styleIndex] = style
		styles.Unlock()
	}
	return style
}
func (styles *xlsxStyleSheet) argbValue(color xlsxColor) string {
	if color.Theme != nil && styles.theme != nil {
		return styles.theme.themeColor(int64(*color.Theme), color.Tint)
	}
	return color.RGB
}
func getBuiltinNumberFormat(numFmtId int) string {
	return builtInNumFmt[numFmtId]
}
func (styles *xlsxStyleSheet) getNumberFormat(styleIndex int) string {
	if styles.CellXfs.Xf == nil {
		return ""
	}
	var numberFormat string = ""
	if styleIndex > -1 && styleIndex <= styles.CellXfs.Count {
		xf := styles.CellXfs.Xf[styleIndex]
		if builtin := getBuiltinNumberFormat(xf.NumFmtId); builtin != "" {
			return builtin
		}
		if styles.numFmtRefTable != nil {
			numFmt := styles.numFmtRefTable[xf.NumFmtId]
			numberFormat = numFmt.FormatCode
		}
	}
	return strings.ToLower(numberFormat)
}
func (styles *xlsxStyleSheet) addFont(xFont xlsxFont) (index int) {
	var font xlsxFont
	if xFont.Name.Val == "" {
		return 0
	}
	for index, font = range styles.Fonts.Font {
		if font.Equals(xFont) {
			return index
		}
	}
	styles.Fonts.Font = append(styles.Fonts.Font, xFont)
	index = styles.Fonts.Count
	styles.Fonts.Count++
	return
}
func (styles *xlsxStyleSheet) addFill(xFill xlsxFill) (index int) {
	var fill xlsxFill
	for index, fill = range styles.Fills.Fill {
		if fill.Equals(xFill) {
			return index
		}
	}
	styles.Fills.Fill = append(styles.Fills.Fill, xFill)
	index = styles.Fills.Count
	styles.Fills.Count++
	return
}
func (styles *xlsxStyleSheet) addBorder(xBorder xlsxBorder) (index int) {
	var border xlsxBorder
	for index, border = range styles.Borders.Border {
		if border.Equals(xBorder) {
			return index
		}
	}
	styles.Borders.Border = append(styles.Borders.Border, xBorder)
	index = styles.Borders.Count
	styles.Borders.Count++
	return
}
func (styles *xlsxStyleSheet) addCellStyleXf(xCellStyleXf xlsxXf) (index int) {
	var cellStyleXf xlsxXf
	if styles.CellStyleXfs == nil {
		styles.CellStyleXfs = &xlsxCellStyleXfs{Count: 0}
	}
	for index, cellStyleXf = range styles.CellStyleXfs.Xf {
		if cellStyleXf.Equals(xCellStyleXf) {
			return index
		}
	}
	styles.CellStyleXfs.Xf = append(styles.CellStyleXfs.Xf, xCellStyleXf)
	index = styles.CellStyleXfs.Count
	styles.CellStyleXfs.Count++
	return
}
func (styles *xlsxStyleSheet) addCellXf(xCellXf xlsxXf) (index int) {
	var cellXf xlsxXf
	for index, cellXf = range styles.CellXfs.Xf {
		if cellXf.Equals(xCellXf) {
			return index
		}
	}
	styles.CellXfs.Xf = append(styles.CellXfs.Xf, xCellXf)
	index = styles.CellXfs.Count
	styles.CellXfs.Count++
	return
}
func (styles *xlsxStyleSheet) newNumFmt(formatCode string) xlsxNumFmt {
	if formatCode == "" {
		return xlsxNumFmt{NumFmtId: 0, FormatCode: "general"}
	}
	numFmtId, ok := builtInNumFmtInv[formatCode]
	if ok {
		return xlsxNumFmt{NumFmtId: numFmtId, FormatCode: formatCode}
	}
	for _, numFmt := range styles.NumFmts.NumFmt {
		if formatCode == numFmt.FormatCode {
			return numFmt
		}
	}
	numFmtId = builtinNumFmtsCount + 1
	styles.Lock()
	defer styles.Unlock()
	for {
		if _, ok = styles.numFmtRefTable[numFmtId]; ok {
			numFmtId++
		} else {
			styles.addNumFmt(xlsxNumFmt{NumFmtId: numFmtId, FormatCode: formatCode})
			break
		}
	}
	return xlsxNumFmt{NumFmtId: numFmtId, FormatCode: formatCode}
}
func (styles *xlsxStyleSheet) addNumFmt(xNumFmt xlsxNumFmt) {
	if xNumFmt.NumFmtId <= builtinNumFmtsCount {
		return
	}
	_, ok := styles.numFmtRefTable[xNumFmt.NumFmtId]
	if !ok {
		if styles.numFmtRefTable == nil {
			styles.numFmtRefTable = make(map[int]xlsxNumFmt)
		}
		styles.NumFmts.NumFmt = append(styles.NumFmts.NumFmt, xNumFmt)
		styles.numFmtRefTable[xNumFmt.NumFmtId] = xNumFmt
		styles.NumFmts.Count++
	}
}
func (styles *xlsxStyleSheet) Marshal() (string, error) {
	result := xml.Header + `<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`
	xNumFmts, err := styles.NumFmts.Marshal()
	if err != nil {
		return "", err
	}
	result += xNumFmts
	outputFontMap := make(map[int]int)
	xfonts, err := styles.Fonts.Marshal(outputFontMap)
	if err != nil {
		return "", err
	}
	result += xfonts
	outputFillMap := make(map[int]int)
	xfills, err := styles.Fills.Marshal(outputFillMap)
	if err != nil {
		return "", err
	}
	result += xfills
	outputBorderMap := make(map[int]int)
	xborders, err := styles.Borders.Marshal(outputBorderMap)
	if err != nil {
		return "", err
	}
	result += xborders
	if styles.CellStyleXfs != nil {
		xcellStyleXfs, err := styles.CellStyleXfs.Marshal(outputBorderMap, outputFillMap, outputFontMap)
		if err != nil {
			return "", err
		}
		result += xcellStyleXfs
	}
	xcellXfs, err := styles.CellXfs.Marshal(outputBorderMap, outputFillMap, outputFontMap)
	if err != nil {
		return "", err
	}
	result += xcellXfs
	if styles.CellStyles != nil {
		xcellStyles, err := styles.CellStyles.Marshal()
		if err != nil {
			return "", err
		}
		result += xcellStyles
	}
	return result + "</styleSheet>", nil
}
type xlsxNumFmts struct {
	Count  int          `xml:"count,attr"`
	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
}
type xlsxNumFmt struct {
	NumFmtId   int    `xml:"numFmtId,attr,omitempty"`
	FormatCode string `xml:"formatCode,attr,omitempty"`
}
func (numFmt *xlsxNumFmt) Marshal() (result string, err error) {
	formatCode := &bytes.Buffer{}
	if err := xml.EscapeText(formatCode, []byte(numFmt.FormatCode)); err != nil {
		return "", err
	}
	return fmt.Sprintf(`<numFmt numFmtId="%d" formatCode="%s"/>`, numFmt.NumFmtId, formatCode), nil
}
type xlsxFonts struct {
	XMLName xml.Name `xml:"fonts"`
	Count int        `xml:"count,attr"`
	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++
			subparts += xfont
		}
	}
	if emittedCount > 0 {
		result = fmt.Sprintf(`<fonts count="%d">`, fonts.Count)
		result += subparts
		result += `</fonts>`
	}
	return
}
type xlsxFont struct {
	Sz      xlsxVal   `xml:"sz,omitempty"`
	Name    xlsxVal   `xml:"name,omitempty"`
	Family  xlsxVal   `xml:"family,omitempty"`
	Charset xlsxVal   `xml:"charset,omitempty"`
	Color   xlsxColor `xml:"color,omitempty"`
	B       *xlsxVal  `xml:"b,omitempty"`
	I       *xlsxVal  `xml:"i,omitempty"`
	U       *xlsxVal  `xml:"u,omitempty"`
}
func (font *xlsxFont) Equals(other xlsxFont) bool {
	if (font.B == nil && other.B != nil) || (font.B != nil && other.B == nil) {
		return false
	}
	if (font.I == nil && other.I != nil) || (font.I != nil && other.I == nil) {
		return false
	}
	if (font.U == nil && other.U != nil) || (font.U != nil && other.U == nil) {
		return false
	}
	return font.Sz.Equals(other.Sz) && font.Name.Equals(other.Name) && font.Family.Equals(other.Family) && font.Charset.Equals(other.Charset) && font.Color.Equals(other.Color)
}
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)
	}
	if font.B != nil {
		result += "<b/>"
	}
	if font.I != nil {
		result += "<i/>"
	}
	if font.U != nil {
		result += "<u/>"
	}
	return result + "</font>", nil
}
type xlsxVal struct {
	Val string `xml:"val,attr,omitempty"`
}
func (val *xlsxVal) Equals(other xlsxVal) bool {
	return val.Val == other.Val
}
type xlsxFills struct {
	Count int        `xml:"count,attr"`
	Fill  []xlsxFill `xml:"fill,omitempty"`
}
func (fills *xlsxFills) Marshal(outputFillMap map[int]int) (string, error) {
	var subparts string
	var emittedCount int
	for i, fill := range fills.Fill {
		xfill, err := fill.Marshal()
		if err != nil {
			return "", err
		}
		if xfill != "" {
			outputFillMap[i] = emittedCount
			emittedCount++
			subparts += xfill
		}
	}
	var result string
	if emittedCount > 0 {
		result = fmt.Sprintf(`<fills count="%d">`, emittedCount)
		result += subparts
		result += `</fills>`
	}
	return result, nil
}
type xlsxFill struct {
	PatternFill xlsxPatternFill `xml:"patternFill,omitempty"`
}
func (fill *xlsxFill) Equals(other xlsxFill) bool {
	return fill.PatternFill.Equals(other.PatternFill)
}
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
}
type xlsxPatternFill struct {
	PatternType string    `xml:"patternType,attr,omitempty"`
	FgColor     xlsxColor `xml:"fgColor,omitempty"`
	BgColor     xlsxColor `xml:"bgColor,omitempty"`
}
func (patternFill *xlsxPatternFill) Equals(other xlsxPatternFill) bool {
	return patternFill.PatternType == other.PatternType && patternFill.FgColor.Equals(other.FgColor) && patternFill.BgColor.Equals(other.BgColor)
}
func (patternFill *xlsxPatternFill) Marshal() (result string, err error) {
	result = fmt.Sprintf(`<patternFill patternType="%s"`, patternFill.PatternType)
	ending := `/>`
	terminator := ""
	subparts := ""
	if patternFill.FgColor.RGB != "" {
		ending = `>`
		terminator = "</patternFill>"
		subparts += fmt.Sprintf(`<fgColor rgb="%s"/>`, patternFill.FgColor.RGB)
	}
	if patternFill.BgColor.RGB != "" {
		ending = `>`
		terminator = "</patternFill>"
		subparts += fmt.Sprintf(`<bgColor rgb="%s"/>`, patternFill.BgColor.RGB)
	}
	result += ending
	result += subparts
	result += terminator
	return
}
type xlsxColor struct {
	RGB   string  `xml:"rgb,attr,omitempty"`
	Theme *int    `xml:"theme,attr,omitempty"`
	Tint  float64 `xml:"tint,attr,omitempty"`
}
func (color *xlsxColor) Equals(other xlsxColor) bool {
	return color.RGB == other.RGB
}
type xlsxBorders struct {
	Count  int          `xml:"count,attr"`
	Border []xlsxBorder `xml:"border"`
}
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++
			subparts += xborder
		}
	}
	if emittedCount > 0 {
		result += fmt.Sprintf(`<borders count="%d">`, emittedCount)
		result += subparts
		result += `</borders>`
	}
	return
}
type xlsxBorder struct {
	Left   xlsxLine `xml:"left,omitempty"`
	Right  xlsxLine `xml:"right,omitempty"`
	Top    xlsxLine `xml:"top,omitempty"`
	Bottom xlsxLine `xml:"bottom,omitempty"`
}
func (border *xlsxBorder) Equals(other xlsxBorder) bool {
	return border.Left.Equals(other.Left) && border.Right.Equals(other.Right) && border.Top.Equals(other.Top) && border.Bottom.Equals(other.Bottom)
}