From 0833a9d5dab846ed01be52fa59c97ede36ee4a93 Mon Sep 17 00:00:00 2001 From: Ri Xu Date: Sun, 12 Feb 2017 19:03:24 +0800 Subject: - 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 --- rows.go | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 89365a2..58b52a3 100644 --- a/rows.go +++ b/rows.go @@ -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 { -- cgit v1.2.1