diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | README_zh.md | 2 | ||||
-rw-r--r-- | chart.go | 4 | ||||
-rw-r--r-- | excelize_test.go | 12 | ||||
-rw-r--r-- | picture.go | 11 | ||||
-rw-r--r-- | rows.go | 100 | ||||
-rw-r--r-- | rows_test.go | 42 | ||||
-rw-r--r-- | shape.go | 4 | ||||
-rw-r--r-- | sheet.go | 22 | ||||
-rw-r--r-- | styles.go | 24 | ||||
-rw-r--r-- | table.go | 35 | ||||
-rw-r--r-- | xmlDrawing.go | 1 | ||||
-rw-r--r-- | xmlTable.go | 1 |
13 files changed, 203 insertions, 57 deletions
@@ -11,7 +11,7 @@ ## Introduction -Excelize is a library written in pure Golang and 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. The full API docs can be seen using go's built-in documentation tool, or online at [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize). +Excelize is a library written in pure Golang and 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. The full API docs can be seen using go's built-in documentation tool, or online at [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) and [Chinese translation](https://xuri.me/excelize/zh_cn). ## Basic Usage diff --git a/README_zh.md b/README_zh.md index a657d8a..ef149b0 100644 --- a/README_zh.md +++ b/README_zh.md @@ -11,7 +11,7 @@ ## 简介 -Excelize 是 Go 语言编写的用于操作 Office Excel 文档类库,基于 ECMA-376 Office OpenXML 标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的 XLSX 文档。相比较其他的开源类库,Excelize 支持写入原本带有图片(表)、透视表和切片器等复杂样式的文档,还支持向 Excel 文档中插入图片与图表,并且在保存后不会丢失文档原有样式,可以应用于各类报表系统中。使用本类库要求使用的 Go 语言为 1.8 或更高版本,完整的 API 使用文档请访问 [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize)。 +Excelize 是 Go 语言编写的用于操作 Office Excel 文档类库,基于 ECMA-376 Office OpenXML 标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的 XLSX 文档。相比较其他的开源类库,Excelize 支持写入原本带有图片(表)、透视表和切片器等复杂样式的文档,还支持向 Excel 文档中插入图片与图表,并且在保存后不会丢失文档原有样式,可以应用于各类报表系统中。使用本类库要求使用的 Go 语言为 1.8 或更高版本,完整的 API 使用文档请访问 [godoc.org](https://godoc.org/github.com/360EntSecGroup-Skylar/excelize) 或查看 [中文翻译](https://xuri.me/excelize/zh_cn)。 ## 快速上手 @@ -261,7 +261,7 @@ func parseFormatChartSet(formatSet string) *formatChart { // colStacked | 2D stacked column chart // colPercentStacked | 2D 100% stacked column chart // col3DClustered | 3D clustered column chart -// col3D | 3D column column chart +// col3D | 3D column chart // col3DStacked | 3D stacked column chart // col3DPercentStacked | 3D 100% stacked column chart // doughnut | doughnut chart @@ -1111,7 +1111,7 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI content.Xdr = NameSpaceDrawingMLSpreadSheet cNvPrID := f.drawingParser(drawingXML, &content) twoCellAnchor := xdrCellAnchor{} - twoCellAnchor.EditAs = "oneCell" + twoCellAnchor.EditAs = formatSet.Positioning from := xlsxFrom{} from.Col = colStart from.ColOff = formatSet.OffsetX * EMU diff --git a/excelize_test.go b/excelize_test.go index ade3baf..9587f33 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -137,8 +137,8 @@ func TestAddPicture(t *testing.T) { if err != nil { t.Log(err) } - // Test add picture to worksheet with offset and external hyperlink. - err = xlsx.AddPicture("Sheet1", "F21", "./test/images/excel.png", `{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External"}`) + // Test add picture to worksheet with offset, external hyperlink and positioning. + err = xlsx.AddPicture("Sheet1", "F21", "./test/images/excel.png", `{"x_offset": 10, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "positioning": "oneCell"}`) if err != nil { t.Log(err) } @@ -196,8 +196,8 @@ func TestNewFile(t *testing.T) { xlsx.SetCellInt("XLSXSheet2", "A23", 56) xlsx.SetCellStr("Sheet1", "B20", "42") xlsx.SetActiveSheet(0) - // Test add picture to sheet with scaling. - err := xlsx.AddPicture("Sheet1", "H2", "./test/images/excel.gif", `{"x_scale": 0.5, "y_scale": 0.5}`) + // Test add picture to sheet with scaling and positioning. + err := xlsx.AddPicture("Sheet1", "H2", "./test/images/excel.gif", `{"x_scale": 0.5, "y_scale": 0.5, "positioning": "absolute"}`) if err != nil { t.Log(err) } @@ -756,7 +756,7 @@ func TestAddTable(t *testing.T) { t.Log(err) } xlsx.AddTable("Sheet1", "B26", "A21", ``) - xlsx.AddTable("Sheet2", "A2", "B5", `{"table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`) + xlsx.AddTable("Sheet2", "A2", "B5", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`) xlsx.AddTable("Sheet2", "F1", "F1", `{"table_style":"TableStyleMedium8"}`) err = xlsx.Save() if err != nil { @@ -860,7 +860,7 @@ func TestAddChart(t *testing.T) { xlsx.AddChart("Sheet2", "X32", `{"type":"pie","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit Pie Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":false,"show_val":false},"show_blanks_as":"gap"}`) xlsx.AddChart("Sheet2", "P48", `{"type":"bar","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Clustered Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) xlsx.AddChart("Sheet2", "X48", `{"type":"barStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Stacked Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) - xlsx.AddChart("Sheet2", "P64", `{"type":"barPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Stacked Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) + xlsx.AddChart("Sheet2", "P64", `{"type":"barPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 2D Stacked 100% Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) xlsx.AddChart("Sheet2", "X64", `{"type":"bar3DClustered","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D Clustered Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) xlsx.AddChart("Sheet2", "P80", `{"type":"bar3DStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D Stacked Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","y_axis":{"maximum":7.5,"minimum":0.5}}`) xlsx.AddChart("Sheet2", "X80", `{"type":"bar3DPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D 100% Stacked Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"reverse_order":true,"maximum":0,"minimum":0},"y_axis":{"reverse_order":true,"maximum":0,"minimum":0}}`) @@ -57,8 +57,8 @@ func parseFormatPictureSet(formatSet string) *formatPicture { // if err != nil { // fmt.Println(err) // } -// // Insert a picture offset in the cell with external hyperlink and printing support. -// err = xlsx.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "print_obj": true, "lock_aspect_ratio": false, "locked": false}`) +// // Insert a picture offset in the cell with external hyperlink, printing and positioning support. +// err = xlsx.AddPicture("Sheet1", "H2", "./image3.gif", `{"x_offset": 15, "y_offset": 10, "hyperlink": "https://github.com/360EntSecGroup-Skylar/excelize", "hyperlink_type": "External", "print_obj": true, "lock_aspect_ratio": false, "locked": false, "positioning": "oneCell"}`) // if err != nil { // fmt.Println(err) // } @@ -71,6 +71,11 @@ func parseFormatPictureSet(formatSet string) *formatPicture { // LinkType defines two types of hyperlink "External" for web site or // "Location" for moving to one of cell in this workbook. When the // "hyperlink_type" is "Location", coordinates need to start with "#". +// +// Positioning defines two types of the position of a picture in an Excel +// spreadsheet, "oneCell" (Move but don't size with cells) or "absolute" +// (Don't move or size with cells). If you don't set this parameter, default +// positioning is move and size with cells. func (f *File) AddPicture(sheet, cell, picture, format string) error { var err error var drawingHyperlinkRID int @@ -217,7 +222,7 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he content.Xdr = NameSpaceDrawingMLSpreadSheet cNvPrID := f.drawingParser(drawingXML, &content) twoCellAnchor := xdrCellAnchor{} - twoCellAnchor.EditAs = "oneCell" + twoCellAnchor.EditAs = formatSet.Positioning from := xlsxFrom{} from.Col = colStart from.ColOff = formatSet.OffsetX * EMU @@ -3,6 +3,8 @@ package excelize import ( "bytes" "encoding/xml" + "fmt" + "io" "math" "strconv" "strings" @@ -67,6 +69,100 @@ func (f *File) GetRows(sheet string) [][]string { return rows } +// Rows defines an iterator to a sheet +type Rows struct { + decoder *xml.Decoder + token xml.Token + err error + f *File +} + +// Next will return true if find the next row element. +func (rows *Rows) Next() bool { + for { + rows.token, rows.err = rows.decoder.Token() + if rows.err == io.EOF { + rows.err = nil + } + if rows.token == nil { + return false + } + + switch startElement := rows.token.(type) { + case xml.StartElement: + inElement := startElement.Name.Local + if inElement == "row" { + return true + } + } + } +} + +// Error will return the error when the find next row element +func (rows *Rows) Error() error { + return rows.err +} + +// Columns return the current row's column values +func (rows *Rows) Columns() []string { + if rows.token == nil { + return []string{} + } + + startElement := rows.token.(xml.StartElement) + r := xlsxRow{} + rows.decoder.DecodeElement(&r, &startElement) + + d := rows.f.sharedStringsReader() + row := make([]string, len(r.C), len(r.C)) + for _, colCell := range r.C { + c := TitleToNumber(strings.Map(letterOnlyMapF, colCell.R)) + val, _ := colCell.getValueFrom(rows.f, d) + row[c] = val + } + return row +} + +// ErrSheetNotExist defines an error of sheet is not exist +type ErrSheetNotExist struct { + SheetName string +} + +func (err ErrSheetNotExist) Error() string { + return fmt.Sprintf("Sheet %s is not exist", string(err.SheetName)) +} + +// Rows return a rows iterator. For example: +// +// rows, err := xlsx.GetRows("Sheet1") +// +// for rows.Next() { +// for _, colCell := range rows.Columns() { +// fmt.Print(colCell, "\t") +// } +// fmt.Println() +// } +// +func (f *File) Rows(sheet string) (*Rows, error) { + xlsx := f.workSheetReader(sheet) + name, ok := f.sheetMap[trimSheetName(sheet)] + if !ok { + return nil, ErrSheetNotExist{sheet} + } + if xlsx != nil { + output, err := xml.Marshal(f.Sheet[name]) + if err != nil { + return nil, err + } + f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) + } + + return &Rows{ + f: f, + decoder: xml.NewDecoder(strings.NewReader(f.readXML(name))), + }, nil +} + // getTotalRowsCols provides a function to get total columns and rows in a // worksheet. func (f *File) getTotalRowsCols(name string) (int, int) { @@ -182,7 +278,7 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) { } // SetRowVisible provides a function to set visible of a single row by given -// worksheet name and row index. For example, hide row 3 in Sheet1: +// worksheet name and row index. For example, hide row 2 in Sheet1: // // xlsx.SetRowVisible("Sheet1", 2, false) // @@ -199,7 +295,7 @@ func (f *File) SetRowVisible(sheet string, rowIndex int, visible bool) { } // GetRowVisible provides a function to get visible of a single row by given -// worksheet name and row index. For example, get visible state of row 3 in +// worksheet name and row index. For example, get visible state of row 2 in // Sheet1: // // xlsx.GetRowVisible("Sheet1", 2) diff --git a/rows_test.go b/rows_test.go new file mode 100644 index 0000000..eadf077 --- /dev/null +++ b/rows_test.go @@ -0,0 +1,42 @@ +package excelize + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func trimSliceSpace(s []string) []string { + for { + if len(s) > 0 && s[len(s)-1] == "" { + s = s[:len(s)-1] + } else { + break + } + } + return s +} + +func TestRows(t *testing.T) { + xlsx, err := OpenFile("./test/Book1.xlsx") + assert.NoError(t, err) + + rows, err := xlsx.Rows("Sheet2") + assert.NoError(t, err) + + rowStrs := make([][]string, 0) + var i = 0 + for rows.Next() { + i++ + columns := rows.Columns() + //fmt.Println(i, columns) + rowStrs = append(rowStrs, columns) + } + assert.NoError(t, rows.Error()) + + dstRows := xlsx.GetRows("Sheet2") + assert.EqualValues(t, len(dstRows), len(rowStrs)) + for i := 0; i < len(rowStrs); i++ { + assert.EqualValues(t, trimSliceSpace(dstRows[i]), trimSliceSpace(rowStrs[i])) + } +} @@ -34,7 +34,7 @@ func parseFormatShapeSet(formatSet string) *formatShape { // // xlsx.AddShape("Sheet1", "G6", `{"type":"rect","color":{"line":"#4286F4","fill":"#8eb9ff"},"paragraph":[{"text":"Rectangle Shape","font":{"bold":true,"italic":true,"family":"Berlin Sans FB Demi","size":36,"color":"#777777","underline":"sng"}}],"width":180,"height": 90}`) // -// The following shows the type of chart supported by excelize: +// The following shows the type of shape supported by excelize: // // accentBorderCallout1 (Callout 1 with Border and Accent Shape) // accentBorderCallout2 (Callout 2 with Border and Accent Shape) @@ -285,7 +285,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *format content.Xdr = NameSpaceDrawingMLSpreadSheet cNvPrID := f.drawingParser(drawingXML, &content) twoCellAnchor := xdrCellAnchor{} - twoCellAnchor.EditAs = "oneCell" + twoCellAnchor.EditAs = formatSet.Format.Positioning from := xlsxFrom{} from.Col = colStart from.ColOff = formatSet.Format.OffsetX * EMU @@ -12,9 +12,9 @@ import ( "unicode/utf8" ) -// NewSheet provides function to create a new sheet by given index, 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 create, when you +// create a new file. func (f *File) NewSheet(name string) int { // Check if the worksheet already exists if f.GetSheetIndex(name) != 0 { @@ -536,13 +536,9 @@ func parseFormatPanesSet(formatSet string) *formatPanes { // | been applied, dividing the pane into right and left // | regions. In that case, this value specifies the left pane // | -// | Top right pane, when both vertical and horizontal +// topRight (Top Right Pane) | Top right pane, when both vertical and horizontal // | splits are applied. // | -// topRight (Top Right Pane) | This value is also used when only a vertical split has -// | splits are applied. -// | -// | // | This value is also used when only a vertical split has // | been applied, dividing the pane into right and left // | regions. In that case, this value specifies the right @@ -577,19 +573,19 @@ func parseFormatPanesSet(formatSet string) *formatPanes { // set of ranges. // // An example of how to freeze column A in the Sheet1 and set the active cell on -// Sheet1!A16: +// Sheet1!K16: // -// xlsx.SetPanes("Sheet1", `{"freeze":true,"split":false,"x_split":1,"y_split":0,"topLeftCell":"B1","activePane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`) +// xlsx.SetPanes("Sheet1", `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`) // // An example of how to freeze rows 1 to 9 in the Sheet1 and set the active cell -// on Sheet1!A11: +// ranges on Sheet1!A11:XFD11: // -// xlsx.SetPanes("Sheet1", `{"freeze":true,"split":false,"x_split":0,"y_split":9,"topLeftCell":"A34","activePane":"bottomLeft","panes":[{"sqref":"A11:XFD11","active_cell":"A11","pane":"bottomLeft"}]}`) +// xlsx.SetPanes("Sheet1", `{"freeze":true,"split":false,"x_split":0,"y_split":9,"top_left_cell":"A34","active_pane":"bottomLeft","panes":[{"sqref":"A11:XFD11","active_cell":"A11","pane":"bottomLeft"}]}`) // // An example of how to create split panes in the Sheet1 and set the active cell // on Sheet1!J60: // -// xlsx.SetPanes("Sheet1", `{"freeze":false,"split":true,"x_split":3270,"y_split":1800,"topLeftCell":"N57","activePane":"bottomLeft","panes":[{"sqref":"I36","active_cell":"I36"},{"sqref":"G33","active_cell":"G33","pane":"topRight"},{"sqref":"J60","active_cell":"J60","pane":"bottomLeft"},{"sqref":"O60","active_cell":"O60","pane":"bottomRight"}]}`) +// xlsx.SetPanes("Sheet1", `{"freeze":false,"split":true,"x_split":3270,"y_split":1800,"top_left_cell":"N57","active_pane":"bottomLeft","panes":[{"sqref":"I36","active_cell":"I36"},{"sqref":"G33","active_cell":"G33","pane":"topRight"},{"sqref":"J60","active_cell":"J60","pane":"bottomLeft"},{"sqref":"O60","active_cell":"O60","pane":"bottomRight"}]}`) // // An example of how to unfreeze and remove all panes on Sheet1: // @@ -1236,13 +1236,13 @@ func parseFormatStyleSet(style string) (*formatStyle, error) { // 55 | 4E0A5348/4E0B5348h"65F6"mm"5206 // 56 | 4E0A5348/4E0B5348h"65F6"mm"5206"ss"79D2 // 57 | yyyy"5E74"m"6708 -// 58 | m"6708"d"65E5"`, +// 58 | m"6708"d"65E5" // // Number format code in ja-jp language: // // Index | Symbol // -------+------------------------------------------- -// 27 | [$-411]ge.m. +// 27 | [$-411]ge.m.d // 28 | [$-411]ggge"年"m"月"d"日 // 29 | [$-411]ggge"年"m"月"d"日 // 30 | m/d/y @@ -1251,18 +1251,18 @@ func parseFormatStyleSet(style string) (*formatStyle, error) { // 33 | h"時"mm"分"ss"秒 // 34 | yyyy"年"m"月 // 35 | m"月"d"日 -// 36 | [$-411]ge.m. -// 50 | [$-411]ge.m. +// 36 | [$-411]ge.m.d +// 50 | [$-411]ge.m.d // 51 | [$-411]ggge"年"m"月"d"日 // 52 | yyyy"年"m"月 // 53 | m"月"d"日 // 54 | [$-411]ggge"年"m"月"d"日 // 55 | yyyy"年"m"月 // 56 | m"月"d"日 -// 57 | [$-411]ge.m. +// 57 | [$-411]ge.m.d // 58 | [$-411]ggge"年"m"月"d"日" // -// Number format code in th-th language: +// Number format code in ko-kr language: // // Index | Symbol // -------+------------------------------------------- @@ -1291,7 +1291,7 @@ func parseFormatStyleSet(style string) (*formatStyle, error) { // // Index | Symbol // -------+------------------------------------------- -// 27 | [$-411]ge.m. +// 27 | [$-411]ge.m.d // 28 | [$-411]ggge"5E74"m"6708"d"65E5 // 29 | [$-411]ggge"5E74"m"6708"d"65E5 // 30 | m/d/y @@ -1300,15 +1300,15 @@ func parseFormatStyleSet(style string) (*formatStyle, error) { // 33 | h"6642"mm"5206"ss"79D2 // 34 | yyyy"5E74"m"6708 // 35 | m"6708"d"65E5 -// 36 | [$-411]ge.m. -// 50 | [$-411]ge.m. +// 36 | [$-411]ge.m.d +// 50 | [$-411]ge.m.d // 51 | [$-411]ggge"5E74"m"6708"d"65E5 // 52 | yyyy"5E74"m"6708 // 53 | m"6708"d"65E5 // 54 | [$-411]ggge"5E74"m"6708"d"65E5 // 55 | yyyy"5E74"m"6708 // 56 | m"6708"d"65E5 -// 57 | [$-411]ge.m. +// 57 | [$-411]ge.m.d // 58 | [$-411]ggge"5E74"m"6708"d"65E5" // // Number format code with unicode values provided for language glyphs where @@ -1336,7 +1336,7 @@ func parseFormatStyleSet(style string) (*formatStyle, error) { // 57 | yyyy"5E74" mm"6708" dd"65E5 // 58 | mm-dd // -// Number format code in ko-kr language: +// Number format code in th-th language: // // Index | Symbol // -------+------------------------------------------- @@ -2304,7 +2304,7 @@ func setCellXfs(style *xlsxStyleSheet, fontID, numFmtID, fillID, borderID int, a // // Hide and lock for cell H9 on Sheet1: // -// style, err := xlsx.NewStyle(`{"protection":{"hidden":true, "locked":true}`) +// style, err := xlsx.NewStyle(`{"protection":{"hidden":true, "locked":true}}`) // if err != nil { // fmt.Println(err) // } @@ -28,10 +28,12 @@ func parseFormatTableSet(formatSet string) *formatTable { // // Create a table of F2:H6 on Sheet2 with format set: // -// xlsx.AddTable("Sheet2", "F2", "H6", `{"table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`) +// xlsx.AddTable("Sheet2", "F2", "H6", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`) // -// Note that the table at least two lines include string type header. The two -// chart coordinate areas can not have an intersection. +// Note that the table at least two lines include string type header. Multiple +// tables coordinate areas can't have an intersection. +// +// table_name: The name of the table, in the same worksheet name of the table should be unique // // table_style: The built-in table style names // @@ -122,7 +124,10 @@ func (f *File) addTable(sheet, tableXML string, hxAxis, hyAxis, vxAxis, vyAxis, Name: name, }) } - name := "Table" + strconv.Itoa(i) + name := formatSet.TableName + if name == "" { + name = "Table" + strconv.Itoa(i) + } t := xlsxTable{ XMLNS: NameSpaceSpreadSheet, ID: i, @@ -157,9 +162,9 @@ func parseAutoFilterSet(formatSet string) *formatAutoFilter { } // AutoFilter provides the method to add auto filter in a worksheet by given -// worksheet name, coordinate area and settings. An autofilter in Excel is a way -// of filtering a 2D range of data based on some simple criteria. For example -// applying an autofilter to a cell range A1:D4 in the worksheet 1: +// worksheet name, coordinate area and settings. An autofilter in Excel is a +// way of filtering a 2D range of data based on some simple criteria. For +// example applying an autofilter to a cell range A1:D4 in the Sheet1: // // err = xlsx.AutoFilter("Sheet1", "A1", "D4", "") // @@ -170,15 +175,15 @@ func parseAutoFilterSet(formatSet string) *formatAutoFilter { // column defines the filter columns in a autofilter range based on simple // criteria // -// It isn't sufficient to just specify the filter condition. You must also hide -// any rows that don't match the filter condition. Rows are hidden using the -// SetRowVisible() method. Excelize can't filter rows automatically since this -// isn't part of the file format. +// It isn't sufficient to just specify the filter condition. You must also +// hide any rows that don't match the filter condition. Rows are hidden using +// the SetRowVisible() method. Excelize can't filter rows automatically since +// this isn't part of the file format. // // Setting a filter criteria for a column: // -// expression defines the conditions, the following operators are available for -// setting the filter criteria: +// expression defines the conditions, the following operators are available +// for setting the filter criteria: // // == // != @@ -189,8 +194,8 @@ func parseAutoFilterSet(formatSet string) *formatAutoFilter { // and // or // -// An expression can comprise a single statement or two statements separated by -// the and and or operators. For example: +// An expression can comprise a single statement or two statements separated +// by the 'and' and 'or' operators. For example: // // x < 2000 // x > 2000 diff --git a/xmlDrawing.go b/xmlDrawing.go index 600d83a..beb6bc9 100644 --- a/xmlDrawing.go +++ b/xmlDrawing.go @@ -360,6 +360,7 @@ type formatPicture struct { YScale float64 `json:"y_scale"` Hyperlink string `json:"hyperlink"` HyperlinkType string `json:"hyperlink_type"` + Positioning string `json:"positioning"` } // formatShape directly maps the format settings of the shape. diff --git a/xmlTable.go b/xmlTable.go index 610950b..b238350 100644 --- a/xmlTable.go +++ b/xmlTable.go @@ -186,6 +186,7 @@ type xlsxTableStyleInfo struct { // formatTable directly maps the format settings of the table. type formatTable struct { + TableName string `json:"table_name"` TableStyle string `json:"table_style"` ShowFirstColumn bool `json:"show_first_column"` ShowLastColumn bool `json:"show_last_column"` |