diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | README.md | 20 | ||||
-rw-r--r-- | README_zh.md | 20 | ||||
-rw-r--r-- | cell.go | 16 | ||||
-rw-r--r-- | chart.go | 11 | ||||
-rw-r--r-- | col.go | 12 | ||||
-rw-r--r-- | comment.go | 32 | ||||
-rw-r--r-- | datavalidation.go | 233 | ||||
-rw-r--r-- | datavalidation_test.go | 57 | ||||
-rw-r--r-- | date.go | 22 | ||||
-rw-r--r-- | date_test.go | 54 | ||||
-rw-r--r-- | excelize.go | 12 | ||||
-rw-r--r-- | excelize.png | bin | 54188 -> 62974 bytes | |||
-rw-r--r-- | excelize_test.go | 71 | ||||
-rw-r--r-- | file.go | 31 | ||||
-rw-r--r-- | go.mod | 1 | ||||
-rw-r--r-- | hsl.go | 56 | ||||
-rw-r--r-- | lib.go | 53 | ||||
-rw-r--r-- | logo.png | bin | 4208 -> 7085 bytes | |||
-rw-r--r-- | picture.go | 89 | ||||
-rw-r--r-- | rows.go | 11 | ||||
-rw-r--r-- | shape.go | 9 | ||||
-rw-r--r-- | sheet.go | 239 | ||||
-rw-r--r-- | sheetpr.go | 29 | ||||
-rw-r--r-- | sheetpr_test.go | 8 | ||||
-rw-r--r-- | sheetview.go | 19 | ||||
-rw-r--r-- | sheetview_test.go | 18 | ||||
-rw-r--r-- | styles.go | 69 | ||||
-rw-r--r-- | table.go | 17 | ||||
-rw-r--r-- | templates.go | 9 | ||||
-rw-r--r--[-rwxr-xr-x] | test/Book1.xlsx | bin | 23099 -> 23153 bytes | |||
-rw-r--r-- | test/images/excel.gif | bin | 4952 -> 7221 bytes | |||
-rw-r--r-- | test/images/excel.jpg | bin | 3960 -> 5376 bytes | |||
-rw-r--r-- | test/images/excel.png | bin | 8991 -> 13233 bytes | |||
-rw-r--r-- | vmlDrawing.go | 9 | ||||
-rw-r--r-- | xmlChart.go | 13 | ||||
-rw-r--r-- | xmlComments.go | 17 | ||||
-rw-r--r-- | xmlContentTypes.go | 9 | ||||
-rw-r--r-- | xmlDecodeDrawing.go | 9 | ||||
-rw-r--r-- | xmlDrawing.go | 50 | ||||
-rw-r--r-- | xmlSharedStrings.go | 9 | ||||
-rw-r--r-- | xmlStyles.go | 9 | ||||
-rw-r--r-- | xmlTable.go | 9 | ||||
-rw-r--r-- | xmlTheme.go | 9 | ||||
-rw-r--r-- | xmlWorkbook.go | 11 | ||||
-rw-r--r-- | xmlWorksheet.go | 108 |
46 files changed, 1206 insertions, 275 deletions
diff --git a/.travis.yml b/.travis.yml index 26ca7b2..c2f0f90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ go: - 1.8.x - 1.9.x - 1.10.x + - 1.11.x os: - linux @@ -1,13 +1,15 @@ - +<p align="center"><img width="650" src="./excelize.png" alt="Excelize logo"></p> -# Excelize +<p align="center"> + <a href="https://travis-ci.org/360EntSecGroup-Skylar/excelize"><img src="https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master" alt="Build Status"></a> + <a href="https://codecov.io/gh/360EntSecGroup-Skylar/excelize"><img src="https://codecov.io/gh/360EntSecGroup-Skylar/excelize/branch/master/graph/badge.svg" alt="Code Coverage"></a> + <a href="https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize"><img src="https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize" alt="Go Report Card"></a> + <a href="https://godoc.org/github.com/360EntSecGroup-Skylar/excelize"><img src="https://godoc.org/github.com/360EntSecGroup-Skylar/excelize?status.svg" alt="GoDoc"></a> + <a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/license-bsd-orange.svg" alt="Licenses"></a> + <a href="https://www.paypal.me/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a> +</p> -[](https://travis-ci.org/360EntSecGroup-Skylar/excelize) -[](https://codecov.io/gh/360EntSecGroup-Skylar/excelize) -[](https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize) -[](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) -[](https://opensource.org/licenses/BSD-3-Clause) -[](https://www.paypal.me/xuri) +# Excelize ## Introduction @@ -88,7 +90,7 @@ func main() { With Excelize chart generation and management is as easy as a few lines of code. You can build charts based off data in your worksheet or generate charts without any data in your worksheet at all. - +<p align="center"><img width="650" src="./test/images/chart.png" alt="Excelize"></p> ```go package main diff --git a/README_zh.md b/README_zh.md index 49680d1..6be0f92 100644 --- a/README_zh.md +++ b/README_zh.md @@ -1,13 +1,15 @@ - +<p align="center"><img width="650" src="./excelize.png" alt="Excelize logo"></p> -# Excelize +<p align="center"> + <a href="https://travis-ci.org/360EntSecGroup-Skylar/excelize"><img src="https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master" alt="Build Status"></a> + <a href="https://codecov.io/gh/360EntSecGroup-Skylar/excelize"><img src="https://codecov.io/gh/360EntSecGroup-Skylar/excelize/branch/master/graph/badge.svg" alt="Code Coverage"></a> + <a href="https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize"><img src="https://goreportcard.com/badge/github.com/360EntSecGroup-Skylar/excelize" alt="Go Report Card"></a> + <a href="https://godoc.org/github.com/360EntSecGroup-Skylar/excelize"><img src="https://godoc.org/github.com/360EntSecGroup-Skylar/excelize?status.svg" alt="GoDoc"></a> + <a href="https://opensource.org/licenses/BSD-3-Clause"><img src="https://img.shields.io/badge/license-bsd-orange.svg" alt="Licenses"></a> + <a href="https://www.paypal.me/xuri"><img src="https://img.shields.io/badge/Donate-PayPal-green.svg" alt="Donate"></a> +</p> -[](https://travis-ci.org/360EntSecGroup-Skylar/excelize) -[](https://codecov.io/gh/360EntSecGroup-Skylar/excelize) -[](https://goreportcard.com/report/github.com/360EntSecGroup-Skylar/excelize) -[](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) -[](https://opensource.org/licenses/BSD-3-Clause) -[](https://www.paypal.me/xuri) +# Excelize ## 简介 @@ -88,7 +90,7 @@ func main() { 使用 Excelize 生成图表十分简单,仅需几行代码。您可以根据工作表中的已有数据构建图表,或向工作表中添加数据并创建图表。 - +<p align="center"><img width="650" src="./test/images/chart.png" alt="Excelize"></p> ```go package main @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -235,12 +244,13 @@ func (f *File) GetCellFormula(sheet, axis string) string { if xlsx.SheetData.Row[k].R == row { for i := range xlsx.SheetData.Row[k].C { if axis == xlsx.SheetData.Row[k].C[i].R { + if xlsx.SheetData.Row[k].C[i].F == nil { + continue + } if xlsx.SheetData.Row[k].C[i].F.T == STCellFormulaTypeShared { return getSharedForumula(xlsx, xlsx.SheetData.Row[k].C[i].F.Si) } - if xlsx.SheetData.Row[k].C[i].F != nil { - return xlsx.SheetData.Row[k].C[i].F.Content - } + return xlsx.SheetData.Row[k].C[i].F.Content } } } @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -1088,7 +1097,7 @@ func (f *File) drawingParser(drawingXML string, content *xlsxWsDr) int { _, ok := f.XLSX[drawingXML] if ok { // Append Model decodeWsDr := decodeWsDr{} - _ = xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr) content.R = decodeWsDr.R cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1 for _, v := range decodeWsDr.OneCellAnchor { @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -328,7 +337,8 @@ func (f *File) RemoveCol(sheet, column string) { f.adjustHelper(sheet, col, -1, -1) } -// Completion column element tags of XML in a sheet. +// completeCol provieds function to completion column element tags of XML in a +// sheet. func completeCol(xlsx *xlsxWorksheet, row, cell int) { buffer := bytes.Buffer{} for r := range xlsx.SheetData.Row { @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -21,8 +30,8 @@ func parseFormatCommentsSet(formatSet string) (*formatComment, error) { // GetComments retrieves all comments and returns a map of worksheet name to // the worksheet comments. -func (f *File) GetComments() (comments map[string]*xlsxComments) { - comments = map[string]*xlsxComments{} +func (f *File) GetComments() (comments map[string][]Comment) { + comments = map[string][]Comment{} for n := range f.sheetMap { commentID := f.GetSheetIndex(n) commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml" @@ -30,7 +39,20 @@ func (f *File) GetComments() (comments map[string]*xlsxComments) { if ok { d := xlsxComments{} xml.Unmarshal([]byte(c), &d) - comments[n] = &d + sheetComments := []Comment{} + for _, comment := range d.CommentList.Comment { + sheetComment := Comment{} + if comment.AuthorID < len(d.Authors) { + sheetComment.Author = d.Authors[comment.AuthorID].Author + } + sheetComment.Ref = comment.Ref + sheetComment.AuthorID = comment.AuthorID + for _, text := range comment.Text.R { + sheetComment.Text += text.T + } + sheetComments = append(sheetComments, sheetComment) + } + comments[n] = sheetComments } } return @@ -160,7 +182,7 @@ func (f *File) addDrawingVML(commentID int, drawingVML, cell string, lineCount, c, ok := f.XLSX[drawingVML] if ok { d := decodeVmlDrawing{} - _ = xml.Unmarshal([]byte(c), &d) + _ = xml.Unmarshal(namespaceStrictToTransitional(c), &d) for _, v := range d.Shape { s := xlsxShape{ ID: "_x0000_s1025", @@ -230,7 +252,7 @@ func (f *File) addComment(commentsXML, cell string, formatSet *formatComment) { c, ok := f.XLSX[commentsXML] if ok { d := xlsxComments{} - _ = xml.Unmarshal([]byte(c), &d) + _ = xml.Unmarshal(namespaceStrictToTransitional(c), &d) comments.CommentList.Comment = append(comments.CommentList.Comment, d.CommentList.Comment...) } comments.CommentList.Comment = append(comments.CommentList.Comment, cmt) diff --git a/datavalidation.go b/datavalidation.go new file mode 100644 index 0000000..5ebd61f --- /dev/null +++ b/datavalidation.go @@ -0,0 +1,233 @@ +// Copyright 2016 - 2018 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. +// +// 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. + +package excelize + +import ( + "fmt" + "strings" +) + +// DataValidationType defined the type of data validation. +type DataValidationType int + +// Data validation types. +const ( + _DataValidationType = iota + typeNone // inline use + DataValidationTypeCustom + DataValidationTypeDate + DataValidationTypeDecimal + typeList // inline use + DataValidationTypeTextLeng + DataValidationTypeTime + // DataValidationTypeWhole Integer + DataValidationTypeWhole +) + +const ( + // dataValidationFormulaStrLen 255 characters+ 2 quotes + dataValidationFormulaStrLen = 257 + // dataValidationFormulaStrLenErr + dataValidationFormulaStrLenErr = "data validation must be 0-255 characters" +) + +// DataValidationErrorStyle defined the style of data validation error alert. +type DataValidationErrorStyle int + +// Data validation error styles. +const ( + _ DataValidationErrorStyle = iota + DataValidationErrorStyleStop + DataValidationErrorStyleWarning + DataValidationErrorStyleInformation +) + +// Data validation error styles. +const ( + styleStop = "stop" + styleWarning = "warning" + styleInformation = "information" +) + +// DataValidationOperator operator enum. +type DataValidationOperator int + +// Data validation operators. +const ( + _DataValidationOperator = iota + DataValidationOperatorBetween + DataValidationOperatorEqual + DataValidationOperatorGreaterThan + DataValidationOperatorGreaterThanOrEqual + DataValidationOperatorLessThan + DataValidationOperatorLessThanOrEqual + DataValidationOperatorNotBetween + DataValidationOperatorNotEqual +) + +// NewDataValidation return data validation struct. +func NewDataValidation(allowBlank bool) *DataValidation { + return &DataValidation{ + AllowBlank: allowBlank, + ShowErrorMessage: false, + ShowInputMessage: false, + } +} + +// SetError set error notice. +func (dd *DataValidation) SetError(style DataValidationErrorStyle, title, msg string) { + dd.Error = &msg + dd.ErrorTitle = &title + strStyle := styleStop + switch style { + case DataValidationErrorStyleStop: + strStyle = styleStop + case DataValidationErrorStyleWarning: + strStyle = styleWarning + case DataValidationErrorStyleInformation: + strStyle = styleInformation + + } + dd.ShowErrorMessage = true + dd.ErrorStyle = &strStyle +} + +// SetInput set prompt notice. +func (dd *DataValidation) SetInput(title, msg string) { + dd.ShowInputMessage = true + dd.PromptTitle = &title + dd.Prompt = &msg +} + +// SetDropList data validation list. +func (dd *DataValidation) SetDropList(keys []string) error { + dd.Formula1 = "\"" + strings.Join(keys, ",") + "\"" + dd.Type = convDataValidationType(typeList) + return nil +} + +// SetRange provides function to set data validation range in drop list. +func (dd *DataValidation) SetRange(f1, f2 int, t DataValidationType, o DataValidationOperator) error { + formula1 := fmt.Sprintf("%d", f1) + formula2 := fmt.Sprintf("%d", f2) + if dataValidationFormulaStrLen < len(dd.Formula1) || dataValidationFormulaStrLen < len(dd.Formula2) { + return fmt.Errorf(dataValidationFormulaStrLenErr) + } + + dd.Formula1 = formula1 + dd.Formula2 = formula2 + dd.Type = convDataValidationType(t) + dd.Operator = convDataValidationOperatior(o) + return nil +} + +// SetSqrefDropList provides set data validation on a range with source +// reference range of the worksheet by given data validation object and +// worksheet name. The data validation object can be created by +// NewDataValidation function. For example, set data validation on +// Sheet1!A7:B8 with validation criteria source Sheet1!E1:E3 settings, create +// in-cell dropdown by allowing list source: +// +// dvRange := excelize.NewDataValidation(true) +// dvRange.Sqref = "A7:B8" +// dvRange.SetSqrefDropList("E1:E3", true) +// xlsx.AddDataValidation("Sheet1", dvRange) +// +func (dd *DataValidation) SetSqrefDropList(sqref string, isCurrentSheet bool) error { + if isCurrentSheet { + dd.Formula1 = sqref + dd.Type = convDataValidationType(typeList) + return nil + } + return fmt.Errorf("cross-sheet sqref cell are not supported") +} + +// SetSqref provides function to set data validation range in drop list. +func (dd *DataValidation) SetSqref(sqref string) { + if dd.Sqref == "" { + dd.Sqref = sqref + } else { + dd.Sqref = fmt.Sprintf("%s %s", dd.Sqref, sqref) + } +} + +// convDataValidationType get excel data validation type. +func convDataValidationType(t DataValidationType) string { + typeMap := map[DataValidationType]string{ + typeNone: "none", + DataValidationTypeCustom: "custom", + DataValidationTypeDate: "date", + DataValidationTypeDecimal: "decimal", + typeList: "list", + DataValidationTypeTextLeng: "textLength", + DataValidationTypeTime: "time", + DataValidationTypeWhole: "whole", + } + + return typeMap[t] + +} + +// convDataValidationOperatior get excel data validation operator. +func convDataValidationOperatior(o DataValidationOperator) string { + typeMap := map[DataValidationOperator]string{ + DataValidationOperatorBetween: "between", + DataValidationOperatorEqual: "equal", + DataValidationOperatorGreaterThan: "greaterThan", + DataValidationOperatorGreaterThanOrEqual: "greaterThanOrEqual", + DataValidationOperatorLessThan: "lessThan", + DataValidationOperatorLessThanOrEqual: "lessThanOrEqual", + DataValidationOperatorNotBetween: "notBetween", + DataValidationOperatorNotEqual: "notEqual", + } + + return typeMap[o] + +} + +// AddDataValidation provides set data validation on a range of the worksheet +// by given data validation object and worksheet name. The data validation +// object can be created by NewDataValidation function. +// +// Example 1, set data validation on Sheet1!A1:B2 with validation criteria +// settings, show error alert after invalid data is entered with "Stop" style +// and custom title "error body": +// +// dvRange := excelize.NewDataValidation(true) +// dvRange.Sqref = "A1:B2" +// dvRange.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorBetween) +// dvRange.SetError(excelize.DataValidationErrorStyleStop, "error title", "error body") +// xlsx.AddDataValidation("Sheet1", dvRange) +// +// Example 2, set data validation on Sheet1!A3:B4 with validation criteria +// settings, and show input message when cell is selected: +// +// dvRange = excelize.NewDataValidation(true) +// dvRange.Sqref = "A3:B4" +// dvRange.SetRange(10, 20, excelize.DataValidationTypeWhole, excelize.DataValidationOperatorGreaterThan) +// dvRange.SetInput("input title", "input body") +// xlsx.AddDataValidation("Sheet1", dvRange) +// +// Example 3, set data validation on Sheet1!A5:B6 with validation criteria +// settings, create in-cell dropdown by allowing list source: +// +// dvRange = excelize.NewDataValidation(true) +// dvRange.Sqref = "A5:B6" +// dvRange.SetDropList([]string{"1", "2", "3"}) +// xlsx.AddDataValidation("Sheet1", dvRange) +// +func (f *File) AddDataValidation(sheet string, dv *DataValidation) { + xlsx := f.workSheetReader(sheet) + if nil == xlsx.DataValidations { + xlsx.DataValidations = new(xlsxDataValidations) + } + xlsx.DataValidations.DataValidation = append(xlsx.DataValidations.DataValidation, dv) + xlsx.DataValidations.Count = len(xlsx.DataValidations.DataValidation) +} diff --git a/datavalidation_test.go b/datavalidation_test.go new file mode 100644 index 0000000..39dd229 --- /dev/null +++ b/datavalidation_test.go @@ -0,0 +1,57 @@ +// Copyright 2016 - 2018 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. +// +// 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. + +package excelize + +import "testing" + +func TestDataValidation(t *testing.T) { + xlsx := NewFile() + + dvRange := NewDataValidation(true) + dvRange.Sqref = "A1:B2" + dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorBetween) + dvRange.SetError(DataValidationErrorStyleStop, "error title", "error body") + dvRange.SetError(DataValidationErrorStyleWarning, "error title", "error body") + dvRange.SetError(DataValidationErrorStyleInformation, "error title", "error body") + xlsx.AddDataValidation("Sheet1", dvRange) + + dvRange = NewDataValidation(true) + dvRange.Sqref = "A3:B4" + dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan) + dvRange.SetInput("input title", "input body") + xlsx.AddDataValidation("Sheet1", dvRange) + + dvRange = NewDataValidation(true) + dvRange.Sqref = "A5:B6" + dvRange.SetDropList([]string{"1", "2", "3"}) + xlsx.AddDataValidation("Sheet1", dvRange) + + xlsx.SetCellStr("Sheet1", "E1", "E1") + xlsx.SetCellStr("Sheet1", "E2", "E2") + xlsx.SetCellStr("Sheet1", "E3", "E3") + dvRange = NewDataValidation(true) + dvRange.SetSqref("A7:B8") + dvRange.SetSqref("A7:B8") + dvRange.SetSqrefDropList("$E$1:$E$3", true) + err := dvRange.SetSqrefDropList("$E$1:$E$3", false) + t.Log(err) + xlsx.AddDataValidation("Sheet1", dvRange) + + dvRange = NewDataValidation(true) + dvRange.SetDropList(make([]string, 258)) + err = dvRange.SetRange(10, 20, DataValidationTypeWhole, DataValidationOperatorGreaterThan) + t.Log(err) + + // Test write file to given path. + err = xlsx.SaveAs("./test/Book_data_validation.xlsx") + if err != nil { + t.Error(err) + } +} @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -81,12 +90,13 @@ func julianDateToGregorianTime(part1, part2 float64) time.Time { return time.Date(year, time.Month(month), day, hours, minutes, seconds, nanoseconds, time.UTC) } -// By this point generations of programmers have repeated the algorithm sent -// to the editor of "Communications of the ACM" in 1968 (published in CACM, -// volume 11, number 10, October 1968, p.657). None of those programmers seems -// to have found it necessary to explain the constants or variable names set -// out by Henry F. Fliegel and Thomas C. Van Flandern. Maybe one day I'll buy -// that jounal and expand an explanation here - that day is not today. +// doTheFliegelAndVanFlandernAlgorithm; By this point generations of +// programmers have repeated the algorithm sent to the editor of +// "Communications of the ACM" in 1968 (published in CACM, volume 11, number +// 10, October 1968, p.657). None of those programmers seems to have found it +// necessary to explain the constants or variable names set out by Henry F. +// Fliegel and Thomas C. Van Flandern. Maybe one day I'll buy that jounal and +// expand an explanation here - that day is not today. func doTheFliegelAndVanFlandernAlgorithm(jd int) (day, month, year int) { l := jd + 68569 n := (4 * l) / 146097 diff --git a/date_test.go b/date_test.go index bf071e0..06421b8 100644 --- a/date_test.go +++ b/date_test.go @@ -1,42 +1,42 @@ package excelize import ( - "testing" - "time" + "testing" + "time" ) type dateTest struct { - ExcelValue float64 - GoValue time.Time + ExcelValue float64 + GoValue time.Time } func TestTimeToExcelTime(t *testing.T) { - trueExpectedInputList := []dateTest { - {0.0, time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)}, - {25569.0, time.Unix(0, 0)}, - {43269.0, time.Date(2018, 6, 18, 0, 0, 0, 0, time.UTC)}, - {401769.0, time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)}, - } + trueExpectedInputList := []dateTest{ + {0.0, time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)}, + {25569.0, time.Unix(0, 0)}, + {43269.0, time.Date(2018, 6, 18, 0, 0, 0, 0, time.UTC)}, + {401769.0, time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)}, + } - for _, test := range trueExpectedInputList { - if test.ExcelValue != timeToExcelTime(test.GoValue) { - t.Fatalf("Expected %v from %v = true, got %v\n", test.ExcelValue, test.GoValue, timeToExcelTime(test.GoValue)) - } - } + for _, test := range trueExpectedInputList { + if test.ExcelValue != timeToExcelTime(test.GoValue) { + t.Fatalf("Expected %v from %v = true, got %v\n", test.ExcelValue, test.GoValue, timeToExcelTime(test.GoValue)) + } + } } func TestTimeFromExcelTime(t *testing.T) { - trueExpectedInputList := []dateTest { - {0.0, time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)}, - {60.0, time.Date(1900, 2, 28, 0, 0, 0, 0, time.UTC)}, - {61.0, time.Date(1900, 3, 1, 0, 0, 0, 0, time.UTC)}, - {41275.0, time.Date(2013, 1, 1, 0, 0, 0, 0, time.UTC)}, - {401769.0, time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)}, - } + trueExpectedInputList := []dateTest{ + {0.0, time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)}, + {60.0, time.Date(1900, 2, 28, 0, 0, 0, 0, time.UTC)}, + {61.0, time.Date(1900, 3, 1, 0, 0, 0, 0, time.UTC)}, + {41275.0, time.Date(2013, 1, 1, 0, 0, 0, 0, time.UTC)}, + {401769.0, time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)}, + } - for _, test := range trueExpectedInputList { - if test.GoValue != timeFromExcelTime(test.ExcelValue, false) { - t.Fatalf("Expected %v from %v = true, got %v\n", test.GoValue, test.ExcelValue, timeFromExcelTime(test.ExcelValue, false)) - } - } + for _, test := range trueExpectedInputList { + if test.GoValue != timeFromExcelTime(test.ExcelValue, false) { + t.Fatalf("Expected %v from %v = true, got %v\n", test.GoValue, test.ExcelValue, timeFromExcelTime(test.ExcelValue, false)) + } + } } diff --git a/excelize.go b/excelize.go index 013f357..4b4aa32 100644 --- a/excelize.go +++ b/excelize.go @@ -1,3 +1,13 @@ +// Copyright 2016 - 2018 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. + +// 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. +// +// See https://xuri.me/excelize for more information about this package. package excelize import ( @@ -90,7 +100,7 @@ func (f *File) workSheetReader(sheet string) *xlsxWorksheet { } if f.Sheet[name] == nil { var xlsx xlsxWorksheet - _ = xml.Unmarshal(f.readXML(name), &xlsx) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(name)), &xlsx) if f.checked == nil { f.checked = make(map[string]bool) } diff --git a/excelize.png b/excelize.png Binary files differindex 9f220b5..5d0766b 100644 --- a/excelize.png +++ b/excelize.png diff --git a/excelize_test.go b/excelize_test.go index f55ac01..6eb3692 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -21,9 +21,9 @@ func TestOpenFile(t *testing.T) { t.Error(err) } // Test get all the rows in a not exists worksheet. - rows := xlsx.GetRows("Sheet4") + xlsx.GetRows("Sheet4") // Test get all the rows in a worksheet. - rows = xlsx.GetRows("Sheet2") + rows := xlsx.GetRows("Sheet2") for _, row := range rows { for _, cell := range row { t.Log(cell, "\t") @@ -128,7 +128,7 @@ func TestOpenFile(t *testing.T) { } err = xlsx.Save() if err != nil { - t.Log(err) + t.Error(err) } // Test write file to not exist directory. err = xlsx.SaveAs("") @@ -162,6 +162,24 @@ func TestAddPicture(t *testing.T) { if err != nil { t.Log(err) } + err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", "jpg", make([]byte, 1)) + if err != nil { + t.Log(err) + } + // Test add picture to worksheet with invalid file data. + err = xlsx.AddPictureFromBytes("Sheet1", "G21", "", "Excel Logo", ".jpg", make([]byte, 1)) + if err != nil { + t.Log(err) + } + file, err := ioutil.ReadFile("./test/images/excel.jpg") + if err != nil { + t.Error(err) + } + // Test add picture to worksheet from bytes. + err = xlsx.AddPictureFromBytes("Sheet1", "Q1", "", "Excel Logo", ".jpg", file) + if err != nil { + t.Log(err) + } // Test write file to given path. err = xlsx.SaveAs("./test/Book2.xlsx") if err != nil { @@ -211,9 +229,14 @@ func TestNewFile(t *testing.T) { if err != nil { t.Error(err) } - // Test add picture to worksheet with invalid formatset + // Test add picture to worksheet without formatset. err = xlsx.AddPicture("Sheet1", "C2", "./test/images/excel.png", "") if err != nil { + t.Error(err) + } + // Test add picture to worksheet with invalid formatset. + err = xlsx.AddPicture("Sheet1", "C2", "./test/images/excel.png", `{`) + if err != nil { t.Log(err) } err = xlsx.SaveAs("./test/Book3.xlsx") @@ -548,7 +571,7 @@ func TestSetCellStyleCurrencyNumberFormat(t *testing.T) { xlsx.SetCellValue("Sheet1", "A1", 42920.5) xlsx.SetCellValue("Sheet1", "A2", 42920.5) - style, err = xlsx.NewStyle(`{"number_format": 26, "lang": "zh-tw"}`) + _, err = xlsx.NewStyle(`{"number_format": 26, "lang": "zh-tw"}`) if err != nil { t.Log(err) } @@ -1225,6 +1248,44 @@ func TestHSL(t *testing.T) { t.Log(RGBToHSL(250, 50, 100)) } +func TestSearchSheet(t *testing.T) { + xlsx, err := OpenFile("./test/SharedStrings.xlsx") + if err != nil { + t.Error(err) + return + } + // Test search in a not exists worksheet. + t.Log(xlsx.SearchSheet("Sheet4", "")) + // Test search a not exists value. + t.Log(xlsx.SearchSheet("Sheet1", "X")) + t.Log(xlsx.SearchSheet("Sheet1", "A")) +} + +func TestProtectSheet(t *testing.T) { + xlsx := NewFile() + xlsx.ProtectSheet("Sheet1", nil) + xlsx.ProtectSheet("Sheet1", &FormatSheetProtection{ + Password: "password", + EditScenarios: false, + }) + err := xlsx.SaveAs("./test/Book_protect_sheet.xlsx") + if err != nil { + t.Error(err) + } +} + +func TestUnprotectSheet(t *testing.T) { + xlsx, err := OpenFile("./test/Book1.xlsx") + if err != nil { + t.Error(err) + } + xlsx.UnprotectSheet("Sheet1") + err = xlsx.Save() + if err != nil { + t.Error(err) + } +} + func trimSliceSpace(s []string) []string { for { if len(s) > 0 && s[len(s)-1] == "" { @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -43,7 +52,7 @@ func NewFile() *File { // Save provides a function to override the xlsx file with origin path. func (f *File) Save() error { if f.Path == "" { - return fmt.Errorf("No path defined for file, consider File.WriteTo or File.Write") + return fmt.Errorf("no path defined for file, consider File.WriteTo or File.Write") } return f.SaveAs(f.Path) } @@ -67,6 +76,15 @@ func (f *File) Write(w io.Writer) error { // WriteTo implements io.WriterTo to write the file. func (f *File) WriteTo(w io.Writer) (int64, error) { + buf, err := f.WriteToBuffer() + if err != nil { + return 0, err + } + return buf.WriteTo(w) +} + +// WriteToBuffer provides a function to get bytes.Buffer from the saved file. +func (f *File) WriteToBuffer() (*bytes.Buffer, error) { buf := new(bytes.Buffer) zw := zip.NewWriter(buf) f.contentTypesWriter() @@ -77,17 +95,12 @@ func (f *File) WriteTo(w io.Writer) (int64, error) { for path, content := range f.XLSX { fi, err := zw.Create(path) if err != nil { - return 0, err + return buf, err } _, err = fi.Write(content) if err != nil { - return 0, err + return buf, err } } - err := zw.Close() - if err != nil { - return 0, err - } - - return buf.WriteTo(w) + return buf, zw.Close() } @@ -0,0 +1 @@ +module github.com/360EntSecGroup-Skylar/excelize @@ -1,32 +1,30 @@ -/* -Copyright (c) 2012 Rodrigo Moraes. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ +// Copyright (c) 2012 Rodrigo Moraes. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package excelize @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -6,6 +15,8 @@ import ( "io" "log" "math" + "strconv" + "strings" "unicode" ) @@ -174,3 +185,45 @@ func parseFormatSet(formatSet string) []byte { } return []byte("{}") } + +// namespaceStrictToTransitional provides a method to convert Strict and +// Transitional namespaces. +func namespaceStrictToTransitional(content []byte) []byte { + var namespaceTranslationDic = map[string]string{ + StrictSourceRelationship: SourceRelationship, + StrictSourceRelationshipChart: SourceRelationshipChart, + StrictSourceRelationshipComments: SourceRelationshipComments, + StrictSourceRelationshipImage: SourceRelationshipImage, + StrictNameSpaceSpreadSheet: NameSpaceSpreadSheet, + } + for s, n := range namespaceTranslationDic { + content = bytes.Replace(content, []byte(s), []byte(n), -1) + } + return content +} + +// genSheetPasswd provides a method to generate password for worksheet +// protection by given plaintext. When an Excel sheet is being protected with +// a password, a 16-bit (two byte) long hash is generated. To verify a +// password, it is compared to the hash. Obviously, if the input data volume +// is great, numerous passwords will match the same hash. Here is the +// algorithm to create the hash value: +// +// take the ASCII values of all characters shift left the first character 1 bit, the second 2 bits and so on (use only the lower 15 bits and rotate all higher bits, the highest bit of the 16-bit value is always 0 [signed short]) +// XOR all these values +// XOR the count of characters +// XOR the constant 0xCE4B +func genSheetPasswd(plaintext string) string { + var password int64 = 0x0000 + var charPos uint = 1 + for _, v := range plaintext { + value := int64(v) << charPos + charPos++ + rotatedBits := value >> 15 // rotated bits beyond bit 15 + value &= 0x7fff // first 15 bits + password ^= (value | rotatedBits) + } + password ^= int64(len(plaintext)) + password ^= 0xCE4B + return strings.ToUpper(strconv.FormatInt(password, 16)) +} Binary files differ@@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -78,27 +87,66 @@ func parseFormatPictureSet(formatSet string) (*formatPicture, error) { // positioning is move and size with cells. func (f *File) AddPicture(sheet, cell, picture, format string) error { var err error - var drawingHyperlinkRID int - var hyperlinkType string // Check picture exists first. if _, err = os.Stat(picture); os.IsNotExist(err) { return err } ext, ok := supportImageTypes[path.Ext(picture)] if !ok { - return errors.New("Unsupported image extension") + return errors.New("unsupported image extension") } - readFile, err := os.Open(picture) - if err!=nil{ - return err + file, _ := ioutil.ReadFile(picture) + _, name := filepath.Split(picture) + return f.AddPictureFromBytes(sheet, cell, format, name, ext, file) +} + +// AddPictureFromBytes provides the method to add picture in a sheet by given +// picture format set (such as offset, scale, aspect ratio setting and print +// settings), file base name, extension name and file bytes. For example: +// +// package main +// +// import ( +// "fmt" +// _ "image/jpeg" +// "io/ioutil" +// +// "github.com/360EntSecGroup-Skylar/excelize" +// ) +// +// func main() { +// xlsx := excelize.NewFile() +// +// file, err := ioutil.ReadFile("./image1.jpg") +// if err != nil { +// fmt.Println(err) +// } +// err = xlsx.AddPictureFromBytes("Sheet1", "A2", "", "Excel Logo", ".jpg", file) +// if err != nil { +// fmt.Println(err) +// } +// err = xlsx.SaveAs("./Book1.xlsx") +// if err != nil { +// fmt.Println(err) +// } +// } +// +func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string, file []byte) error { + var err error + var drawingHyperlinkRID int + var hyperlinkType string + ext, ok := supportImageTypes[extension] + if !ok { + return errors.New("unsupported image extension") } - defer readFile.Close() - image, _, _ := image.DecodeConfig(readFile) - _, file := filepath.Split(picture) formatSet, err := parseFormatPictureSet(format) if err != nil { return err } + image, _, err := image.DecodeConfig(bytes.NewReader(file)) + if err != nil { + return err + } // Read sheet data. xlsx := f.workSheetReader(sheet) // Add first picture for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder. @@ -114,8 +162,8 @@ func (f *File) AddPicture(sheet, cell, picture, format string) error { } drawingHyperlinkRID = f.addDrawingRelationships(drawingID, SourceRelationshipHyperLink, formatSet.Hyperlink, hyperlinkType) } - f.addDrawingPicture(sheet, drawingXML, cell, file, image.Width, image.Height, drawingRID, drawingHyperlinkRID, formatSet) - f.addMedia(picture, ext) + f.addDrawingPicture(sheet, drawingXML, cell, name, image.Width, image.Height, drawingRID, drawingHyperlinkRID, formatSet) + f.addMedia(file, ext) f.addContentTypePart(drawingID, "drawings") return err } @@ -137,7 +185,7 @@ func (f *File) addSheetRelationships(sheet, relType, target, targetMode string) _, ok = f.XLSX[rels] if ok { ID.Reset() - _ = xml.Unmarshal([]byte(f.readXML(rels)), &sheetRels) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &sheetRels) rID = len(sheetRels.Relationships) + 1 ID.WriteString("rId") ID.WriteString(strconv.Itoa(rID)) @@ -163,7 +211,7 @@ func (f *File) deleteSheetRelationships(sheet, rID string) { } var rels = "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels" var sheetRels xlsxWorkbookRels - _ = xml.Unmarshal([]byte(f.readXML(rels)), &sheetRels) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &sheetRels) for k, v := range sheetRels.Relationships { if v.ID == rID { sheetRels.Relationships = append(sheetRels.Relationships[:k], sheetRels.Relationships[k+1:]...) @@ -280,7 +328,7 @@ func (f *File) addDrawingRelationships(index int, relType, target, targetMode st _, ok := f.XLSX[rels] if ok { ID.Reset() - _ = xml.Unmarshal([]byte(f.readXML(rels)), &drawingRels) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &drawingRels) rID = len(drawingRels.Relationships) + 1 ID.WriteString("rId") ID.WriteString(strconv.Itoa(rID)) @@ -309,12 +357,11 @@ func (f *File) countMedia() int { } // addMedia provides a function to add picture into folder xl/media/image by -// given file name and extension name. -func (f *File) addMedia(file, ext string) { +// given file and extension name. +func (f *File) addMedia(file []byte, ext string) { count := f.countMedia() - dat, _ := ioutil.ReadFile(file) media := "xl/media/image" + strconv.Itoa(count+1) + ext - f.XLSX[media] = dat + f.XLSX[media] = file } // setContentTypePartImageExtensions provides a function to set the content @@ -401,7 +448,7 @@ func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string { } var rels = "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels" var sheetRels xlsxWorkbookRels - _ = xml.Unmarshal([]byte(f.readXML(rels)), &sheetRels) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &sheetRels) for _, v := range sheetRels.Relationships { if v.ID == rID { return v.Target @@ -441,7 +488,7 @@ func (f *File) GetPicture(sheet, cell string) (string, []byte) { return "", nil } decodeWsDr := decodeWsDr{} - _ = xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(drawingXML)), &decodeWsDr) cell = strings.ToUpper(cell) fromCol := string(strings.Map(letterOnlyMapF, cell)) @@ -476,7 +523,7 @@ func (f *File) getDrawingRelationships(rels, rID string) *xlsxWorkbookRelation { return nil } var drawingRels xlsxWorkbookRels - _ = xml.Unmarshal([]byte(f.readXML(rels)), &drawingRels) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rels)), &drawingRels) for _, v := range drawingRels.Relationships { if v.ID == rID { return &v @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -240,7 +249,7 @@ func (f *File) sharedStringsReader() *xlsxSST { if len(ss) == 0 { ss = f.readXML("xl/SharedStrings.xml") } - _ = xml.Unmarshal([]byte(ss), &sharedStrings) + _ = xml.Unmarshal(namespaceStrictToTransitional(ss), &sharedStrings) f.SharedStrings = &sharedStrings } return f.SharedStrings @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -5,6 +14,8 @@ import ( "encoding/json" "encoding/xml" "errors" + "fmt" + "io/ioutil" "os" "path" "strconv" @@ -14,26 +25,35 @@ import ( "github.com/mohae/deepcopy" ) -// NewSheet provides a function to create a new sheet by given worksheet name, -// when creating a new XLSX file, the default sheet will be create, when you -// create a new file. +// NewSheet provides function to create a new sheet by given worksheet name. +// When creating a new XLSX file, the default sheet will be created. Returns +// the number of sheets in the workbook (file) after appending the new sheet. func (f *File) NewSheet(name string) int { // Check if the worksheet already exists if f.GetSheetIndex(name) != 0 { return f.SheetCount } + f.DeleteSheet(name) f.SheetCount++ + wb := f.workbookReader() + sheetID := 0 + for _, v := range wb.Sheets.Sheet { + if v.SheetID > sheetID { + sheetID = v.SheetID + } + } + sheetID++ // Update docProps/app.xml f.setAppXML() // Update [Content_Types].xml - f.setContentTypes(f.SheetCount) + f.setContentTypes(sheetID) // Create new sheet /xl/worksheets/sheet%d.xml - f.setSheet(f.SheetCount, name) + f.setSheet(sheetID, name) // Update xl/_rels/workbook.xml.rels - rID := f.addXlsxWorkbookRels(f.SheetCount) + rID := f.addXlsxWorkbookRels(sheetID) // Update xl/workbook.xml - f.setWorkbook(name, rID) - return f.SheetCount + f.setWorkbook(name, sheetID, rID) + return sheetID } // contentTypesReader provides a function to get the pointer to the @@ -41,7 +61,7 @@ func (f *File) NewSheet(name string) int { func (f *File) contentTypesReader() *xlsxTypes { if f.ContentTypes == nil { var content xlsxTypes - _ = xml.Unmarshal([]byte(f.readXML("[Content_Types].xml")), &content) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("[Content_Types].xml")), &content) f.ContentTypes = &content } return f.ContentTypes @@ -61,7 +81,7 @@ func (f *File) contentTypesWriter() { func (f *File) workbookReader() *xlsxWorkbook { if f.WorkBook == nil { var content xlsxWorkbook - _ = xml.Unmarshal([]byte(f.readXML("xl/workbook.xml")), &content) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/workbook.xml")), &content) f.WorkBook = &content } return f.WorkBook @@ -107,7 +127,8 @@ func trimCell(column []xlsxC) []xlsxC { return col[0:i] } -// Read and update property of contents type of XLSX. +// setContentTypes provides a function to read and update property of contents +// type of XLSX. func (f *File) setContentTypes(index int) { content := f.contentTypesReader() content.Overrides = append(content.Overrides, xlsxOverride{ @@ -116,7 +137,7 @@ func (f *File) setContentTypes(index int) { }) } -// Update sheet property by given index. +// setSheet provides a function to update sheet property by given index. func (f *File) setSheet(index int, name string) { var xlsx xlsxWorksheet xlsx.Dimension.Ref = "A1" @@ -130,19 +151,11 @@ func (f *File) setSheet(index int, name string) { // setWorkbook update workbook property of XLSX. Maximum 31 characters are // allowed in sheet title. -func (f *File) setWorkbook(name string, rid int) { +func (f *File) setWorkbook(name string, sheetID, rid int) { content := f.workbookReader() - rID := 0 - for _, v := range content.Sheets.Sheet { - t, _ := strconv.Atoi(v.SheetID) - if t > rID { - rID = t - } - } - rID++ content.Sheets.Sheet = append(content.Sheets.Sheet, xlsxSheet{ Name: trimSheetName(name), - SheetID: strconv.Itoa(rID), + SheetID: sheetID, ID: "rId" + strconv.Itoa(rid), }) } @@ -152,7 +165,7 @@ func (f *File) setWorkbook(name string, rid int) { func (f *File) workbookRelsReader() *xlsxWorkbookRels { if f.WorkBookRels == nil { var content xlsxWorkbookRels - _ = xml.Unmarshal([]byte(f.readXML("xl/_rels/workbook.xml.rels")), &content) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/_rels/workbook.xml.rels")), &content) f.WorkBookRels = &content } return f.WorkBookRels @@ -198,39 +211,44 @@ func (f *File) setAppXML() { f.saveFileList("docProps/app.xml", []byte(templateDocpropsApp)) } -// Some tools that read XLSX files have very strict requirements about the -// structure of the input XML. In particular both Numbers on the Mac and SAS -// dislike inline XML namespace declarations, or namespace prefixes that don't -// match the ones that Excel itself uses. This is a problem because the Go XML -// library doesn't multiple namespace declarations in a single element of a -// document. This function is a horrible hack to fix that after the XML -// marshalling is completed. +// replaceRelationshipsNameSpaceBytes; Some tools that read XLSX files have +// very strict requirements about the structure of the input XML. In +// particular both Numbers on the Mac and SAS dislike inline XML namespace +// declarations, or namespace prefixes that don't match the ones that Excel +// itself uses. This is a problem because the Go XML library doesn't multiple +// namespace declarations in a single element of a document. This function is +// a horrible hack to fix that after the XML marshalling is completed. func replaceRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte { oldXmlns := []byte(`<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`) newXmlns := []byte(`<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x15" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main">`) return bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1) } -// SetActiveSheet provides a function to set default active worksheet of XLSX by -// given index. Note that active index is different with the index that got by -// function GetSheetMap, and it should be greater than 0 and less than total +// SetActiveSheet provides function to set default active worksheet of XLSX by +// given index. Note that active index is different from the index returned by +// function GetSheetMap(). It should be greater than 0 and less than total // worksheet numbers. func (f *File) SetActiveSheet(index int) { if index < 1 { index = 1 } - index-- - content := f.workbookReader() - if len(content.BookViews.WorkBookView) > 0 { - content.BookViews.WorkBookView[0].ActiveTab = index - } else { - content.BookViews.WorkBookView = append(content.BookViews.WorkBookView, xlsxWorkBookView{ - ActiveTab: index, - }) + wb := f.workbookReader() + for activeTab, sheet := range wb.Sheets.Sheet { + if sheet.SheetID == index { + if len(wb.BookViews.WorkBookView) > 0 { + wb.BookViews.WorkBookView[0].ActiveTab = activeTab + } else { + wb.BookViews.WorkBookView = append(wb.BookViews.WorkBookView, xlsxWorkBookView{ + ActiveTab: activeTab, + }) + } + } } - index++ for idx, name := range f.GetSheetMap() { xlsx := f.workSheetReader(name) + if len(xlsx.SheetViews.SheetView) > 0 { + xlsx.SheetViews.SheetView[0].TabSelected = false + } if index == idx { if len(xlsx.SheetViews.SheetView) > 0 { xlsx.SheetViews.SheetView[0].TabSelected = true @@ -239,32 +257,20 @@ func (f *File) SetActiveSheet(index int) { TabSelected: true, }) } - } else { - if len(xlsx.SheetViews.SheetView) > 0 { - xlsx.SheetViews.SheetView[0].TabSelected = false - } } } } -// GetActiveSheetIndex provides a function to get active sheet of XLSX. If not -// found the active sheet will be return integer 0. +// GetActiveSheetIndex provides a function to get active sheet index of the +// XLSX. If not found the active sheet will be return integer 0. func (f *File) GetActiveSheetIndex() int { - buffer := bytes.Buffer{} - content := f.workbookReader() - for _, v := range content.Sheets.Sheet { - xlsx := xlsxWorksheet{} - buffer.WriteString("xl/worksheets/sheet") - buffer.WriteString(strings.TrimPrefix(v.ID, "rId")) - buffer.WriteString(".xml") - _ = xml.Unmarshal([]byte(f.readXML(buffer.String())), &xlsx) + for idx, name := range f.GetSheetMap() { + xlsx := f.workSheetReader(name) for _, sheetView := range xlsx.SheetViews.SheetView { if sheetView.TabSelected { - ID, _ := strconv.Atoi(strings.TrimPrefix(v.ID, "rId")) - return ID + return idx } } - buffer.Reset() } return 0 } @@ -342,8 +348,9 @@ func (f *File) GetSheetMap() map[int]string { sheetMap := map[int]string{} for _, v := range content.Sheets.Sheet { for _, rel := range rels.Relationships { - if rel.ID == v.ID { - rID, _ := strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(rel.Target, "worksheets/sheet"), ".xml")) + relStr := strings.SplitN(rel.Target, "worksheets/sheet", 2) + if rel.ID == v.ID && len(relStr) == 2 { + rID, _ := strconv.Atoi(strings.TrimSuffix(relStr[1], ".xml")) sheetMap[rID] = v.Name } } @@ -362,7 +369,7 @@ func (f *File) getSheetMap() map[string]string { } // SetSheetBackground provides a function to set background picture by given -// worksheet name. +// worksheet name and file path. func (f *File) SetSheetBackground(sheet, picture string) error { var err error // Check picture exists first. @@ -371,12 +378,13 @@ func (f *File) SetSheetBackground(sheet, picture string) error { } ext, ok := supportImageTypes[path.Ext(picture)] if !ok { - return errors.New("Unsupported image extension") + return errors.New("unsupported image extension") } pictureID := f.countMedia() + 1 rID := f.addSheetRelationships(sheet, SourceRelationshipImage, "../media/image"+strconv.Itoa(pictureID)+ext, "") f.addSheetPicture(sheet, rID) - f.addMedia(picture, ext) + file, _ := ioutil.ReadFile(picture) + f.addMedia(file, ext) f.setContentTypePartImageExtensions() return err } @@ -391,8 +399,8 @@ func (f *File) DeleteSheet(name string) { for k, v := range content.Sheets.Sheet { if v.Name == trimSheetName(name) && len(content.Sheets.Sheet) > 1 { content.Sheets.Sheet = append(content.Sheets.Sheet[:k], content.Sheets.Sheet[k+1:]...) - sheet := "xl/worksheets/sheet" + strings.TrimPrefix(v.ID, "rId") + ".xml" - rels := "xl/worksheets/_rels/sheet" + strings.TrimPrefix(v.ID, "rId") + ".xml.rels" + sheet := "xl/worksheets/sheet" + strconv.Itoa(v.SheetID) + ".xml" + rels := "xl/worksheets/_rels/sheet" + strconv.Itoa(v.SheetID) + ".xml.rels" target := f.deleteSheetFromWorkbookRels(v.ID) f.deleteSheetFromContentTypes(target) delete(f.sheetMap, name) @@ -441,7 +449,7 @@ func (f *File) deleteSheetFromContentTypes(target string) { // func (f *File) CopySheet(from, to int) error { if from < 1 || to < 1 || from == to || f.GetSheetName(from) == "" || f.GetSheetName(to) == "" { - return errors.New("Invalid worksheet index") + return errors.New("invalid worksheet index") } f.copySheet(from, to) return nil @@ -649,6 +657,103 @@ func (f *File) GetSheetVisible(name string) bool { return visible } +// SearchSheet provides a function to get coordinates by given worksheet name +// and cell value. This function only supports exact match of strings and +// numbers, doesn't support the calculated result, formatted numbers and +// conditional lookup currently. If it is a merged cell, it will return the +// coordinates of the upper left corner of the merged area. For example, +// search the coordinates of the value of "100" on Sheet1: +// +// xlsx.SearchSheet("Sheet1", "100") +// +func (f *File) SearchSheet(sheet, value string) []string { + xlsx := f.workSheetReader(sheet) + result := []string{} + name, ok := f.sheetMap[trimSheetName(sheet)] + if !ok { + return result + } + 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 + var r xlsxRow + 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" { + r = xlsxRow{} + _ = decoder.DecodeElement(&r, &startElement) + for _, colCell := range r.C { + val, _ := colCell.getValueFrom(f, d) + if val != value { + continue + } + result = append(result, fmt.Sprintf("%s%d", strings.Map(letterOnlyMapF, colCell.R), r.R)) + } + } + default: + } + } + return result +} + +// ProtectSheet provides a function to prevent other users from accidentally +// or deliberately changing, moving, or deleting data in a worksheet. For +// example, protect Sheet1 with protection settings: +// +// xlsx.ProtectSheet("Sheet1", &excelize.FormatSheetProtection{ +// Password: "password", +// EditScenarios: false, +// }) +// +func (f *File) ProtectSheet(sheet string, settings *FormatSheetProtection) { + xlsx := f.workSheetReader(sheet) + if settings == nil { + settings = &FormatSheetProtection{ + EditObjects: true, + EditScenarios: true, + SelectLockedCells: true, + } + } + xlsx.SheetProtection = &xlsxSheetProtection{ + AutoFilter: settings.AutoFilter, + DeleteColumns: settings.DeleteColumns, + DeleteRows: settings.DeleteRows, + FormatCells: settings.FormatCells, + FormatColumns: settings.FormatColumns, + FormatRows: settings.FormatRows, + InsertColumns: settings.InsertColumns, + InsertHyperlinks: settings.InsertHyperlinks, + InsertRows: settings.InsertRows, + Objects: settings.EditObjects, + PivotTables: settings.PivotTables, + Scenarios: settings.EditScenarios, + SelectLockedCells: settings.SelectLockedCells, + SelectUnlockedCells: settings.SelectUnlockedCells, + Sheet: true, + Sort: settings.Sort, + } + if settings.Password != "" { + xlsx.SheetProtection.Password = genSheetPasswd(settings.Password) + } +} + +// UnprotectSheet provides a function to unprotect an Excel worksheet. +func (f *File) UnprotectSheet(sheet string) { + xlsx := f.workSheetReader(sheet) + xlsx.SheetProtection = nil +} + // trimSheetName provides a function to trim invaild characters by given worksheet // name. func trimSheetName(name string) string { @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize // SheetPrOption is an option of a view of a worksheet. See SetSheetPrOptions(). @@ -22,8 +31,26 @@ type ( FitToPage bool // AutoPageBreaks is a SheetPrOption AutoPageBreaks bool + // OutlineSummaryBelow is an outlinePr, within SheetPr option + OutlineSummaryBelow bool ) +func (o OutlineSummaryBelow) setSheetPrOption(pr *xlsxSheetPr) { + if pr.OutlinePr == nil { + pr.OutlinePr = new(xlsxOutlinePr) + } + pr.OutlinePr.SummaryBelow = bool(o) +} + +func (o *OutlineSummaryBelow) getSheetPrOption(pr *xlsxSheetPr) { + // Excel default: true + if pr == nil || pr.OutlinePr == nil { + *o = true + return + } + *o = OutlineSummaryBelow(defaultTrue(&pr.OutlinePr.SummaryBelow)) +} + func (o CodeName) setSheetPrOption(pr *xlsxSheetPr) { pr.CodeName = string(o) } @@ -106,6 +133,7 @@ func (o *AutoPageBreaks) getSheetPrOption(pr *xlsxSheetPr) { // Published(bool) // FitToPage(bool) // AutoPageBreaks(bool) +// OutlineSummaryBelow(bool) func (f *File) SetSheetPrOptions(name string, opts ...SheetPrOption) error { sheet := f.workSheetReader(name) pr := sheet.SheetPr @@ -128,6 +156,7 @@ func (f *File) SetSheetPrOptions(name string, opts ...SheetPrOption) error { // Published(bool) // FitToPage(bool) // AutoPageBreaks(bool) +// OutlineSummaryBelow(bool) func (f *File) GetSheetPrOptions(name string, opts ...SheetPrOptionPtr) error { sheet := f.workSheetReader(name) pr := sheet.SheetPr diff --git a/sheetpr_test.go b/sheetpr_test.go index e7e7482..d9f5059 100644 --- a/sheetpr_test.go +++ b/sheetpr_test.go @@ -15,6 +15,7 @@ var _ = []excelize.SheetPrOption{ excelize.Published(false), excelize.FitToPage(true), excelize.AutoPageBreaks(true), + excelize.OutlineSummaryBelow(true), } var _ = []excelize.SheetPrOptionPtr{ @@ -23,6 +24,7 @@ var _ = []excelize.SheetPrOptionPtr{ (*excelize.Published)(nil), (*excelize.FitToPage)(nil), (*excelize.AutoPageBreaks)(nil), + (*excelize.OutlineSummaryBelow)(nil), } func ExampleFile_SetSheetPrOptions() { @@ -35,6 +37,7 @@ func ExampleFile_SetSheetPrOptions() { excelize.Published(false), excelize.FitToPage(true), excelize.AutoPageBreaks(true), + excelize.OutlineSummaryBelow(false), ); err != nil { panic(err) } @@ -51,6 +54,7 @@ func ExampleFile_GetSheetPrOptions() { published excelize.Published fitToPage excelize.FitToPage autoPageBreaks excelize.AutoPageBreaks + outlineSummaryBelow excelize.OutlineSummaryBelow ) if err := xl.GetSheetPrOptions(sheet, @@ -59,6 +63,7 @@ func ExampleFile_GetSheetPrOptions() { &published, &fitToPage, &autoPageBreaks, + &outlineSummaryBelow, ); err != nil { panic(err) } @@ -68,6 +73,7 @@ func ExampleFile_GetSheetPrOptions() { fmt.Println("- published:", published) fmt.Println("- fitToPage:", fitToPage) fmt.Println("- autoPageBreaks:", autoPageBreaks) + fmt.Println("- outlineSummaryBelow:", outlineSummaryBelow) // Output: // Defaults: // - codeName: "" @@ -75,6 +81,7 @@ func ExampleFile_GetSheetPrOptions() { // - published: true // - fitToPage: false // - autoPageBreaks: false + // - outlineSummaryBelow: true } func TestSheetPrOptions(t *testing.T) { @@ -88,6 +95,7 @@ func TestSheetPrOptions(t *testing.T) { {new(excelize.Published), excelize.Published(false)}, {new(excelize.FitToPage), excelize.FitToPage(true)}, {new(excelize.AutoPageBreaks), excelize.AutoPageBreaks(true)}, + {new(excelize.OutlineSummaryBelow), excelize.OutlineSummaryBelow(false)}, } { opt := test.nonDefault t.Logf("option %T", opt) diff --git a/sheetview.go b/sheetview.go index 679e915..37a0c39 100644 --- a/sheetview.go +++ b/sheetview.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "fmt" @@ -26,6 +35,8 @@ type ( ShowRowColHeaders bool // ZoomScale is a SheetViewOption. ZoomScale float64 + // TopLeftCell is a SheetViewOption. + TopLeftCell string /* TODO // ShowWhiteSpace is a SheetViewOption. ShowWhiteSpace bool @@ -38,6 +49,14 @@ type ( // Defaults for each option are described in XML schema for CT_SheetView +func (o TopLeftCell) setSheetViewOption(view *xlsxSheetView) { + view.TopLeftCell = string(o) +} + +func (o *TopLeftCell) getSheetViewOption(view *xlsxSheetView) { + *o = TopLeftCell(string(view.TopLeftCell)) +} + func (o DefaultGridColor) setSheetViewOption(view *xlsxSheetView) { view.DefaultGridColor = boolPtr(bool(o)) } diff --git a/sheetview_test.go b/sheetview_test.go index c580906..ee81d5b 100644 --- a/sheetview_test.go +++ b/sheetview_test.go @@ -13,12 +13,14 @@ var _ = []excelize.SheetViewOption{ excelize.ShowFormulas(false), excelize.ShowGridLines(true), excelize.ShowRowColHeaders(true), + excelize.TopLeftCell("B2"), // SheetViewOptionPtr are also SheetViewOption new(excelize.DefaultGridColor), new(excelize.RightToLeft), new(excelize.ShowFormulas), new(excelize.ShowGridLines), new(excelize.ShowRowColHeaders), + new(excelize.TopLeftCell), } var _ = []excelize.SheetViewOptionPtr{ @@ -27,6 +29,7 @@ var _ = []excelize.SheetViewOptionPtr{ (*excelize.ShowFormulas)(nil), (*excelize.ShowGridLines)(nil), (*excelize.ShowRowColHeaders)(nil), + (*excelize.TopLeftCell)(nil), } func ExampleFile_SetSheetViewOptions() { @@ -40,6 +43,7 @@ func ExampleFile_SetSheetViewOptions() { excelize.ShowGridLines(true), excelize.ShowRowColHeaders(true), excelize.ZoomScale(80), + excelize.TopLeftCell("C3"), ); err != nil { panic(err) } @@ -91,6 +95,7 @@ func ExampleFile_GetSheetViewOptions() { showGridLines excelize.ShowGridLines showRowColHeaders excelize.ShowRowColHeaders zoomScale excelize.ZoomScale + topLeftCell excelize.TopLeftCell ) if err := xl.GetSheetViewOptions(sheet, 0, @@ -100,6 +105,7 @@ func ExampleFile_GetSheetViewOptions() { &showGridLines, &showRowColHeaders, &zoomScale, + &topLeftCell, ); err != nil { panic(err) } @@ -111,6 +117,15 @@ func ExampleFile_GetSheetViewOptions() { fmt.Println("- showGridLines:", showGridLines) fmt.Println("- showRowColHeaders:", showRowColHeaders) fmt.Println("- zoomScale:", zoomScale) + fmt.Println("- topLeftCell:", `"`+topLeftCell+`"`) + + if err := xl.SetSheetViewOptions(sheet, 0, excelize.TopLeftCell("B2")); err != nil { + panic(err) + } + + if err := xl.GetSheetViewOptions(sheet, 0, &topLeftCell); err != nil { + panic(err) + } if err := xl.SetSheetViewOptions(sheet, 0, excelize.ShowGridLines(false)); err != nil { panic(err) @@ -122,6 +137,7 @@ func ExampleFile_GetSheetViewOptions() { fmt.Println("After change:") fmt.Println("- showGridLines:", showGridLines) + fmt.Println("- topLeftCell:", topLeftCell) // Output: // Default: @@ -131,8 +147,10 @@ func ExampleFile_GetSheetViewOptions() { // - showGridLines: true // - showRowColHeaders: true // - zoomScale: 0 + // - topLeftCell: "" // After change: // - showGridLines: false + // - topLeftCell: B2 } func TestSheetViewOptionsErrors(t *testing.T) { @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -798,35 +807,35 @@ var validType = map[string]string{ // criteriaType defined the list of valid criteria types. var criteriaType = map[string]string{ - "between": "between", - "not between": "notBetween", - "equal to": "equal", - "=": "equal", - "==": "equal", - "not equal to": "notEqual", - "!=": "notEqual", - "<>": "notEqual", - "greater than": "greaterThan", - ">": "greaterThan", - "less than": "lessThan", - "<": "lessThan", + "between": "between", + "not between": "notBetween", + "equal to": "equal", + "=": "equal", + "==": "equal", + "not equal to": "notEqual", + "!=": "notEqual", + "<>": "notEqual", + "greater than": "greaterThan", + ">": "greaterThan", + "less than": "lessThan", + "<": "lessThan", "greater than or equal to": "greaterThanOrEqual", - ">=": "greaterThanOrEqual", - "less than or equal to": "lessThanOrEqual", - "<=": "lessThanOrEqual", - "containing": "containsText", - "not containing": "notContains", - "begins with": "beginsWith", - "ends with": "endsWith", - "yesterday": "yesterday", - "today": "today", - "last 7 days": "last7Days", - "last week": "lastWeek", - "this week": "thisWeek", - "continue week": "continueWeek", - "last month": "lastMonth", - "this month": "thisMonth", - "continue month": "continueMonth", + ">=": "greaterThanOrEqual", + "less than or equal to": "lessThanOrEqual", + "<=": "lessThanOrEqual", + "containing": "containsText", + "not containing": "notContains", + "begins with": "beginsWith", + "ends with": "endsWith", + "yesterday": "yesterday", + "today": "today", + "last 7 days": "last7Days", + "last week": "lastWeek", + "this week": "thisWeek", + "continue week": "continueWeek", + "last month": "lastMonth", + "this month": "thisMonth", + "continue month": "continueMonth", } // formatToString provides a function to return original string by given @@ -990,7 +999,7 @@ func is12HourTime(format string) bool { func (f *File) stylesReader() *xlsxStyleSheet { if f.Styles == nil { var styleSheet xlsxStyleSheet - _ = xml.Unmarshal([]byte(f.readXML("xl/styles.xml")), &styleSheet) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/styles.xml")), &styleSheet) f.Styles = &styleSheet } return f.Styles @@ -2748,7 +2757,7 @@ func getPaletteColor(color string) string { // structure after deserialization. func (f *File) themeReader() *xlsxTheme { var theme xlsxTheme - _ = xml.Unmarshal([]byte(f.readXML("xl/theme/theme1.xml")), &theme) + _ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/theme/theme1.xml")), &theme) return &theme } @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import ( @@ -282,7 +291,7 @@ func (f *File) autoFilter(sheet, ref string, refRange, hxAxis int, formatSet *fo col := TitleToNumber(formatSet.Column) offset := col - hxAxis if offset < 0 || offset > refRange { - return fmt.Errorf("Incorrect index of column '%s'", formatSet.Column) + return fmt.Errorf("incorrect index of column '%s'", formatSet.Column) } filter.FilterColumn = &xlsxFilterColumn{ ColID: offset, @@ -290,7 +299,7 @@ func (f *File) autoFilter(sheet, ref string, refRange, hxAxis int, formatSet *fo re := regexp.MustCompile(`"(?:[^"]|"")*"|\S+`) token := re.FindAllString(formatSet.Expression, -1) if len(token) != 3 && len(token) != 7 { - return fmt.Errorf("Incorrect number of tokens in criteria '%s'", formatSet.Expression) + return fmt.Errorf("incorrect number of tokens in criteria '%s'", formatSet.Expression) } expressions, tokens, err := f.parseFilterExpression(formatSet.Expression, token) if err != nil { @@ -415,7 +424,7 @@ func (f *File) parseFilterTokens(expression string, tokens []string) ([]int, str operator, ok := operators[strings.ToLower(tokens[1])] if !ok { // Convert the operator from a number to a descriptive string. - return []int{}, "", fmt.Errorf("Unknown operator: %s", tokens[1]) + return []int{}, "", fmt.Errorf("unknown operator: %s", tokens[1]) } token := tokens[2] // Special handling for Blanks/NonBlanks. @@ -423,7 +432,7 @@ func (f *File) parseFilterTokens(expression string, tokens []string) ([]int, str if re { // Only allow Equals or NotEqual in this context. if operator != 2 && operator != 5 { - return []int{operator}, token, fmt.Errorf("The operator '%s' in expression '%s' is not valid in relation to Blanks/NonBlanks'", tokens[1], expression) + return []int{operator}, token, fmt.Errorf("the operator '%s' in expression '%s' is not valid in relation to Blanks/NonBlanks'", tokens[1], expression) } token = strings.ToLower(token) // The operator should always be 2 (=) to flag a "simple" equality in diff --git a/templates.go b/templates.go index ef6058c..1d0655d 100644 --- a/templates.go +++ b/templates.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. +// // This file contains default templates for XML files we don't yet populated // based on content. diff --git a/test/Book1.xlsx b/test/Book1.xlsx Binary files differindex 84c43d1..2ef1121 100755..100644 --- a/test/Book1.xlsx +++ b/test/Book1.xlsx diff --git a/test/images/excel.gif b/test/images/excel.gif Binary files differindex bf7499a..4baa4b5 100644 --- a/test/images/excel.gif +++ b/test/images/excel.gif diff --git a/test/images/excel.jpg b/test/images/excel.jpg Binary files differindex 49edfef..ed1ee1d 100644 --- a/test/images/excel.jpg +++ b/test/images/excel.jpg diff --git a/test/images/excel.png b/test/images/excel.png Binary files differindex 52c36db..3e4760b 100644 --- a/test/images/excel.png +++ b/test/images/excel.png diff --git a/vmlDrawing.go b/vmlDrawing.go index 307186a..c17dde7 100644 --- a/vmlDrawing.go +++ b/vmlDrawing.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" diff --git a/xmlChart.go b/xmlChart.go index a263334..3271cbb 100644 --- a/xmlChart.go +++ b/xmlChart.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" @@ -244,7 +253,7 @@ type aLn struct { Algn string `xml:"algn,attr,omitempty"` Cap string `xml:"cap,attr,omitempty"` Cmpd string `xml:"cmpd,attr,omitempty"` - W int `xml:"w,attr,omitempty" ` + W int `xml:"w,attr,omitempty"` NoFill string `xml:"a:noFill,omitempty"` Round string `xml:"a:round,omitempty"` SolidFill *aSolidFill `xml:"a:solidFill"` @@ -582,7 +591,7 @@ type formatChartSeries struct { } `json:"line"` Marker struct { Type string `json:"type"` - Size int `json:"size,"` + Size int `json:"size"` Width float64 `json:"width"` Border struct { Color string `json:"color"` diff --git a/xmlComments.go b/xmlComments.go index fadc9b3..9075c88 100644 --- a/xmlComments.go +++ b/xmlComments.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" @@ -53,3 +62,11 @@ type formatComment struct { Author string `json:"author"` Text string `json:"text"` } + +// Comment directly maps the comment information. +type Comment struct { + Author string `json:"author"` + AuthorID int `json:"author_id"` + Ref string `json:"ref"` + Text string `json:"text"` +} diff --git a/xmlContentTypes.go b/xmlContentTypes.go index 121c684..8d09d51 100644 --- a/xmlContentTypes.go +++ b/xmlContentTypes.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" diff --git a/xmlDecodeDrawing.go b/xmlDecodeDrawing.go index fff6b9d..d21c3f0 100644 --- a/xmlDecodeDrawing.go +++ b/xmlDecodeDrawing.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" diff --git a/xmlDrawing.go b/xmlDrawing.go index beb6bc9..7356cb5 100644 --- a/xmlDrawing.go +++ b/xmlDrawing.go @@ -1,27 +1,41 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" // Source relationship and namespace. const ( - SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships" - SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart" - SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" - SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" - SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table" - SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" - SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" - SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" - SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" - SourceRelationshipChart201506 = "http://schemas.microsoft.com/office/drawing/2015/06/chart" - SourceRelationshipChart20070802 = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart" - SourceRelationshipChart2014 = "http://schemas.microsoft.com/office/drawing/2014/chart" - SourceRelationshipCompatibility = "http://schemas.openxmlformats.org/markup-compatibility/2006" - NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main" - NameSpaceDrawingMLChart = "http://schemas.openxmlformats.org/drawingml/2006/chart" - NameSpaceDrawingMLSpreadSheet = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" - NameSpaceSpreadSheet = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" - NameSpaceXML = "http://www.w3.org/XML/1998/namespace" + SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships" + SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart" + SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" + SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" + SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table" + SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" + SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" + SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" + SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" + SourceRelationshipChart201506 = "http://schemas.microsoft.com/office/drawing/2015/06/chart" + SourceRelationshipChart20070802 = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart" + SourceRelationshipChart2014 = "http://schemas.microsoft.com/office/drawing/2014/chart" + SourceRelationshipCompatibility = "http://schemas.openxmlformats.org/markup-compatibility/2006" + NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main" + NameSpaceDrawingMLChart = "http://schemas.openxmlformats.org/drawingml/2006/chart" + NameSpaceDrawingMLSpreadSheet = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" + NameSpaceSpreadSheet = "http://schemas.openxmlformats.org/spreadsheetml/2006/main" + NameSpaceXML = "http://www.w3.org/XML/1998/namespace" + StrictSourceRelationship = "http://purl.oclc.org/ooxml/officeDocument/relationships" + StrictSourceRelationshipChart = "http://purl.oclc.org/ooxml/officeDocument/relationships/chart" + StrictSourceRelationshipComments = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments" + StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image" + StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main" ) var supportImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png"} diff --git a/xmlSharedStrings.go b/xmlSharedStrings.go index c8b54a0..782ed61 100644 --- a/xmlSharedStrings.go +++ b/xmlSharedStrings.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" diff --git a/xmlStyles.go b/xmlStyles.go index 05ff22b..7ba4379 100644 --- a/xmlStyles.go +++ b/xmlStyles.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" diff --git a/xmlTable.go b/xmlTable.go index b238350..7e155e6 100644 --- a/xmlTable.go +++ b/xmlTable.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" diff --git a/xmlTheme.go b/xmlTheme.go index d2ab343..b4140b6 100644 --- a/xmlTheme.go +++ b/xmlTheme.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" diff --git a/xmlWorkbook.go b/xmlWorkbook.go index 816d5a4..6572033 100644 --- a/xmlWorkbook.go +++ b/xmlWorkbook.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" @@ -142,7 +151,7 @@ type xlsxSheets struct { // not checked it for completeness - it does as much as I need. type xlsxSheet struct { Name string `xml:"name,attr,omitempty"` - SheetID string `xml:"sheetId,attr,omitempty"` + SheetID int `xml:"sheetId,attr,omitempty"` ID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"` State string `xml:"state,attr,omitempty"` } diff --git a/xmlWorksheet.go b/xmlWorksheet.go index 87d66a1..d35b40e 100644 --- a/xmlWorksheet.go +++ b/xmlWorksheet.go @@ -1,3 +1,12 @@ +// Copyright 2016 - 2018 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. +// +// 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. + package excelize import "encoding/xml" @@ -18,7 +27,7 @@ type xlsxWorksheet struct { MergeCells *xlsxMergeCells `xml:"mergeCells"` PhoneticPr *xlsxPhoneticPr `xml:"phoneticPr"` ConditionalFormatting []*xlsxConditionalFormatting `xml:"conditionalFormatting"` - DataValidations *xlsxDataValidations `xml:"dataValidations"` + DataValidations *xlsxDataValidations `xml:"dataValidations,omitempty"` Hyperlinks *xlsxHyperlinks `xml:"hyperlinks"` PrintOptions *xlsxPrintOptions `xml:"printOptions"` PageMargins *xlsxPageMargins `xml:"pageMargins"` @@ -202,6 +211,13 @@ type xlsxSheetPr struct { TransitionEntry bool `xml:"transitionEntry,attr,omitempty"` TabColor *xlsxTabColor `xml:"tabColor,omitempty"` PageSetUpPr *xlsxPageSetUpPr `xml:"pageSetUpPr,omitempty"` + OutlinePr *xlsxOutlinePr `xml:"outlinePr,omitempty"` +} + +// xlsxOutlinePr maps to the outlinePr element +// SummaryBelow allows you to adjust the direction of grouper controls +type xlsxOutlinePr struct { + SummaryBelow bool `xml:"summaryBelow,attr"` } // xlsxPageSetUpPr directly maps the pageSetupPr element in the namespace @@ -294,11 +310,30 @@ type xlsxMergeCells struct { // xlsxDataValidations expresses all data validation information for cells in a // sheet which have data validation features applied. type xlsxDataValidations struct { - Count int `xml:"count,attr,omitempty"` - DisablePrompts bool `xml:"disablePrompts,attr,omitempty"` - XWindow int `xml:"xWindow,attr,omitempty"` - YWindow int `xml:"yWindow,attr,omitempty"` - DataValidation string `xml:",innerxml"` + Count int `xml:"count,attr,omitempty"` + DisablePrompts bool `xml:"disablePrompts,attr,omitempty"` + XWindow int `xml:"xWindow,attr,omitempty"` + YWindow int `xml:"yWindow,attr,omitempty"` + DataValidation []*DataValidation `xml:"dataValidation"` +} + +// DataValidation directly maps the a single item of data validation defined +// on a range of the worksheet. +type DataValidation struct { + AllowBlank bool `xml:"allowBlank,attr"` + Error *string `xml:"error,attr"` + ErrorStyle *string `xml:"errorStyle,attr"` + ErrorTitle *string `xml:"errorTitle,attr"` + Operator string `xml:"operator,attr"` + Prompt *string `xml:"prompt,attr"` + PromptTitle *string `xml:"promptTitle"` + ShowDropDown bool `xml:"showDropDown,attr"` + ShowErrorMessage bool `xml:"showErrorMessage,attr"` + ShowInputMessage bool `xml:"showInputMessage,attr"` + Sqref string `xml:"sqref,attr"` + Type string `xml:"type,attr"` + Formula1 string `xml:"formula1"` + Formula2 string `xml:"formula2"` } // xlsxC directly maps the c element in the namespace @@ -349,26 +384,27 @@ type xlsxF struct { // xlsxSheetProtection collection expresses the sheet protection options to // enforce when the sheet is protected. type xlsxSheetProtection struct { - AlgorithmName string `xml:"algorithmName,attr,omitempty"` - AutoFilter int `xml:"autoFilter,attr,omitempty"` - DeleteColumns int `xml:"deleteColumns,attr,omitempty"` - DeleteRows int `xml:"deleteRows,attr,omitempty"` - FormatCells int `xml:"formatCells,attr,omitempty"` - FormatColumns int `xml:"formatColumns,attr,omitempty"` - FormatRows int `xml:"formatRows,attr,omitempty"` - HashValue string `xml:"hashValue,attr,omitempty"` - InsertColumns int `xml:"insertColumns,attr,omitempty"` - InsertHyperlinks int `xml:"insertHyperlinks,attr,omitempty"` - InsertRows int `xml:"insertRows,attr,omitempty"` - Objects int `xml:"objects,attr,omitempty"` - PivotTables int `xml:"pivotTables,attr,omitempty"` - SaltValue string `xml:"saltValue,attr,omitempty"` - Scenarios int `xml:"scenarios,attr,omitempty"` - SelectLockedCells int `xml:"selectLockedCells,attr,omitempty"` - SelectUnlockedCell int `xml:"selectUnlockedCell,attr,omitempty"` - Sheet int `xml:"sheet,attr,omitempty"` - Sort int `xml:"sort,attr,omitempty"` - SpinCount int `xml:"spinCount,attr,omitempty"` + AlgorithmName string `xml:"algorithmName,attr,omitempty"` + AutoFilter bool `xml:"autoFilter,attr,omitempty"` + DeleteColumns bool `xml:"deleteColumns,attr,omitempty"` + DeleteRows bool `xml:"deleteRows,attr,omitempty"` + FormatCells bool `xml:"formatCells,attr,omitempty"` + FormatColumns bool `xml:"formatColumns,attr,omitempty"` + FormatRows bool `xml:"formatRows,attr,omitempty"` + HashValue string `xml:"hashValue,attr,omitempty"` + InsertColumns bool `xml:"insertColumns,attr,omitempty"` + InsertHyperlinks bool `xml:"insertHyperlinks,attr,omitempty"` + InsertRows bool `xml:"insertRows,attr,omitempty"` + Objects bool `xml:"objects,attr,omitempty"` + Password string `xml:"password,attr,omitempty"` + PivotTables bool `xml:"pivotTables,attr,omitempty"` + SaltValue string `xml:"saltValue,attr,omitempty"` + Scenarios bool `xml:"scenarios,attr,omitempty"` + SelectLockedCells bool `xml:"selectLockedCells,attr,omitempty"` + SelectUnlockedCells bool `xml:"selectUnlockedCells,attr,omitempty"` + Sheet bool `xml:"sheet,attr,omitempty"` + Sort bool `xml:"sort,attr,omitempty"` + SpinCount int `xml:"spinCount,attr,omitempty"` } // xlsxPhoneticPr (Phonetic Properties) represents a collection of phonetic @@ -571,3 +607,23 @@ type formatConditional struct { MultiRange string `json:"multi_range,omitempty"` BarColor string `json:"bar_color,omitempty"` } + +// FormatSheetProtection directly maps the settings of worksheet protection. +type FormatSheetProtection struct { + AutoFilter bool + DeleteColumns bool + DeleteRows bool + EditObjects bool + EditScenarios bool + FormatCells bool + FormatColumns bool + FormatRows bool + InsertColumns bool + InsertHyperlinks bool + InsertRows bool + Password string + PivotTables bool + SelectLockedCells bool + SelectUnlockedCells bool + Sort bool +} |