diff --git a/cell.go b/cell.go index 86c35677..0145b8ed 100644 --- a/cell.go +++ b/cell.go @@ -70,8 +70,7 @@ func (f *File) formattedValue(s int, v string) string { if s == 0 { return v } - var styleSheet xlsxStyleSheet - xml.Unmarshal([]byte(f.readXML("xl/styles.xml")), &styleSheet) + styleSheet := f.stylesReader() ok := builtInNumFmtFunc[styleSheet.CellXfs.Xf[s].NumFmtID] if ok != nil { return ok(styleSheet.CellXfs.Xf[s].NumFmtID, v) @@ -200,7 +199,7 @@ func (f *File) MergeCell(sheet, hcell, vcell string) { if xlsx.MergeCells != nil { mergeCell := xlsxMergeCell{} // Correct the coordinate area, such correct C1:B3 to B1:C3. - mergeCell.Ref = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) + mergeCell.Ref = ToAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) // Delete the merged cells of the overlapping area. for i := 0; i < len(xlsx.MergeCells.Cells); i++ { if checkCellInArea(hcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0], mergeCell.Ref) { @@ -213,7 +212,7 @@ func (f *File) MergeCell(sheet, hcell, vcell string) { } else { mergeCell := xlsxMergeCell{} // Correct the coordinate area, such correct C1:B3 to B1:C3. - mergeCell.Ref = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) + mergeCell.Ref = ToAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) mergeCells := xlsxMergeCells{} mergeCells.Cells = append(mergeCells.Cells, &mergeCell) xlsx.MergeCells = &mergeCells diff --git a/excelize.go b/excelize.go index 8c7365b1..2554565a 100644 --- a/excelize.go +++ b/excelize.go @@ -20,6 +20,7 @@ type File struct { Path string Sheet map[string]*xlsxWorksheet SheetCount int + Styles *xlsxStyleSheet WorkBook *xlsxWorkbook WorkBookRels *xlsxWorkbookRels XLSX map[string]string @@ -268,7 +269,7 @@ func completeCol(xlsx *xlsxWorksheet, row, cell int) { if len(v.C) < cell { start := len(v.C) for iii := start; iii < cell; iii++ { - buffer.WriteString(toAlphaString(iii + 1)) + buffer.WriteString(ToAlphaString(iii + 1)) buffer.WriteString(strconv.Itoa(k + 1)) xlsx.SheetData.Row[k].C = append(xlsx.SheetData.Row[k].C, xlsxC{ R: buffer.String(), @@ -300,7 +301,7 @@ func completeRow(xlsx *xlsxWorksheet, row, cell int) { start := len(xlsx.SheetData.Row[ii].C) if start == 0 { for iii := start; iii < cell; iii++ { - buffer.WriteString(toAlphaString(iii + 1)) + buffer.WriteString(ToAlphaString(iii + 1)) buffer.WriteString(strconv.Itoa(ii + 1)) xlsx.SheetData.Row[ii].C = append(xlsx.SheetData.Row[ii].C, xlsxC{ R: buffer.String(), @@ -388,7 +389,7 @@ func checkRow(xlsx *xlsxWorksheet) { xlsx.SheetData.Row[k].C = xlsx.SheetData.Row[k].C[:0] tmp := []xlsxC{} for i := 0; i <= endCol; i++ { - buffer.WriteString(toAlphaString(i + 1)) + buffer.WriteString(ToAlphaString(i + 1)) buffer.WriteString(strconv.Itoa(endRow)) tmp = append(tmp, xlsxC{ R: buffer.String(), diff --git a/file.go b/file.go index da1fbc75..a0948993 100644 --- a/file.go +++ b/file.go @@ -57,6 +57,7 @@ func (f *File) Write(w io.Writer) error { f.workbookWriter() f.workbookRelsWriter() f.worksheetWriter() + f.styleSheetWriter() for path, content := range f.XLSX { fi, err := zw.Create(path) if err != nil { diff --git a/lib.go b/lib.go index 3eda1eb8..60587582 100644 --- a/lib.go +++ b/lib.go @@ -50,9 +50,12 @@ func readFile(file *zip.File) string { return string(buff.Bytes()) } -// toAlphaString provides function to convert integer to Excel sheet column -// title. -func toAlphaString(value int) string { +// ToAlphaString provides function to convert integer to Excel sheet column +// title. For example convert 37 to column title AK: +// +// excelize.ToAlphaString(37) +// +func ToAlphaString(value int) string { if value < 0 { return "" } diff --git a/styles.go b/styles.go index 2c4c5afc..04774c24 100644 --- a/styles.go +++ b/styles.go @@ -224,6 +224,26 @@ func parseTime(i int, v string) string { return val.Format(format) } +// stylesReader provides function to get the pointer to the structure after +// deserialization of workbook. +func (f *File) stylesReader() *xlsxStyleSheet { + if f.Styles == nil { + var styleSheet xlsxStyleSheet + xml.Unmarshal([]byte(f.readXML("xl/styles.xml")), &styleSheet) + f.Styles = &styleSheet + } + return f.Styles +} + +// styleSheetWriter provides function to save xl/styles.xml after serialize +// structure. +func (f *File) styleSheetWriter() { + if f.Styles != nil { + output, _ := xml.Marshal(f.Styles) + f.saveFileList("xl/styles.xml", replaceWorkSheetsRelationshipsNameSpace(string(output))) + } +} + // parseFormatStyleSet provides function to parse the format settings of the // borders. func parseFormatStyleSet(style string) (*formatCellStyle, error) { @@ -500,23 +520,17 @@ func parseFormatStyleSet(style string) (*formatCellStyle, error) { // +-------+----------------------------------------------------+ // func (f *File) SetCellStyle(sheet, hcell, vcell, style string) error { - var styleSheet xlsxStyleSheet - xml.Unmarshal([]byte(f.readXML("xl/styles.xml")), &styleSheet) + styleSheet := f.stylesReader() formatCellStyle, err := parseFormatStyleSet(style) if err != nil { return err } - numFmtID := setNumFmt(&styleSheet, formatCellStyle) - fontID := setFont(&styleSheet, formatCellStyle) - borderID := setBorders(&styleSheet, formatCellStyle) - fillID := setFills(&styleSheet, formatCellStyle) - applyAlignment, alignment := setAlignment(&styleSheet, formatCellStyle) - cellXfsID := setCellXfs(&styleSheet, fontID, numFmtID, fillID, borderID, applyAlignment, alignment) - output, err := xml.Marshal(styleSheet) - if err != nil { - return err - } - f.saveFileList("xl/styles.xml", replaceWorkSheetsRelationshipsNameSpace(string(output))) + numFmtID := setNumFmt(styleSheet, formatCellStyle) + fontID := setFont(styleSheet, formatCellStyle) + borderID := setBorders(styleSheet, formatCellStyle) + fillID := setFills(styleSheet, formatCellStyle) + applyAlignment, alignment := setAlignment(styleSheet, formatCellStyle) + cellXfsID := setCellXfs(styleSheet, fontID, numFmtID, fillID, borderID, applyAlignment, alignment) f.setCellStyle(sheet, hcell, vcell, cellXfsID) return err } @@ -771,8 +785,8 @@ func (f *File) setCellStyle(sheet, hcell, vcell string, styleID int) { } // Correct the coordinate area, such correct C1:B3 to B1:C3. - hcell = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) - vcell = toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) + hcell = ToAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + vcell = ToAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) xlsx := f.workSheetReader(sheet) diff --git a/table.go b/table.go index 72f9a9a0..5c8325b0 100644 --- a/table.go +++ b/table.go @@ -108,12 +108,12 @@ func (f *File) addTable(sheet, tableXML string, hxAxis, hyAxis, vxAxis, vyAxis, vyAxis++ } // Correct table reference coordinate area, such correct C1:B3 to B1:C3. - ref := toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) + ref := ToAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) tableColumn := []*xlsxTableColumn{} idx := 0 for i := hxAxis; i <= vxAxis; i++ { idx++ - cell := toAlphaString(i+1) + strconv.Itoa(hyAxis+1) + cell := ToAlphaString(i+1) + strconv.Itoa(hyAxis+1) name := f.GetCellValue(sheet, cell) if _, err := strconv.Atoi(name); err == nil { f.SetCellStr(sheet, cell, name) @@ -254,7 +254,7 @@ func (f *File) AutoFilter(sheet, hcell, vcell, format string) error { if vyAxis < hyAxis { vyAxis, hyAxis = hyAxis, vyAxis } - ref := toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) + ref := ToAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + ToAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) refRange := vxAxis - hxAxis err := f.autoFilter(sheet, ref, refRange, hxAxis, formatSet) return err