summaryrefslogtreecommitdiff
path: root/rows.go
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2019-11-23 04:13:59 +0800
committerxuri <xuri.me@gmail.com>2019-11-23 04:13:59 +0800
commit7965e1231b736f8507f93f6383b76332eb15ff5f (patch)
tree6f59a9e29efc085d0f54ead48a1b66af9f8266bb /rows.go
parentc8c8397751e994dca05467e7615f6ee77704775b (diff)
Resolve #146, make the GetRow function read data as streaming. Ref: #382, #515
Diffstat (limited to 'rows.go')
-rw-r--r--rows.go122
1 files changed, 95 insertions, 27 deletions
diff --git a/rows.go b/rows.go
index c8ad2b1..69a9846 100644
--- a/rows.go
+++ b/rows.go
@@ -10,6 +10,7 @@
package excelize
import (
+ "bytes"
"encoding/xml"
"errors"
"fmt"
@@ -49,16 +50,19 @@ func (f *File) GetRows(sheet string) ([][]string, error) {
// Rows defines an iterator to a sheet
type Rows struct {
- err error
- f *File
- rows []xlsxRow
- curRow int
+ err error
+ f *File
+ rows []xlsxRow
+ sheet string
+ curRow int
+ totalRow int
+ decoder *xml.Decoder
}
// Next will return true if find the next row element.
func (rows *Rows) Next() bool {
rows.curRow++
- return rows.curRow <= len(rows.rows)
+ return rows.curRow <= rows.totalRow
}
// Error will return the error when the find next row element
@@ -68,19 +72,57 @@ func (rows *Rows) Error() error {
// Columns return the current row's column values
func (rows *Rows) Columns() ([]string, error) {
- curRow := rows.rows[rows.curRow-1]
-
- columns := make([]string, len(curRow.C))
+ var (
+ err error
+ inElement string
+ row, cellCol int
+ columns []string
+ )
d := rows.f.sharedStringsReader()
- for _, colCell := range curRow.C {
- col, _, err := CellNameToCoordinates(colCell.R)
- if err != nil {
- return columns, err
+ for {
+ token, _ := rows.decoder.Token()
+ if token == nil {
+ break
+ }
+ switch startElement := token.(type) {
+ case xml.StartElement:
+ inElement = startElement.Name.Local
+ if inElement == "row" {
+ for _, attr := range startElement.Attr {
+ if attr.Name.Local == "r" {
+ row, err = strconv.Atoi(attr.Value)
+ if err != nil {
+ return columns, err
+ }
+ if row > rows.curRow {
+ return columns, err
+ }
+ }
+ }
+ }
+ if inElement == "c" {
+ colCell := xlsxC{}
+ _ = rows.decoder.DecodeElement(&colCell, &startElement)
+ cellCol, _, err = CellNameToCoordinates(colCell.R)
+ if err != nil {
+ return columns, err
+ }
+ blank := cellCol - len(columns)
+ for i := 1; i < blank; i++ {
+ columns = append(columns, "")
+ }
+ val, _ := colCell.getValueFrom(rows.f, d)
+ columns = append(columns, val)
+ }
+ case xml.EndElement:
+ inElement = startElement.Name.Local
+ if inElement == "row" {
+ return columns, err
+ }
+ default:
}
- val, _ := colCell.getValueFrom(rows.f, d)
- columns[col-1] = val
}
- return columns, nil
+ return columns, err
}
// ErrSheetNotExist defines an error of sheet is not exist
@@ -89,7 +131,7 @@ type ErrSheetNotExist struct {
}
func (err ErrSheetNotExist) Error() string {
- return fmt.Sprintf("Sheet %s is not exist", string(err.SheetName))
+ return fmt.Sprintf("sheet %s is not exist", string(err.SheetName))
}
// Rows return a rows iterator. For example:
@@ -104,22 +146,48 @@ func (err ErrSheetNotExist) Error() string {
// }
//
func (f *File) Rows(sheet string) (*Rows, error) {
- xlsx, err := f.workSheetReader(sheet)
- if err != nil {
- return nil, err
- }
name, ok := f.sheetMap[trimSheetName(sheet)]
if !ok {
return nil, ErrSheetNotExist{sheet}
}
- if xlsx != nil {
- data := f.readXML(name)
- f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(namespaceStrictToTransitional(data)))
+ if f.Sheet[name] != nil {
+ // flush data
+ output, _ := xml.Marshal(f.Sheet[name])
+ f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output))
+ }
+ var (
+ err error
+ inElement string
+ row int
+ rows Rows
+ )
+ decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name)))
+ for {
+ token, _ := decoder.Token()
+ if token == nil {
+ break
+ }
+ switch startElement := token.(type) {
+ case xml.StartElement:
+ inElement = startElement.Name.Local
+ if inElement == "row" {
+ for _, attr := range startElement.Attr {
+ if attr.Name.Local == "r" {
+ row, err = strconv.Atoi(attr.Value)
+ if err != nil {
+ return &rows, err
+ }
+ }
+ }
+ rows.totalRow = row
+ }
+ default:
+ }
}
- return &Rows{
- f: f,
- rows: xlsx.SheetData.Row,
- }, nil
+ rows.f = f
+ rows.sheet = name
+ rows.decoder = xml.NewDecoder(bytes.NewReader(f.readXML(name)))
+ return &rows, nil
}
// SetRowHeight provides a function to set the height of a single row. For