Skip to content

Commit

Permalink
Performance improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
xuri committed Mar 12, 2017
1 parent 5384756 commit de6e075
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 185 deletions.
54 changes: 7 additions & 47 deletions cell.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ import (
// GetCellValue provides function to get value from cell by given sheet index
// and axis in XLSX file.
func (f *File) GetCellValue(sheet, axis string) string {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand Down Expand Up @@ -60,10 +58,8 @@ func (f *File) GetCellValue(sheet, axis string) string {
// GetCellFormula provides function to get formula from cell by given sheet
// index and axis in XLSX file.
func (f *File) GetCellFormula(sheet, axis string) string {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand Down Expand Up @@ -102,18 +98,8 @@ func (f *File) GetCellFormula(sheet, axis string) string {
// SetCellFormula provides function to set cell formula by given string and
// sheet index.
func (f *File) SetCellFormula(sheet, axis, formula string) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand All @@ -129,8 +115,8 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
rows := xAxis + 1
cell := yAxis + 1

completeRow(&xlsx, rows, cell)
completeCol(&xlsx, rows, cell)
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)

if xlsx.SheetData.Row[xAxis].C[yAxis].F != nil {
xlsx.SheetData.Row[xAxis].C[yAxis].F.Content = formula
Expand All @@ -140,25 +126,13 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
}
xlsx.SheetData.Row[xAxis].C[yAxis].F = &f
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}

// SetCellHyperLink provides function to set cell hyperlink by given sheet index
// and link URL address. Only support external link currently.
func (f *File) SetCellHyperLink(sheet, axis, link string) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand All @@ -178,8 +152,6 @@ func (f *File) SetCellHyperLink(sheet, axis, link string) {
hyperlinks.Hyperlink = append(hyperlinks.Hyperlink, hyperlink)
xlsx.Hyperlinks = &hyperlinks
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}

// MergeCell provides function to merge cells by given coordinate area and sheet
Expand Down Expand Up @@ -218,17 +190,7 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
vyAxis, hyAxis = hyAxis, vyAxis
}

var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
xlsx := f.workSheetReader(sheet)
if xlsx.MergeCells != nil {
mergeCell := xlsxMergeCell{}
// Correct the coordinate area, such correct C1:B3 to B1:C3.
Expand All @@ -250,8 +212,6 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
mergeCells.Cells = append(mergeCells.Cells, &mergeCell)
xlsx.MergeCells = &mergeCells
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}

// checkCellInArea provides function to determine if a given coordinate is
Expand Down
15 changes: 3 additions & 12 deletions col.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package excelize

import (
"encoding/xml"
"math"
"strconv"
"strings"
Expand Down Expand Up @@ -31,9 +30,7 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) {
if min > max {
min, max = max, min
}
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
col := xlsxCol{
Min: min,
Max: max,
Expand All @@ -47,8 +44,6 @@ func (f *File) SetColWidth(sheet, startcol, endcol string, width float64) {
cols.Col = append(cols.Col, col)
xlsx.Cols = &cols
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}

// positionObjectPixels calculate the vertices that define the position of a
Expand Down Expand Up @@ -160,9 +155,7 @@ func (f *File) positionObjectPixels(sheet string, colStart, rowStart, x1, y1, wi
// getColWidth provides function to get column width in pixels by given sheet
// name and column index.
func (f *File) getColWidth(sheet string, col int) int {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
if xlsx.Cols != nil {
var width float64
for _, v := range xlsx.Cols.Col {
Expand All @@ -181,9 +174,7 @@ func (f *File) getColWidth(sheet string, col int) int {
// getRowHeight provides function to get row height in pixels by given sheet
// name and row index.
func (f *File) getRowHeight(sheet string, row int) int {
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader(sheet)
for _, v := range xlsx.SheetData.Row {
if v.R == row && v.Ht != "" {
ht, _ := strconv.ParseFloat(v.Ht, 64)
Expand Down
88 changes: 34 additions & 54 deletions excelize.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type File struct {
checked map[string]bool
XLSX map[string]string
Path string
Sheet map[string]*xlsxWorksheet
SheetCount int
}

Expand Down Expand Up @@ -52,6 +53,7 @@ func OpenReader(r io.Reader) (*File, error) {
return nil, err
}
return &File{
Sheet: make(map[string]*xlsxWorksheet),
checked: make(map[string]bool),
XLSX: file,
Path: "",
Expand Down Expand Up @@ -85,21 +87,32 @@ func (f *File) SetCellValue(sheet, axis string, value interface{}) {
}
}

// SetCellInt provides function to set int type value of a cell.
func (f *File) SetCellInt(sheet, axis string, value int) {
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
// workSheetReader provides function to get the pointer to the structure after
// deserialization by given worksheet index.
func (f *File) workSheetReader(sheet string) *xlsxWorksheet {
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
worksheet := f.Sheet[name]
if worksheet == nil {
var xlsx xlsxWorksheet
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
f.Sheet[name] = &xlsx
worksheet = f.Sheet[name]
}
return worksheet
}

// SetCellInt provides function to set int type value of a cell.
func (f *File) SetCellInt(sheet, axis string, value int) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand All @@ -115,31 +128,18 @@ func (f *File) SetCellInt(sheet, axis string, value int) {
rows := xAxis + 1
cell := yAxis + 1

completeRow(&xlsx, rows, cell)
completeCol(&xlsx, rows, cell)
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)

xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
xlsx.SheetData.Row[xAxis].C[yAxis].V = strconv.Itoa(value)

output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}

// SetCellStr provides function to set string type value of a cell. Total number
// of characters that a cell can contain 32767 characters.
func (f *File) SetCellStr(sheet, axis, value string) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand All @@ -158,31 +158,18 @@ func (f *File) SetCellStr(sheet, axis, value string) {
rows := xAxis + 1
cell := yAxis + 1

completeRow(&xlsx, rows, cell)
completeCol(&xlsx, rows, cell)
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)

xlsx.SheetData.Row[xAxis].C[yAxis].T = "str"
xlsx.SheetData.Row[xAxis].C[yAxis].V = value

output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}

// SetCellDefault provides function to set string type value of a cell as
// default format without escaping the cell.
func (f *File) SetCellDefault(sheet, axis, value string) {
xlsx := f.workSheetReader(sheet)
axis = strings.ToUpper(axis)
var xlsx xlsxWorksheet
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
if f.checked == nil {
f.checked = make(map[string]bool)
}
ok := f.checked[name]
if !ok {
checkRow(&xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
Expand All @@ -198,14 +185,11 @@ func (f *File) SetCellDefault(sheet, axis, value string) {
rows := xAxis + 1
cell := yAxis + 1

completeRow(&xlsx, rows, cell)
completeCol(&xlsx, rows, cell)
completeRow(xlsx, rows, cell)
completeCol(xlsx, rows, cell)

xlsx.SheetData.Row[xAxis].C[yAxis].T = ""
xlsx.SheetData.Row[xAxis].C[yAxis].V = value

output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}

// Completion column element tags of XML in a sheet.
Expand Down Expand Up @@ -364,9 +348,7 @@ func checkRow(xlsx *xlsxWorksheet) {
//
func (f *File) UpdateLinkedValue() {
for i := 1; i <= f.SheetCount; i++ {
var xlsx xlsxWorksheet
name := "xl/worksheets/sheet" + strconv.Itoa(i) + ".xml"
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
xlsx := f.workSheetReader("sheet" + strconv.Itoa(i))
for indexR, row := range xlsx.SheetData.Row {
for indexC, col := range row.C {
if col.F != nil && col.V != "" {
Expand All @@ -375,7 +357,5 @@ func (f *File) UpdateLinkedValue() {
}
}
}
output, _ := xml.Marshal(xlsx)
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
}
14 changes: 13 additions & 1 deletion file.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package excelize
import (
"archive/zip"
"bytes"
"encoding/xml"
"fmt"
"io"
"os"
Expand All @@ -25,7 +26,8 @@ func CreateFile() *File {
file["xl/workbook.xml"] = templateWorkbook
file["[Content_Types].xml"] = templateContentTypes
return &File{
XLSX: file,
XLSX: file,
Sheet: make(map[string]*xlsxWorksheet),
}
}

Expand All @@ -52,6 +54,16 @@ func (f *File) WriteTo(name string) error {
func (f *File) Write(w io.Writer) error {
buf := new(bytes.Buffer)
zw := zip.NewWriter(buf)
for path, sheet := range f.Sheet {
if sheet == nil {
continue
}
output, err := xml.Marshal(sheet)
if err != nil {
return err
}
f.saveFileList(path, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
for path, content := range f.XLSX {
fi, err := zw.Create(path)
if err != nil {
Expand Down
Loading

0 comments on commit de6e075

Please sign in to comment.