summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cell.go3
-rw-r--r--col.go120
-rw-r--r--col_test.go53
-rw-r--r--lib.go3
-rw-r--r--rows.go3
5 files changed, 106 insertions, 76 deletions
diff --git a/cell.go b/cell.go
index 0912dc4..fb0a833 100644
--- a/cell.go
+++ b/cell.go
@@ -41,9 +41,6 @@ var rwMutex sync.RWMutex
func (f *File) GetCellValue(sheet, axis string) (string, error) {
return f.getCellStringFunc(sheet, axis, func(x *xlsxWorksheet, c *xlsxC) (string, bool, error) {
val, err := c.getValueFrom(f, f.sharedStringsReader())
- if err != nil {
- return val, false, err
- }
return val, true, err
})
}
diff --git a/col.go b/col.go
index 561cec9..6756f2f 100644
--- a/col.go
+++ b/col.go
@@ -13,8 +13,8 @@ import (
"bytes"
"encoding/xml"
"errors"
- "fmt"
"math"
+ "strconv"
"strings"
"github.com/mohae/deepcopy"
@@ -34,10 +34,11 @@ type Cols struct {
sheet string
cols []xlsxCols
f *File
- decoder *xml.Decoder
+ sheetXML []byte
}
-// GetCols return all the columns in a sheet by given worksheet name (case sensitive). For example:
+// GetCols return all the columns in a sheet by given worksheet name (case
+// sensitive). For example:
//
// cols, err := f.Cols("Sheet1")
// if err != nil {
@@ -60,29 +61,17 @@ func (f *File) GetCols(sheet string) ([][]string, error) {
if err != nil {
return nil, err
}
-
results := make([][]string, 0, 64)
-
for cols.Next() {
- if cols.Error() != nil {
- break
- }
-
- col, err := cols.Rows()
- if err != nil {
- break
- }
-
+ col, _ := cols.Rows()
results = append(results, col)
}
-
return results, nil
}
// Next will return true if the next col element is found.
func (cols *Cols) Next() bool {
cols.curCol++
-
return cols.curCol <= cols.totalCol
}
@@ -91,27 +80,53 @@ func (cols *Cols) Error() error {
return cols.err
}
-// Rows return the current column's row values
+// Rows return the current column's row values.
func (cols *Cols) Rows() ([]string, error) {
var (
- err error
- rows []string
+ err error
+ inElement string
+ cellCol, cellRow int
+ rows []string
)
-
if cols.stashCol >= cols.curCol {
return rows, err
}
-
- for i := 1; i <= cols.totalRow; i++ {
- colName, _ := ColumnNumberToName(cols.curCol)
- val, _ := cols.f.GetCellValue(cols.sheet, fmt.Sprintf("%s%d", colName, i))
- rows = append(rows, val)
+ d := cols.f.sharedStringsReader()
+ decoder := cols.f.xmlNewDecoder(bytes.NewReader(cols.sheetXML))
+ for {
+ token, _ := decoder.Token()
+ if token == nil {
+ break
+ }
+ switch startElement := token.(type) {
+ case xml.StartElement:
+ inElement = startElement.Name.Local
+ if inElement == "c" {
+ for _, attr := range startElement.Attr {
+ if attr.Name.Local == "r" {
+ if cellCol, cellRow, err = CellNameToCoordinates(attr.Value); err != nil {
+ return rows, err
+ }
+ blank := cellRow - len(rows)
+ for i := 1; i < blank; i++ {
+ rows = append(rows, "")
+ }
+ if cellCol == cols.curCol {
+ colCell := xlsxC{}
+ _ = decoder.DecodeElement(&colCell, &startElement)
+ val, _ := colCell.getValueFrom(cols.f, d)
+ rows = append(rows, val)
+ }
+ }
+ }
+ }
+ }
}
-
return rows, nil
}
-// Cols returns a columns iterator, used for streaming/reading data for a worksheet with a large data. For example:
+// Cols returns a columns iterator, used for streaming/reading data for a
+// worksheet with a large data. For example:
//
// cols, err := f.Cols("Sheet1")
// if err != nil {
@@ -134,60 +149,51 @@ func (f *File) Cols(sheet string) (*Cols, error) {
if !ok {
return nil, ErrSheetNotExist{sheet}
}
-
if f.Sheet[name] != nil {
output, _ := xml.Marshal(f.Sheet[name])
f.saveFileList(name, replaceRelationshipsNameSpaceBytes(output))
}
-
var (
- inElement string
- cols Cols
- colsNum, rowsNum []int
+ inElement string
+ cols Cols
+ cellCol int
+ err error
)
- decoder := f.xmlNewDecoder(bytes.NewReader(f.readXML(name)))
-
+ cols.sheetXML = f.readXML(name)
+ decoder := f.xmlNewDecoder(bytes.NewReader(cols.sheetXML))
for {
token, _ := decoder.Token()
if token == nil {
break
}
-
switch startElement := token.(type) {
case xml.StartElement:
inElement = startElement.Name.Local
- if inElement == "dimension" {
- colsNum = make([]int, 0)
- rowsNum = make([]int, 0)
-
+ if inElement == "row" {
for _, attr := range startElement.Attr {
- if attr.Name.Local == "ref" {
- sheetCoordinates := attr.Value
- if i := strings.Index(sheetCoordinates, ":"); i <= -1 {
- return &cols, errors.New("Sheet coordinates are wrong")
+ if attr.Name.Local == "r" {
+ if cols.totalRow, err = strconv.Atoi(attr.Value); err != nil {
+ return &cols, err
}
-
- coordinates := strings.Split(sheetCoordinates, ":")
- for _, coordinate := range coordinates {
- c, r, _ := SplitCellName(coordinate)
- columnNum, _ := ColumnNameToNumber(c)
- colsNum = append(colsNum, columnNum)
- rowsNum = append(rowsNum, r)
+ }
+ }
+ }
+ if inElement == "c" {
+ for _, attr := range startElement.Attr {
+ if attr.Name.Local == "r" {
+ if cellCol, _, err = CellNameToCoordinates(attr.Value); err != nil {
+ return &cols, err
+ }
+ if cellCol > cols.totalCol {
+ cols.totalCol = cellCol
}
}
}
-
- cols.totalCol = colsNum[1] - (colsNum[0] - 1)
- cols.totalRow = rowsNum[1] - (rowsNum[0] - 1)
}
- default:
}
}
-
cols.f = f
cols.sheet = trimSheetName(sheet)
- cols.decoder = f.xmlNewDecoder(bytes.NewReader(f.readXML(name)))
-
return &cols, nil
}
diff --git a/col_test.go b/col_test.go
index a130f2b..fac78eb 100644
--- a/col_test.go
+++ b/col_test.go
@@ -1,7 +1,6 @@
package excelize
import (
- "bytes"
"path/filepath"
"testing"
@@ -61,7 +60,7 @@ func TestCols(t *testing.T) {
func TestColumnsIterator(t *testing.T) {
const (
sheet2 = "Sheet2"
- expectedNumCol = 4
+ expectedNumCol = 9
)
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
@@ -82,29 +81,57 @@ func TestColumnsIterator(t *testing.T) {
for _, cell := range cells {
assert.NoError(t, f.SetCellValue("Sheet1", cell, 1))
}
- f.Sheet["xl/worksheets/sheet1.xml"] = &xlsxWorksheet{
- Dimension: &xlsxDimension{
- Ref: "C2:D4",
- },
- }
cols, err = f.Cols("Sheet1")
require.NoError(t, err)
colCount = 0
for cols.Next() {
colCount++
- require.True(t, colCount <= 2, "colCount is greater than expected")
+ require.True(t, colCount <= 4, "colCount is greater than expected")
}
- assert.Equal(t, 2, colCount)
+ assert.Equal(t, 4, colCount)
}
func TestColsError(t *testing.T) {
- xlsx, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
+ f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
+ if !assert.NoError(t, err) {
+ t.FailNow()
+ }
+ _, err = f.Cols("SheetN")
+ assert.EqualError(t, err, "sheet SheetN is not exist")
+}
+
+func TestGetColsError(t *testing.T) {
+ f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
- _, err = xlsx.Cols("SheetN")
+ _, err = f.GetCols("SheetN")
assert.EqualError(t, err, "sheet SheetN is not exist")
+
+ f = NewFile()
+ delete(f.Sheet, "xl/worksheets/sheet1.xml")
+ f.XLSX["xl/worksheets/sheet1.xml"] = []byte(`<worksheet><sheetData><row r="A"><c r="2" t="str"><v>B</v></c></row></sheetData></worksheet>`)
+ f.checked = nil
+ _, err = f.GetCols("Sheet1")
+ assert.EqualError(t, err, `strconv.Atoi: parsing "A": invalid syntax`)
+
+ f = NewFile()
+ delete(f.Sheet, "xl/worksheets/sheet1.xml")
+ f.XLSX["xl/worksheets/sheet1.xml"] = []byte(`<worksheet><sheetData><row r="2"><c r="A" t="str"><v>B</v></c></row></sheetData></worksheet>`)
+ f.checked = nil
+ _, err = f.GetCols("Sheet1")
+ assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
+
+ f = NewFile()
+ cols, err := f.Cols("Sheet1")
+ assert.NoError(t, err)
+ cols.totalRow = 2
+ cols.totalCol = 2
+ cols.curCol = 1
+ cols.decoder = []byte(`<worksheet><sheetData><row r="1"><c r="A" t="str"><v>A</v></c></row></sheetData></worksheet>`)
+ _, err = cols.Rows()
+ assert.EqualError(t, err, `cannot convert cell "A" to coordinates: invalid cell name "A"`)
}
func TestColsRows(t *testing.T) {
@@ -112,7 +139,7 @@ func TestColsRows(t *testing.T) {
f.NewSheet("Sheet1")
cols, err := f.Cols("Sheet1")
- assert.EqualError(t, err, `Sheet coordinates are wrong`)
+ assert.NoError(t, err)
assert.NoError(t, f.SetCellValue("Sheet1", "A1", 1))
f.Sheet["xl/worksheets/sheet1.xml"] = &xlsxWorksheet{
@@ -126,7 +153,7 @@ func TestColsRows(t *testing.T) {
assert.NoError(t, err)
// Test if token is nil
- cols.decoder = f.xmlNewDecoder(bytes.NewReader(nil))
+ cols.decoder = nil
_, err = cols.Rows()
assert.NoError(t, err)
}
diff --git a/lib.go b/lib.go
index d97bb20..ae9287c 100644
--- a/lib.go
+++ b/lib.go
@@ -152,6 +152,9 @@ func ColumnNumberToName(num int) (string, error) {
if num < 1 {
return "", fmt.Errorf("incorrect column number %d", num)
}
+ if num > TotalColumns {
+ return "", fmt.Errorf("column number exceeds maximum limit")
+ }
var col string
for num > 0 {
col = string((num-1)%26+65) + col
diff --git a/rows.go b/rows.go
index 352f1eb..f9770aa 100644
--- a/rows.go
+++ b/rows.go
@@ -46,9 +46,6 @@ func (f *File) GetRows(sheet string) ([][]string, error) {
}
results := make([][]string, 0, 64)
for rows.Next() {
- if rows.Error() != nil {
- break
- }
row, err := rows.Columns()
if err != nil {
break