- Improved performance when reading large files, call Token to read tokens one by one instead Unmarshal. Related issue #20 ;

- Fix go test typo;
- Update README
This commit is contained in:
Ri Xu 2017-02-12 19:03:24 +08:00
parent 53564cbe57
commit 0833a9d5da
7 changed files with 94 additions and 28 deletions

View File

@ -110,13 +110,18 @@ func main() {
}
// Insert a picture.
err = xlsx.AddPicture("Sheet1", "A2", "/tmp/image1.gif", 0, 0, 1, 1)
if err != nil {
fmt.Println(err)
}
// Insert a picture to sheet with scaling.
err = xlsx.AddPicture("Sheet1", "D2", "/tmp/image2.jpg", 0, 0, 0.5, 0.5)
if err != nil {
fmt.Println(err)
}
// Insert a picture offset in the cell.
err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.png", 15, 10, 1, 1)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Save the xlsx file with the origin path.
err = xlsx.Save()

24
cell.go
View File

@ -106,6 +106,14 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
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 {
xlsx = 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) {
@ -143,6 +151,14 @@ func (f *File) SetCellHyperLink(sheet, axis, link string) {
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 {
xlsx = 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) {
@ -205,6 +221,14 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
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 {
xlsx = checkRow(xlsx)
f.checked[name] = true
}
if xlsx.MergeCells != nil {
mergeCell := xlsxMergeCell{}
// Correct the coordinate area, such correct C1:B3 to B1:C3.

View File

@ -10,6 +10,7 @@ import (
// File define a populated XLSX file struct.
type File struct {
checked map[string]bool
XLSX map[string]string
Path string
SheetCount int
@ -21,6 +22,7 @@ func OpenFile(filename string) (*File, error) {
var f *zip.ReadCloser
var err error
file := make(map[string]string)
c := make(map[string]bool)
sheetCount := 0
f, err = zip.OpenReader(filename)
if err != nil {
@ -28,6 +30,7 @@ func OpenFile(filename string) (*File, error) {
}
file, sheetCount, _ = ReadZip(f)
return &File{
checked: c,
XLSX: file,
Path: filename,
SheetCount: sheetCount,
@ -66,6 +69,15 @@ func (f *File) SetCellInt(sheet string, axis string, value int) {
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 {
xlsx = 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) {
@ -98,6 +110,14 @@ func (f *File) SetCellStr(sheet string, axis string, value string) {
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 {
xlsx = 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) {
@ -133,6 +153,14 @@ func (f *File) SetCellDefault(sheet string, axis string, value string) {
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 {
xlsx = 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) {

View File

@ -236,7 +236,7 @@ func TestSetSheetBackground(t *testing.T) {
}
}
func TestSMergeCell(t *testing.T) {
func TestMergeCell(t *testing.T) {
xlsx, err := OpenFile("./test/Workbook1.xlsx")
if err != nil {
t.Log(err)

6
lib.go
View File

@ -3,7 +3,6 @@ package excelize
import (
"archive/zip"
"bytes"
"encoding/xml"
"io"
"log"
"math"
@ -26,11 +25,6 @@ func ReadZipReader(r *zip.Reader) (map[string]string, int, error) {
fileList[v.Name] = readFile(v)
if len(v.Name) > 18 {
if v.Name[0:19] == "xl/worksheets/sheet" {
var xlsx xlsxWorksheet
xml.Unmarshal([]byte(fileList[v.Name]), &xlsx)
xlsx = checkRow(xlsx)
output, _ := xml.Marshal(xlsx)
fileList[v.Name] = replaceWorkSheetsRelationshipsNameSpace(string(output))
worksheets++
}
}

View File

@ -33,13 +33,18 @@ import (
// xlsx := excelize.CreateFile()
// // Insert a picture.
// err := xlsx.AddPicture("Sheet1", "A2", "/tmp/image1.jpg", 0, 0, 1, 1)
// if err != nil {
// fmt.Println(err)
// }
// // Insert a picture to sheet with scaling.
// err = xlsx.AddPicture("Sheet1", "D2", "/tmp/image1.png", 0, 0, 0.5, 0.5)
// if err != nil {
// fmt.Println(err)
// }
// // Insert a picture offset in the cell.
// err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.gif", 15, 10, 1, 1)
// if err != nil {
// fmt.Println(err)
// os.Exit(1)
// }
// err = xlsx.WriteTo("/tmp/Workbook.xlsx")
// if err != nil {

48
rows.go
View File

@ -17,23 +17,37 @@ import (
// }
//
func (f *File) GetRows(sheet string) [][]string {
xlsx := xlsxWorksheet{}
r := [][]string{}
rows := [][]string{}
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
err := xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
decoder := xml.NewDecoder(strings.NewReader(f.readXML(name)))
d, err := readXMLSST(f)
if err != nil {
return r
return rows
}
rows := xlsx.SheetData.Row
for _, row := range rows {
c := []string{}
for _, colCell := range row.C {
val, _ := colCell.getValueFrom(f)
c = append(c, val)
var inElement string
var row []string
for {
token, _ := decoder.Token()
if token == nil {
break
}
switch startElement := token.(type) {
case xml.StartElement:
inElement = startElement.Name.Local
if inElement == "row" {
var r xlsxRow
decoder.DecodeElement(&r, &startElement)
for _, colCell := range r.C {
val, _ := colCell.getValueFrom(f, d)
row = append(row, val)
}
rows = append(rows, row)
row = row[:0]
}
default:
}
r = append(r, c)
}
return r
return rows
}
// SetRowHeight provides a function to set the height of a single row.
@ -65,23 +79,19 @@ func (f *File) SetRowHeight(sheet string, rowIndex int, height float64) {
}
// readXMLSST read xmlSST simple function.
func readXMLSST(f *File) (xlsxSST, error) {
func readXMLSST(f *File) (*xlsxSST, error) {
shardStrings := xlsxSST{}
err := xml.Unmarshal([]byte(f.readXML("xl/sharedStrings.xml")), &shardStrings)
return shardStrings, err
return &shardStrings, err
}
// getValueFrom return a value from a column/row cell, this function is inteded
// to be used with for range on rows an argument with the xlsx opened file.
func (xlsx *xlsxC) getValueFrom(f *File) (string, error) {
func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
switch xlsx.T {
case "s":
xlsxSI := 0
xlsxSI, _ = strconv.Atoi(xlsx.V)
d, err := readXMLSST(f)
if err != nil {
return "", err
}
if len(d.SI[xlsxSI].R) > 0 {
value := ""
for _, v := range d.SI[xlsxSI].R {