add iterator method for rows

This commit is contained in:
Lunny Xiao 2018-05-05 13:33:19 +08:00
parent 934ecec1a9
commit bc451a78de
No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
2 changed files with 138 additions and 0 deletions

96
rows.go
View File

@ -3,6 +3,8 @@ package excelize
import (
"bytes"
"encoding/xml"
"fmt"
"io"
"math"
"strconv"
"strings"
@ -67,6 +69,100 @@ func (f *File) GetRows(sheet string) [][]string {
return rows
}
// Rows defines an iterator to a sheet
type Rows struct {
decoder *xml.Decoder
token xml.Token
err error
f *File
}
// Next will return true if find the next row element.
func (rows *Rows) Next() bool {
for {
rows.token, rows.err = rows.decoder.Token()
if rows.err == io.EOF {
rows.err = nil
}
if rows.token == nil {
return false
}
switch startElement := rows.token.(type) {
case xml.StartElement:
inElement := startElement.Name.Local
if inElement == "row" {
return true
}
}
}
}
// Error will return the error when the find next row element
func (rows *Rows) Error() error {
return rows.err
}
// Columns return the current row's column values
func (rows *Rows) Columns() []string {
if rows.token == nil {
return []string{}
}
startElement := rows.token.(xml.StartElement)
r := xlsxRow{}
rows.decoder.DecodeElement(&r, &startElement)
d := rows.f.sharedStringsReader()
row := make([]string, len(r.C), len(r.C))
for _, colCell := range r.C {
c := TitleToNumber(strings.Map(letterOnlyMapF, colCell.R))
val, _ := colCell.getValueFrom(rows.f, d)
row[c] = val
}
return row
}
// ErrSheetNotExist defines an error of sheet is not exist
type ErrSheetNotExist struct {
SheetName string
}
func (err ErrSheetNotExist) Error() string {
return fmt.Sprintf("Sheet %s is not exist", string(err.SheetName))
}
// Rows return a rows iterator. For example:
//
// rows, err := xlsx.GetRows("Sheet1")
//
// for rows.Next() {
// for _, colCell := range rows.Columns() {
// fmt.Print(colCell, "\t")
// }
// fmt.Println()
// }
//
func (f *File) Rows(sheet string) (*Rows, error) {
xlsx := f.workSheetReader(sheet)
name, ok := f.sheetMap[trimSheetName(sheet)]
if !ok {
return nil, ErrSheetNotExist{sheet}
}
if xlsx != nil {
output, err := xml.Marshal(f.Sheet[name])
if err != nil {
return nil, err
}
f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output)))
}
return &Rows{
f: f,
decoder: xml.NewDecoder(strings.NewReader(f.readXML(name))),
}, nil
}
// getTotalRowsCols provides a function to get total columns and rows in a
// worksheet.
func (f *File) getTotalRowsCols(name string) (int, int) {

42
rows_test.go Normal file
View File

@ -0,0 +1,42 @@
package excelize
import (
"testing"
"github.com/stretchr/testify/assert"
)
func trimSliceSpace(s []string) []string {
for {
if len(s) > 0 && s[len(s)-1] == "" {
s = s[:len(s)-1]
} else {
break
}
}
return s
}
func TestRows(t *testing.T) {
xlsx, err := OpenFile("./test/Book1.xlsx")
assert.NoError(t, err)
rows, err := xlsx.Rows("Sheet2")
assert.NoError(t, err)
rowStrs := make([][]string, 0)
var i = 0
for rows.Next() {
i++
columns := rows.Columns()
//fmt.Println(i, columns)
rowStrs = append(rowStrs, columns)
}
assert.NoError(t, rows.Error())
dstRows := xlsx.GetRows("Sheet2")
assert.EqualValues(t, len(dstRows), len(rowStrs))
for i := 0; i < len(rowStrs); i++ {
assert.EqualValues(t, trimSliceSpace(dstRows[i]), trimSliceSpace(rowStrs[i]))
}
}