summaryrefslogtreecommitdiff
path: root/rows.go
diff options
context:
space:
mode:
Diffstat (limited to 'rows.go')
-rw-r--r--rows.go129
1 files changed, 100 insertions, 29 deletions
diff --git a/rows.go b/rows.go
index e12e349..fc7b55a 100644
--- a/rows.go
+++ b/rows.go
@@ -11,6 +11,7 @@ package excelize
import (
"bytes"
+ "encoding/xml"
"errors"
"fmt"
"io"
@@ -51,15 +52,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 {
- return rows.curRow < len(rows.rows)
+ rows.curRow++
+ return rows.curRow <= rows.totalRow
}
// Error will return the error when the find next row element
@@ -69,20 +74,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]
- rows.curRow++
-
- 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
@@ -91,7 +133,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:
@@ -106,22 +148,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 := f.xmlNewDecoder(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 = f.xmlNewDecoder(bytes.NewReader(f.readXML(name)))
+ return &rows, nil
}
// SetRowHeight provides a function to set the height of a single row. For
@@ -219,7 +287,10 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
case "str":
return f.formattedValue(xlsx.S, xlsx.V), nil
case "inlineStr":
- return f.formattedValue(xlsx.S, xlsx.IS.String()), nil
+ if xlsx.IS != nil {
+ return f.formattedValue(xlsx.S, xlsx.IS.String()), nil
+ }
+ return f.formattedValue(xlsx.S, xlsx.V), nil
default:
return f.formattedValue(xlsx.S, xlsx.V), nil
}