From 421f945f51f254054991127758db0520cf0f5456 Mon Sep 17 00:00:00 2001 From: xuri Date: Sat, 8 Jun 2019 00:00:55 +0800 Subject: Fixed #418, #420, #421, init adjust calculation chain support Update testing case --- rows.go | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'rows.go') diff --git a/rows.go b/rows.go index b228fc2..249ca2f 100644 --- a/rows.go +++ b/rows.go @@ -439,6 +439,10 @@ func (f *File) RemoveRow(sheet string, row int) error { // // err := f.InsertRow("Sheet1", 3) // +// Use this method with caution, which will affect changes in references such +// as formulas, charts, and so on. If there is any referenced value of the +// worksheet, it will cause a file error when you open it. The excelize only +// partially updates these references currently. func (f *File) InsertRow(sheet string, row int) error { if row < 1 { return newInvalidRowNumberError(row) -- cgit v1.2.1 From 821632cf89422b9955160a3af7f28f05a12f70f8 Mon Sep 17 00:00:00 2001 From: xuri Date: Wed, 12 Jun 2019 08:10:33 +0800 Subject: Fix #424, refactor merged cells adjuster --- rows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 249ca2f..064fefe 100644 --- a/rows.go +++ b/rows.go @@ -421,7 +421,7 @@ func (f *File) RemoveRow(sheet string, row int) error { return err } if row > len(xlsx.SheetData.Row) { - return nil + return f.adjustHelper(sheet, rows, row, -1) } for rowIdx := range xlsx.SheetData.Row { if xlsx.SheetData.Row[rowIdx].R == row { -- cgit v1.2.1 From 9f8623047d2fc38e12c3b214475710d25ec88c55 Mon Sep 17 00:00:00 2001 From: xuri Date: Thu, 20 Jun 2019 00:00:40 +0800 Subject: Optimize code, fix golint issues --- rows.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 064fefe..3079d5a 100644 --- a/rows.go +++ b/rows.go @@ -21,7 +21,7 @@ import ( // GetRows return all the rows in a sheet by given worksheet name (case // sensitive). For example: // -// rows, err := f.GetRows("Sheet1") +// rows, err := f.GetRows("Sheet1") // for _, row := range rows { // for _, colCell := range row { // fmt.Print(colCell, "\t") @@ -160,7 +160,7 @@ func (err ErrSheetNotExist) Error() string { // // rows, err := f.Rows("Sheet1") // for rows.Next() { -// row, err := rows.Columns() +// row, err := rows.Columns() // for _, colCell := range row { // fmt.Print(colCell, "\t") // } -- cgit v1.2.1 From ac91ca0ded4111ed9f22578d4a0570a9084c97b0 Mon Sep 17 00:00:00 2001 From: Harris Date: Sun, 4 Aug 2019 17:23:42 -0500 Subject: Only parse xml once when reading We were parsing the whole sheet twice since the sheet reader already reads in all the rows. getTotalRowsCols function is unused after these changes so it has been deleted as well. Closes #439 --- rows.go | 142 ++++++++++------------------------------------------------------ 1 file changed, 21 insertions(+), 121 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 3079d5a..cb0e31f 100644 --- a/rows.go +++ b/rows.go @@ -10,10 +10,8 @@ package excelize import ( - "bytes" "encoding/xml" "fmt" - "io" "math" "strconv" ) @@ -30,95 +28,35 @@ import ( // } // func (f *File) GetRows(sheet string) ([][]string, error) { - name, ok := f.sheetMap[trimSheetName(sheet)] - if !ok { - return nil, nil - } - - xlsx, err := f.workSheetReader(sheet) + rows, err := f.Rows(sheet) if err != nil { return nil, err } - if xlsx != nil { - output, _ := xml.Marshal(f.Sheet[name]) - f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) - } - - xml.NewDecoder(bytes.NewReader(f.readXML(name))) - d := f.sharedStringsReader() - var ( - inElement string - rowData xlsxRow - ) - - rowCount, colCount, err := f.getTotalRowsCols(name) - if err != nil { - return nil, nil - } - rows := make([][]string, rowCount) - for i := range rows { - rows[i] = make([]string, colCount) - } - - var row int - decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name))) - for { - token, _ := decoder.Token() - if token == nil { + results := make([][]string, 0, 64) + for rows.Next() { + if rows.Error() != nil { break } - switch startElement := token.(type) { - case xml.StartElement: - inElement = startElement.Name.Local - if inElement == "row" { - rowData = xlsxRow{} - _ = decoder.DecodeElement(&rowData, &startElement) - cr := rowData.R - 1 - for _, colCell := range rowData.C { - col, _, err := CellNameToCoordinates(colCell.R) - if err != nil { - return nil, err - } - val, _ := colCell.getValueFrom(f, d) - rows[cr][col-1] = val - if val != "" { - row = rowData.R - } - } - } - default: + row, err := rows.Columns() + if err != nil { + break } + results = append(results, row) } - return rows[:row], nil + return results, nil } // Rows defines an iterator to a sheet type Rows struct { - decoder *xml.Decoder - token xml.Token - err error - f *File + err error + f *File + rows []xlsxRow + curRow int } // 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 - } - } - } + return rows.curRow < len(rows.rows) } // Error will return the error when the find next row element @@ -128,15 +66,12 @@ func (rows *Rows) Error() error { // Columns return the current row's column values func (rows *Rows) Columns() ([]string, error) { - if rows.token == nil { - return []string{}, nil - } - startElement := rows.token.(xml.StartElement) - r := xlsxRow{} - _ = rows.decoder.DecodeElement(&r, &startElement) + curRow := rows.rows[rows.curRow] + rows.curRow++ + + columns := make([]string, len(curRow.C)) d := rows.f.sharedStringsReader() - columns := make([]string, len(r.C)) - for _, colCell := range r.C { + for _, colCell := range curRow.C { col, _, err := CellNameToCoordinates(colCell.R) if err != nil { return columns, err @@ -181,46 +116,11 @@ func (f *File) Rows(sheet string) (*Rows, error) { f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) } return &Rows{ - f: f, - decoder: xml.NewDecoder(bytes.NewReader(f.readXML(name))), + f: f, + rows: xlsx.SheetData.Row, }, nil } -// getTotalRowsCols provides a function to get total columns and rows in a -// worksheet. -func (f *File) getTotalRowsCols(name string) (int, int, error) { - decoder := xml.NewDecoder(bytes.NewReader(f.readXML(name))) - var inElement string - var r xlsxRow - var tr, tc int - for { - token, _ := decoder.Token() - if token == nil { - break - } - switch startElement := token.(type) { - case xml.StartElement: - inElement = startElement.Name.Local - if inElement == "row" { - r = xlsxRow{} - _ = decoder.DecodeElement(&r, &startElement) - tr = r.R - for _, colCell := range r.C { - col, _, err := CellNameToCoordinates(colCell.R) - if err != nil { - return tr, tc, err - } - if col > tc { - tc = col - } - } - } - default: - } - } - return tr, tc, nil -} - // SetRowHeight provides a function to set the height of a single row. For // example, set the height of the first row in Sheet1: // -- cgit v1.2.1 From e07581e980444b64bc15fce328ff07736ac9dbf6 Mon Sep 17 00:00:00 2001 From: Harris Date: Tue, 6 Aug 2019 16:43:56 -0500 Subject: Further improve read performance Instead of re-encoding the full sheet to change the namespaces in the encoded bytes, read the sheet again and do the byte replacements there. In this case, file access ends up being more performant than marshaling the sheet back to XML. In the SharedStrings test, ensure the strings are actually read. Fix #439 --- rows.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index cb0e31f..220c233 100644 --- a/rows.go +++ b/rows.go @@ -112,8 +112,8 @@ func (f *File) Rows(sheet string) (*Rows, error) { return nil, ErrSheetNotExist{sheet} } if xlsx != nil { - output, _ := xml.Marshal(f.Sheet[name]) - f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) + data := f.readXML(name) + f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(namespaceStrictToTransitional(data))) } return &Rows{ f: f, -- cgit v1.2.1 From acd76425c2ee55c45a51cf7f71c8a6187a09f507 Mon Sep 17 00:00:00 2001 From: Harris Date: Wed, 7 Aug 2019 16:26:13 -0500 Subject: Handle multi row inline strings The inline string struct is actually the same as the shared strings struct, reuse it. Note that Go version 1.10 is required. Fixes #462 --- rows.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 220c233..c17179f 100644 --- a/rows.go +++ b/rows.go @@ -206,18 +206,11 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) { case "s": xlsxSI := 0 xlsxSI, _ = strconv.Atoi(xlsx.V) - if len(d.SI[xlsxSI].R) > 0 { - value := "" - for _, v := range d.SI[xlsxSI].R { - value += v.T - } - return value, nil - } - return f.formattedValue(xlsx.S, d.SI[xlsxSI].T), nil + return f.formattedValue(xlsx.S, d.SI[xlsxSI].String()), nil case "str": return f.formattedValue(xlsx.S, xlsx.V), nil case "inlineStr": - return f.formattedValue(xlsx.S, xlsx.IS.T), nil + return f.formattedValue(xlsx.S, xlsx.IS.String()), nil default: return f.formattedValue(xlsx.S, xlsx.V), nil } -- cgit v1.2.1 From 9c70d0ac868f66badf2663cc7b4b3c46d5411131 Mon Sep 17 00:00:00 2001 From: xuri Date: Sun, 11 Aug 2019 00:36:14 +0800 Subject: Documentation updated, Go 1.10+ required --- rows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index c17179f..6281e62 100644 --- a/rows.go +++ b/rows.go @@ -5,7 +5,7 @@ // Package excelize providing a set of functions that allow you to write to // and read from XLSX files. Support reads and writes XLSX file generated by // Microsoft Excelâ„¢ 2007 and later. Support save file without losing original -// charts of XLSX. This library needs Go version 1.8 or later. +// charts of XLSX. This library needs Go version 1.10 or later. package excelize -- cgit v1.2.1 From a34d3b8c86d67d3ad0bc0dbedb69d3b4ebbc210f Mon Sep 17 00:00:00 2001 From: xuri Date: Tue, 24 Sep 2019 21:53:19 +0800 Subject: Compatibility improvement --- rows.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 6281e62..3796441 100644 --- a/rows.go +++ b/rows.go @@ -11,6 +11,7 @@ package excelize import ( "encoding/xml" + "errors" "fmt" "math" "strconv" @@ -257,8 +258,8 @@ func (f *File) GetRowVisible(sheet string, row int) (bool, error) { } // SetRowOutlineLevel provides a function to set outline level number of a -// single row by given worksheet name and Excel row number. For example, -// outline row 2 in Sheet1 to level 1: +// single row by given worksheet name and Excel row number. The value of +// parameter 'level' is 1-7. For example, outline row 2 in Sheet1 to level 1: // // err := f.SetRowOutlineLevel("Sheet1", 2, 1) // @@ -266,6 +267,9 @@ func (f *File) SetRowOutlineLevel(sheet string, row int, level uint8) error { if row < 1 { return newInvalidRowNumberError(row) } + if level > 7 || level < 1 { + return errors.New("invalid outline level") + } xlsx, err := f.workSheetReader(sheet) if err != nil { return err -- cgit v1.2.1 From 866fda230028a3a9e6ff1c5234e432ad850d3c6b Mon Sep 17 00:00:00 2001 From: ducquangkstn Date: Fri, 18 Oct 2019 13:57:35 +0700 Subject: fix #503 rows next issue --- rows.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 3796441..c8ad2b1 100644 --- a/rows.go +++ b/rows.go @@ -57,7 +57,8 @@ type Rows struct { // 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 <= len(rows.rows) } // Error will return the error when the find next row element @@ -67,8 +68,7 @@ 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++ + curRow := rows.rows[rows.curRow-1] columns := make([]string, len(curRow.C)) d := rows.f.sharedStringsReader() -- cgit v1.2.1 From 7965e1231b736f8507f93f6383b76332eb15ff5f Mon Sep 17 00:00:00 2001 From: xuri Date: Sat, 23 Nov 2019 04:13:59 +0800 Subject: Resolve #146, make the GetRow function read data as streaming. Ref: #382, #515 --- rows.go | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 95 insertions(+), 27 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index c8ad2b1..69a9846 100644 --- a/rows.go +++ b/rows.go @@ -10,6 +10,7 @@ package excelize import ( + "bytes" "encoding/xml" "errors" "fmt" @@ -49,16 +50,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 { rows.curRow++ - return rows.curRow <= len(rows.rows) + return rows.curRow <= rows.totalRow } // Error will return the error when the find next row element @@ -68,19 +72,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-1] - - 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 @@ -89,7 +131,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: @@ -104,22 +146,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 := xml.NewDecoder(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 = xml.NewDecoder(bytes.NewReader(f.readXML(name))) + return &rows, nil } // SetRowHeight provides a function to set the height of a single row. For -- cgit v1.2.1 From 5d8365ca17240f5b144d437a7b47052f22c4f3c6 Mon Sep 17 00:00:00 2001 From: xuri Date: Wed, 11 Dec 2019 00:02:33 +0800 Subject: Fix #529, handle empty inline rich text --- rows.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 69a9846..ff4aa0f 100644 --- a/rows.go +++ b/rows.go @@ -279,7 +279,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 } -- cgit v1.2.1 From b1b3c0d15158abc71267da5893de020f047c3872 Mon Sep 17 00:00:00 2001 From: Alex Geer Date: Thu, 19 Dec 2019 19:30:48 +0300 Subject: =?UTF-8?q?Fix=20#539=20Fixed=20error=20opening=20excel=20file=20c?= =?UTF-8?q?reated=20in=20encoding=20d=E2=80=A6=20(#540)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed issue #539 Fixed error opening excel file created in encoding different from UTF-8, added logging of possible errors when decoding XML if the function does not provide exit with an error * Added test for CharsetReader * Fixed #discussion_r359397878 Discussion: https://github.com/360EntSecGroup-Skylar/excelize/pull/540#discussion_r359397878 * Fixed go fmt * go mod tidy and removed unused imports * The code has been refactored --- rows.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 3796441..e12e349 100644 --- a/rows.go +++ b/rows.go @@ -10,9 +10,11 @@ package excelize import ( - "encoding/xml" + "bytes" "errors" "fmt" + "io" + "log" "math" "strconv" ) @@ -187,15 +189,21 @@ func (f *File) GetRowHeight(sheet string, row int) (float64, error) { // sharedStringsReader provides a function to get the pointer to the structure // after deserialization of xl/sharedStrings.xml. func (f *File) sharedStringsReader() *xlsxSST { + var err error + if f.SharedStrings == nil { var sharedStrings xlsxSST ss := f.readXML("xl/sharedStrings.xml") if len(ss) == 0 { ss = f.readXML("xl/SharedStrings.xml") } - _ = xml.Unmarshal(namespaceStrictToTransitional(ss), &sharedStrings) + if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(ss))). + Decode(&sharedStrings); err != nil && err != io.EOF { + log.Printf("xml decode error: %s", err) + } f.SharedStrings = &sharedStrings } + return f.SharedStrings } -- cgit v1.2.1 From 7358dca436f6ca5948a3f2865b14e828863d86a9 Mon Sep 17 00:00:00 2001 From: match-meng <54879059+match-meng@users.noreply.github.com> Date: Fri, 20 Dec 2019 22:22:56 +0800 Subject: Update comments for the xmlNewDecoder (#542) --- rows.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index fc7b55a..687828c 100644 --- a/rows.go +++ b/rows.go @@ -283,7 +283,10 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) { case "s": xlsxSI := 0 xlsxSI, _ = strconv.Atoi(xlsx.V) - return f.formattedValue(xlsx.S, d.SI[xlsxSI].String()), nil + if len(d.SI) > xlsxSI { + return f.formattedValue(xlsx.S, d.SI[xlsxSI].String()), nil + } + return f.formattedValue(xlsx.S, xlsx.V), nil case "str": return f.formattedValue(xlsx.S, xlsx.V), nil case "inlineStr": -- cgit v1.2.1 From 09485b3f9f0aefc58d51462aed65c2416205c591 Mon Sep 17 00:00:00 2001 From: xuri Date: Sun, 29 Dec 2019 16:02:31 +0800 Subject: Improve code coverage unit tests --- rows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 687828c..20b4379 100644 --- a/rows.go +++ b/rows.go @@ -1,4 +1,4 @@ -// Copyright 2016 - 2019 The excelize Authors. All rights reserved. Use of +// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of // this source code is governed by a BSD-style license that can be found in // the LICENSE file. // -- cgit v1.2.1 From 5f5ec76740704a8362e5a120b4a3582b409a5fdd Mon Sep 17 00:00:00 2001 From: xuri Date: Tue, 31 Dec 2019 01:01:16 +0800 Subject: Fix #551, handle empty rows in streaming reading --- rows.go | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 20b4379..d24b1a6 100644 --- a/rows.go +++ b/rows.go @@ -23,12 +23,20 @@ import ( // GetRows return all the rows in a sheet by given worksheet name (case // sensitive). For example: // -// rows, err := f.GetRows("Sheet1") -// for _, row := range rows { +// rows, err := f.Rows("Sheet1") +// if err != nil { +// println(err.Error()) +// return +// } +// for rows.Next() { +// row, err := rows.Columns() +// if err != nil { +// println(err.Error()) +// } // for _, colCell := range row { -// fmt.Print(colCell, "\t") +// print(colCell, "\t") // } -// fmt.Println() +// println() // } // func (f *File) GetRows(sheet string) ([][]string, error) { @@ -52,13 +60,13 @@ func (f *File) GetRows(sheet string) ([][]string, error) { // Rows defines an iterator to a sheet type Rows struct { - err error - f *File - rows []xlsxRow - sheet string - curRow int - totalRow int - decoder *xml.Decoder + err error + curRow, totalRow, stashRow int + sheet string + stashColumn []string + rows []xlsxRow + f *File + decoder *xml.Decoder } // Next will return true if find the next row element. @@ -80,6 +88,11 @@ func (rows *Rows) Columns() ([]string, error) { row, cellCol int columns []string ) + + if rows.stashRow >= rows.curRow { + return columns, err + } + d := rows.f.sharedStringsReader() for { token, _ := rows.decoder.Token() @@ -97,6 +110,8 @@ func (rows *Rows) Columns() ([]string, error) { return columns, err } if row > rows.curRow { + rows.stashRow = row - 1 + rows.stashColumn = columns return columns, err } } @@ -121,7 +136,6 @@ func (rows *Rows) Columns() ([]string, error) { if inElement == "row" { return columns, err } - default: } } return columns, err -- cgit v1.2.1 From 5ca7231ed408ac264f509ff52b5d28ff4fbda757 Mon Sep 17 00:00:00 2001 From: xuri Date: Fri, 3 Jan 2020 23:57:25 +0800 Subject: optimize code and comments: use println errors instead of panic --- rows.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index d24b1a6..40972ae 100644 --- a/rows.go +++ b/rows.go @@ -63,7 +63,6 @@ type Rows struct { err error curRow, totalRow, stashRow int sheet string - stashColumn []string rows []xlsxRow f *File decoder *xml.Decoder @@ -111,7 +110,6 @@ func (rows *Rows) Columns() ([]string, error) { } if row > rows.curRow { rows.stashRow = row - 1 - rows.stashColumn = columns return columns, err } } @@ -153,12 +151,19 @@ func (err ErrSheetNotExist) Error() string { // Rows return a rows iterator. For example: // // rows, err := f.Rows("Sheet1") +// if err != nil { +// println(err.Error()) +// return +// } // for rows.Next() { // row, err := rows.Columns() +// if err != nil { +// println(err.Error()) +// } // for _, colCell := range row { -// fmt.Print(colCell, "\t") +// print(colCell, "\t") // } -// fmt.Println() +// println() // } // func (f *File) Rows(sheet string) (*Rows, error) { -- cgit v1.2.1 From ad883caa0f77dfc016ae99bd5fbb606953eb99a0 Mon Sep 17 00:00:00 2001 From: xuri Date: Wed, 19 Feb 2020 00:08:10 +0800 Subject: Resolve #580, revert commit https://github.com/360EntSecGroup-Skylar/excelize/commit/5ca7231ed408ac264f509ff52b5d28ff4fbda757 --- rows.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 40972ae..23f3a2c 100644 --- a/rows.go +++ b/rows.go @@ -25,18 +25,18 @@ import ( // // rows, err := f.Rows("Sheet1") // if err != nil { -// println(err.Error()) +// fmt.Println(err) // return // } // for rows.Next() { // row, err := rows.Columns() // if err != nil { -// println(err.Error()) +// fmt.Println(err) // } // for _, colCell := range row { -// print(colCell, "\t") +// fmt.Print(colCell, "\t") // } -// println() +// fmt.Println() // } // func (f *File) GetRows(sheet string) ([][]string, error) { @@ -152,18 +152,18 @@ func (err ErrSheetNotExist) Error() string { // // rows, err := f.Rows("Sheet1") // if err != nil { -// println(err.Error()) +// fmt.Println(err) // return // } // for rows.Next() { // row, err := rows.Columns() // if err != nil { -// println(err.Error()) +// fmt.Println(err) // } // for _, colCell := range row { -// print(colCell, "\t") +// fmt.Print(colCell, "\t") // } -// println() +// fmt.Println() // } // func (f *File) Rows(sheet string) (*Rows, error) { -- cgit v1.2.1 From 8b20ea1685cdb010be8f95ffc047fa44e1a0e90a Mon Sep 17 00:00:00 2001 From: xuri Date: Tue, 25 Feb 2020 00:19:22 +0800 Subject: Fix #586, duplicate row with merged cells --- rows.go | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 23f3a2c..0684b18 100644 --- a/rows.go +++ b/rows.go @@ -519,6 +519,40 @@ func (f *File) DuplicateRowTo(sheet string, row, row2 int) error { } else { xlsx.SheetData.Row = append(xlsx.SheetData.Row, rowCopy) } + return f.duplicateMergeCells(sheet, xlsx, row, row2) +} + +// duplicateMergeCells merge cells in the destination row if there are single +// row merged cells in the copied row. +func (f *File) duplicateMergeCells(sheet string, xlsx *xlsxWorksheet, row, row2 int) error { + if xlsx.MergeCells == nil { + return nil + } + if row > row2 { + row++ + } + for _, rng := range xlsx.MergeCells.Cells { + coordinates, err := f.areaRefToCoordinates(rng.Ref) + if err != nil { + return err + } + if coordinates[1] < row2 && row2 < coordinates[3] { + return nil + } + } + for i := 0; i < len(xlsx.MergeCells.Cells); i++ { + areaData := xlsx.MergeCells.Cells[i] + coordinates, _ := f.areaRefToCoordinates(areaData.Ref) + x1, y1, x2, y2 := coordinates[0], coordinates[1], coordinates[2], coordinates[3] + if y1 == y2 && y1 == row { + from, _ := CoordinatesToCellName(x1, row2) + to, _ := CoordinatesToCellName(x2, row2) + if err := f.MergeCell(sheet, from, to); err != nil { + return err + } + i++ + } + } return nil } -- cgit v1.2.1 From 386a42dfa25f4ce5d5daf95e87ab65c528dbdd38 Mon Sep 17 00:00:00 2001 From: xxb-at-julichina <57735034+xxb-at-julichina@users.noreply.github.com> Date: Fri, 28 Feb 2020 15:53:04 +0800 Subject: Update rows.go --- rows.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 0684b18..e00a627 100644 --- a/rows.go +++ b/rows.go @@ -238,7 +238,8 @@ func (f *File) SetRowHeight(sheet string, row int, height float64) error { // name and row index. func (f *File) getRowHeight(sheet string, row int) int { xlsx, _ := f.workSheetReader(sheet) - for _, v := range xlsx.SheetData.Row { + for i := range xlsx.SheetData.Row { + v := &xlsx.SheetData.Row[i] if v.R == row+1 && v.Ht != 0 { return int(convertRowHeightToPixels(v.Ht)) } -- cgit v1.2.1 From 3f89c6e9799c9c82af1305f080416c53d19e64c1 Mon Sep 17 00:00:00 2001 From: xuri Date: Sun, 29 Mar 2020 18:44:24 +0800 Subject: remove ineffectual variable assignments and simplify code --- rows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index e00a627..76dd0f0 100644 --- a/rows.go +++ b/rows.go @@ -174,7 +174,7 @@ func (f *File) Rows(sheet string) (*Rows, error) { if f.Sheet[name] != nil { // flush data output, _ := xml.Marshal(f.Sheet[name]) - f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpaceBytes(output)) + f.saveFileList(name, replaceRelationshipsNameSpaceBytes(output)) } var ( err error -- cgit v1.2.1 From 59f6af21a378fdde21422a92b79a7b03bba313d4 Mon Sep 17 00:00:00 2001 From: foxmeder Date: Wed, 1 Apr 2020 15:38:37 +0800 Subject: fix reading wrong string from xml such as below 0 --- rows.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 76dd0f0..d56c81c 100644 --- a/rows.go +++ b/rows.go @@ -301,10 +301,12 @@ func (f *File) sharedStringsReader() *xlsxSST { func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) { switch xlsx.T { case "s": - xlsxSI := 0 - xlsxSI, _ = strconv.Atoi(xlsx.V) - if len(d.SI) > xlsxSI { - return f.formattedValue(xlsx.S, d.SI[xlsxSI].String()), nil + if xlsx.V != "" { + xlsxSI := 0 + xlsxSI, _ = strconv.Atoi(xlsx.V) + if len(d.SI) > xlsxSI { + return f.formattedValue(xlsx.S, d.SI[xlsxSI].String()), nil + } } return f.formattedValue(xlsx.S, xlsx.V), nil case "str": -- cgit v1.2.1 From 0f2a9053246c3ae45e6c7ba911a1fb135664abdf Mon Sep 17 00:00:00 2001 From: xuri Date: Thu, 2 Apr 2020 00:41:14 +0800 Subject: Performance improvements --- rows.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index d56c81c..8f000b3 100644 --- a/rows.go +++ b/rows.go @@ -424,14 +424,16 @@ func (f *File) RemoveRow(sheet string, row int) error { if row > len(xlsx.SheetData.Row) { return f.adjustHelper(sheet, rows, row, -1) } - for rowIdx := range xlsx.SheetData.Row { - if xlsx.SheetData.Row[rowIdx].R == row { - xlsx.SheetData.Row = append(xlsx.SheetData.Row[:rowIdx], - xlsx.SheetData.Row[rowIdx+1:]...)[:len(xlsx.SheetData.Row)-1] - return f.adjustHelper(sheet, rows, row, -1) + keep := 0 + for rowIdx := 0; rowIdx < len(xlsx.SheetData.Row); rowIdx++ { + v := &xlsx.SheetData.Row[rowIdx] + if v.R != row { + xlsx.SheetData.Row[keep] = *v + keep++ } } - return nil + xlsx.SheetData.Row = xlsx.SheetData.Row[:keep] + return f.adjustHelper(sheet, rows, row, -1) } // InsertRow provides a function to insert a new row after given Excel row -- cgit v1.2.1 From 2285d4dc718fb8b96c3b2291c63b39c57468b0b9 Mon Sep 17 00:00:00 2001 From: xuri Date: Fri, 24 Apr 2020 08:26:16 +0800 Subject: handle the cell without r attribute in a row element --- rows.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 8f000b3..6a67672 100644 --- a/rows.go +++ b/rows.go @@ -593,6 +593,22 @@ func checkRow(xlsx *xlsxWorksheet) error { if colCount == 0 { continue } + // check and fill the cell without r attribute in a row element + rCount := 0 + for idx, cell := range rowData.C { + rCount++ + if cell.R != "" { + lastR, _, err := CellNameToCoordinates(cell.R) + if err != nil { + return err + } + if lastR > rCount { + rCount = lastR + } + continue + } + rowData.C[idx].R, _ = CoordinatesToCellName(rCount, rowIdx+1) + } lastCol, _, err := CellNameToCoordinates(rowData.C[colCount-1].R) if err != nil { return err -- cgit v1.2.1 From 98221a332ff9c37c9b20c44e9efdbe4c22a5cf5c Mon Sep 17 00:00:00 2001 From: xuri Date: Sun, 17 May 2020 17:36:53 +0800 Subject: Merge pull request #410 --- rows.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'rows.go') diff --git a/rows.go b/rows.go index 6a67672..17216df 100644 --- a/rows.go +++ b/rows.go @@ -148,7 +148,8 @@ func (err ErrSheetNotExist) Error() string { return fmt.Sprintf("sheet %s is not exist", string(err.SheetName)) } -// Rows return a rows iterator. For example: +// Rows returns a rows iterator, used for streaming reading data for a +// worksheet with a large data. For example: // // rows, err := f.Rows("Sheet1") // if err != nil { -- cgit v1.2.1