- 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:
parent
53564cbe57
commit
0833a9d5da
|
@ -110,13 +110,18 @@ func main() {
|
||||||
}
|
}
|
||||||
// Insert a picture.
|
// Insert a picture.
|
||||||
err = xlsx.AddPicture("Sheet1", "A2", "/tmp/image1.gif", 0, 0, 1, 1)
|
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.
|
// Insert a picture to sheet with scaling.
|
||||||
err = xlsx.AddPicture("Sheet1", "D2", "/tmp/image2.jpg", 0, 0, 0.5, 0.5)
|
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.
|
// Insert a picture offset in the cell.
|
||||||
err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.png", 15, 10, 1, 1)
|
err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.png", 15, 10, 1, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
// Save the xlsx file with the origin path.
|
// Save the xlsx file with the origin path.
|
||||||
err = xlsx.Save()
|
err = xlsx.Save()
|
||||||
|
|
24
cell.go
24
cell.go
|
@ -106,6 +106,14 @@ func (f *File) SetCellFormula(sheet, axis, formula string) {
|
||||||
var xlsx xlsxWorksheet
|
var xlsx xlsxWorksheet
|
||||||
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
||||||
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
|
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 {
|
if xlsx.MergeCells != nil {
|
||||||
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
||||||
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
||||||
|
@ -143,6 +151,14 @@ func (f *File) SetCellHyperLink(sheet, axis, link string) {
|
||||||
var xlsx xlsxWorksheet
|
var xlsx xlsxWorksheet
|
||||||
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
||||||
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
|
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 {
|
if xlsx.MergeCells != nil {
|
||||||
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
||||||
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
||||||
|
@ -205,6 +221,14 @@ func (f *File) MergeCell(sheet, hcell, vcell string) {
|
||||||
var xlsx xlsxWorksheet
|
var xlsx xlsxWorksheet
|
||||||
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
||||||
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
|
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 {
|
if xlsx.MergeCells != nil {
|
||||||
mergeCell := xlsxMergeCell{}
|
mergeCell := xlsxMergeCell{}
|
||||||
// Correct the coordinate area, such correct C1:B3 to B1:C3.
|
// Correct the coordinate area, such correct C1:B3 to B1:C3.
|
||||||
|
|
28
excelize.go
28
excelize.go
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
// File define a populated XLSX file struct.
|
// File define a populated XLSX file struct.
|
||||||
type File struct {
|
type File struct {
|
||||||
|
checked map[string]bool
|
||||||
XLSX map[string]string
|
XLSX map[string]string
|
||||||
Path string
|
Path string
|
||||||
SheetCount int
|
SheetCount int
|
||||||
|
@ -21,6 +22,7 @@ func OpenFile(filename string) (*File, error) {
|
||||||
var f *zip.ReadCloser
|
var f *zip.ReadCloser
|
||||||
var err error
|
var err error
|
||||||
file := make(map[string]string)
|
file := make(map[string]string)
|
||||||
|
c := make(map[string]bool)
|
||||||
sheetCount := 0
|
sheetCount := 0
|
||||||
f, err = zip.OpenReader(filename)
|
f, err = zip.OpenReader(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -28,6 +30,7 @@ func OpenFile(filename string) (*File, error) {
|
||||||
}
|
}
|
||||||
file, sheetCount, _ = ReadZip(f)
|
file, sheetCount, _ = ReadZip(f)
|
||||||
return &File{
|
return &File{
|
||||||
|
checked: c,
|
||||||
XLSX: file,
|
XLSX: file,
|
||||||
Path: filename,
|
Path: filename,
|
||||||
SheetCount: sheetCount,
|
SheetCount: sheetCount,
|
||||||
|
@ -66,6 +69,15 @@ func (f *File) SetCellInt(sheet string, axis string, value int) {
|
||||||
var xlsx xlsxWorksheet
|
var xlsx xlsxWorksheet
|
||||||
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
||||||
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
|
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 {
|
if xlsx.MergeCells != nil {
|
||||||
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
||||||
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
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
|
var xlsx xlsxWorksheet
|
||||||
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
||||||
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
|
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 {
|
if xlsx.MergeCells != nil {
|
||||||
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
||||||
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
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
|
var xlsx xlsxWorksheet
|
||||||
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
||||||
xml.Unmarshal([]byte(f.readXML(name)), &xlsx)
|
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 {
|
if xlsx.MergeCells != nil {
|
||||||
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
|
||||||
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
if checkCellInArea(axis, xlsx.MergeCells.Cells[i].Ref) {
|
||||||
|
|
|
@ -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")
|
xlsx, err := OpenFile("./test/Workbook1.xlsx")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
|
|
6
lib.go
6
lib.go
|
@ -3,7 +3,6 @@ package excelize
|
||||||
import (
|
import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/xml"
|
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
|
@ -26,11 +25,6 @@ func ReadZipReader(r *zip.Reader) (map[string]string, int, error) {
|
||||||
fileList[v.Name] = readFile(v)
|
fileList[v.Name] = readFile(v)
|
||||||
if len(v.Name) > 18 {
|
if len(v.Name) > 18 {
|
||||||
if v.Name[0:19] == "xl/worksheets/sheet" {
|
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++
|
worksheets++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,18 @@ import (
|
||||||
// xlsx := excelize.CreateFile()
|
// xlsx := excelize.CreateFile()
|
||||||
// // Insert a picture.
|
// // Insert a picture.
|
||||||
// err := xlsx.AddPicture("Sheet1", "A2", "/tmp/image1.jpg", 0, 0, 1, 1)
|
// 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.
|
// // Insert a picture to sheet with scaling.
|
||||||
// err = xlsx.AddPicture("Sheet1", "D2", "/tmp/image1.png", 0, 0, 0.5, 0.5)
|
// 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.
|
// // Insert a picture offset in the cell.
|
||||||
// err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.gif", 15, 10, 1, 1)
|
// err = xlsx.AddPicture("Sheet1", "H2", "/tmp/image3.gif", 15, 10, 1, 1)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println(err)
|
// fmt.Println(err)
|
||||||
// os.Exit(1)
|
|
||||||
// }
|
// }
|
||||||
// err = xlsx.WriteTo("/tmp/Workbook.xlsx")
|
// err = xlsx.WriteTo("/tmp/Workbook.xlsx")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
|
|
48
rows.go
48
rows.go
|
@ -17,23 +17,37 @@ import (
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
func (f *File) GetRows(sheet string) [][]string {
|
func (f *File) GetRows(sheet string) [][]string {
|
||||||
xlsx := xlsxWorksheet{}
|
rows := [][]string{}
|
||||||
r := [][]string{}
|
|
||||||
name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml"
|
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 {
|
if err != nil {
|
||||||
return r
|
return rows
|
||||||
}
|
}
|
||||||
rows := xlsx.SheetData.Row
|
var inElement string
|
||||||
for _, row := range rows {
|
var row []string
|
||||||
c := []string{}
|
for {
|
||||||
for _, colCell := range row.C {
|
token, _ := decoder.Token()
|
||||||
val, _ := colCell.getValueFrom(f)
|
if token == nil {
|
||||||
c = append(c, val)
|
break
|
||||||
}
|
}
|
||||||
r = append(r, c)
|
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)
|
||||||
}
|
}
|
||||||
return r
|
rows = append(rows, row)
|
||||||
|
row = row[:0]
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetRowHeight provides a function to set the height of a single row.
|
// 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.
|
// readXMLSST read xmlSST simple function.
|
||||||
func readXMLSST(f *File) (xlsxSST, error) {
|
func readXMLSST(f *File) (*xlsxSST, error) {
|
||||||
shardStrings := xlsxSST{}
|
shardStrings := xlsxSST{}
|
||||||
err := xml.Unmarshal([]byte(f.readXML("xl/sharedStrings.xml")), &shardStrings)
|
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
|
// 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.
|
// 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 {
|
switch xlsx.T {
|
||||||
case "s":
|
case "s":
|
||||||
xlsxSI := 0
|
xlsxSI := 0
|
||||||
xlsxSI, _ = strconv.Atoi(xlsx.V)
|
xlsxSI, _ = strconv.Atoi(xlsx.V)
|
||||||
d, err := readXMLSST(f)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if len(d.SI[xlsxSI].R) > 0 {
|
if len(d.SI[xlsxSI].R) > 0 {
|
||||||
value := ""
|
value := ""
|
||||||
for _, v := range d.SI[xlsxSI].R {
|
for _, v := range d.SI[xlsxSI].R {
|
||||||
|
|
Loading…
Reference in New Issue