Переглянути джерело

add iterator method for rows

Lunny Xiao 7 роки тому
батько
коміт
bc451a78de
2 змінених файлів з 138 додано та 0 видалено
  1. 96 0
      rows.go
  2. 42 0
      rows_test.go

+ 96 - 0
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) {

+ 42 - 0
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]))
+	}
+}