summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2018-05-05 13:33:19 +0800
committerLunny Xiao <xiaolunwen@gmail.com>2018-05-05 13:33:19 +0800
commitbc451a78de32ccde2a4f6d0851ea6e41e45408f1 (patch)
treee1c8723b1e6c61b76379018b7843acc3c9610e36
parent934ecec1a96bfd5a1ecf3f1f373332504971c5fd (diff)
add iterator method for rows
-rw-r--r--rows.go96
-rw-r--r--rows_test.go42
2 files changed, 138 insertions, 0 deletions
diff --git a/rows.go b/rows.go
index 78f38a3..02a6876 100644
--- a/rows.go
+++ b/rows.go
@@ -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) {
diff --git a/rows_test.go b/rows_test.go
new file mode 100644
index 0000000..eadf077
--- /dev/null
+++ b/rows_test.go
@@ -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]))
+ }
+}