Introduce the new exported function `AddSlicer` for adding table slicer

- Fix a v2.8.0 regression bug, generate workbook corruption caused by incorrect MRU colors style parts
- Fix corrupted workbooks generated when adding tables in some cases
- Added several exported extension list child element URI constants
- Move part of the internal constant and variables definition to the template source code file
- Updated unit tests
This commit is contained in:
xuri 2023-09-16 12:21:11 +08:00
parent 5a039f3045
commit e3b7dad69a
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
25 changed files with 1464 additions and 340 deletions

View File

@ -499,10 +499,10 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
opts.Format.Locked = boolPtr(false)
}
if opts.Format.ScaleX == 0 {
opts.Format.ScaleX = defaultPictureScale
opts.Format.ScaleX = defaultDrawingScale
}
if opts.Format.ScaleY == 0 {
opts.Format.ScaleY = defaultPictureScale
opts.Format.ScaleY = defaultDrawingScale
}
if opts.Legend.Position == "" {
opts.Legend.Position = defaultChartLegendPosition

View File

@ -184,8 +184,8 @@ func TestAddChart(t *testing.T) {
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37", Sizes: "Sheet1!$B$37:$D$37"},
}
format := GraphicOptions{
ScaleX: defaultPictureScale,
ScaleY: defaultPictureScale,
ScaleX: defaultDrawingScale,
ScaleY: defaultDrawingScale,
OffsetX: 15,
OffsetY: 10,
PrintObject: boolPtr(true),
@ -369,8 +369,8 @@ func TestDeleteChart(t *testing.T) {
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37"},
}
format := GraphicOptions{
ScaleX: defaultPictureScale,
ScaleY: defaultPictureScale,
ScaleX: defaultDrawingScale,
ScaleY: defaultDrawingScale,
OffsetX: 15,
OffsetY: 10,
PrintObject: boolPtr(true),

View File

@ -1356,7 +1356,7 @@ func (f *File) addSheetDrawingChart(drawingXML string, rID int, opts *GraphicOpt
absoluteAnchor := xdrCellAnchor{
EditAs: opts.Positioning,
Pos: &xlsxPoint2D{},
Ext: &xlsxExt{},
Ext: &aExt{},
}
graphicFrame := xlsxGraphicFrame{

View File

@ -34,6 +34,12 @@ func newInvalidCellNameError(cell string) error {
return fmt.Errorf("invalid cell name %q", cell)
}
// newInvalidSlicerNameError defined the error message on receiving the invalid
// slicer name.
func newInvalidSlicerNameError(name string) error {
return fmt.Errorf("invalid slicer name %q", name)
}
// newInvalidExcelDateError defined the error message on receiving the data
// with negative values.
func newInvalidExcelDateError(dateValue float64) error {

42
lib.go
View File

@ -329,7 +329,7 @@ func (f *File) coordinatesToRangeRef(coordinates []int, abs ...bool) (string, er
}
// getDefinedNameRefTo convert defined name to reference range.
func (f *File) getDefinedNameRefTo(definedNameName string, currentSheet string) (refTo string) {
func (f *File) getDefinedNameRefTo(definedNameName, currentSheet string) (refTo string) {
var workbookRefTo, worksheetRefTo string
for _, definedName := range f.GetDefinedName() {
if definedName.Name == definedNameName {
@ -431,17 +431,17 @@ func float64Ptr(f float64) *float64 { return &f }
func stringPtr(s string) *string { return &s }
// Value extracts string data type text from a attribute value.
func (attr *attrValString) Value() string {
if attr != nil && attr.Val != nil {
return *attr.Val
func (avb *attrValString) Value() string {
if avb != nil && avb.Val != nil {
return *avb.Val
}
return ""
}
// Value extracts boolean data type value from a attribute value.
func (attr *attrValBool) Value() bool {
if attr != nil && attr.Val != nil {
return *attr.Val
func (avb *attrValBool) Value() bool {
if avb != nil && avb.Val != nil {
return *avb.Val
}
return false
}
@ -517,6 +517,34 @@ func (avb *attrValBool) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
return nil
}
// MarshalXML encodes ext element with specified namespace attributes on
// serialization.
func (ext xlsxExt) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Attr = ext.xmlns
return e.EncodeElement(decodeExt{URI: ext.URI, Content: ext.Content}, start)
}
// UnmarshalXML extracts ext element attributes namespace by giving XML decoder
// on deserialization.
func (ext *xlsxExt) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for _, attr := range start.Attr {
if attr.Name.Local == "uri" {
continue
}
if attr.Name.Space == "xmlns" {
attr.Name.Space = ""
attr.Name.Local = "xmlns:" + attr.Name.Local
}
ext.xmlns = append(ext.xmlns, attr)
}
e := &decodeExt{}
if err := d.DecodeElement(&e, &start); err != nil {
return err
}
ext.URI, ext.Content = e.URI, e.Content
return nil
}
// namespaceStrictToTransitional provides a method to convert Strict and
// Transitional namespaces.
func namespaceStrictToTransitional(content []byte) []byte {

View File

@ -274,6 +274,15 @@ func TestBoolValUnmarshalXML(t *testing.T) {
assert.EqualError(t, attr.UnmarshalXML(xml.NewDecoder(strings.NewReader("")), xml.StartElement{}), io.EOF.Error())
}
func TestExtUnmarshalXML(t *testing.T) {
f, extLst := NewFile(), decodeExtLst{}
expected := fmt.Sprintf(`<extLst><ext uri="%s" xmlns:x14="%s"/></extLst>`,
ExtURISlicerCachesX14, NameSpaceSpreadSheetX14.Value)
assert.NoError(t, f.xmlNewDecoder(strings.NewReader(expected)).Decode(&extLst))
assert.Len(t, extLst.Ext, 1)
assert.Equal(t, extLst.Ext[0].URI, ExtURISlicerCachesX14)
}
func TestBytesReplace(t *testing.T) {
s := []byte{0x01}
assert.EqualValues(t, s, bytesReplace(s, []byte{}, []byte{}, 0))

View File

@ -30,8 +30,8 @@ func parseGraphicOptions(opts *GraphicOptions) *GraphicOptions {
return &GraphicOptions{
PrintObject: boolPtr(true),
Locked: boolPtr(true),
ScaleX: defaultPictureScale,
ScaleY: defaultPictureScale,
ScaleX: defaultDrawingScale,
ScaleY: defaultDrawingScale,
}
}
if opts.PrintObject == nil {
@ -41,10 +41,10 @@ func parseGraphicOptions(opts *GraphicOptions) *GraphicOptions {
opts.Locked = boolPtr(true)
}
if opts.ScaleX == 0 {
opts.ScaleX = defaultPictureScale
opts.ScaleX = defaultDrawingScale
}
if opts.ScaleY == 0 {
opts.ScaleY = defaultPictureScale
opts.ScaleY = defaultDrawingScale
}
return opts
}
@ -440,6 +440,28 @@ func (f *File) addMedia(file []byte, ext string) string {
return media
}
// setContentTypePartRelsExtensions provides a function to set the content
// type for relationship parts and the Main Document part.
func (f *File) setContentTypePartRelsExtensions() error {
var rels bool
content, err := f.contentTypesReader()
if err != nil {
return err
}
for _, v := range content.Defaults {
if v.Extension == "rels" {
rels = true
}
}
if !rels {
content.Defaults = append(content.Defaults, xlsxDefault{
Extension: "rels",
ContentType: ContentTypeRelationships,
})
}
return err
}
// setContentTypePartImageExtensions provides a function to set the content
// type for relationship parts and the Main Document part.
func (f *File) setContentTypePartImageExtensions() error {
@ -542,7 +564,7 @@ func (f *File) addContentTypePart(index int, contentType string) error {
PartName: partNames[contentType],
ContentType: contentTypes[contentType],
})
return err
return f.setContentTypePartRelsExtensions()
}
// getSheetRelationshipsTargetByID provides a function to get Target attribute

View File

@ -269,6 +269,17 @@ func TestDrawingResize(t *testing.T) {
assert.EqualError(t, f.AddPicture("Sheet1", "A1", filepath.Join("test", "images", "excel.jpg"), &GraphicOptions{AutoFit: true}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
}
func TestSetContentTypePartRelsExtensions(t *testing.T) {
f := NewFile()
f.ContentTypes = &xlsxTypes{}
assert.NoError(t, f.setContentTypePartRelsExtensions())
// Test set content type part relationships extensions with unsupported charset content types
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, f.setContentTypePartRelsExtensions(), "XML syntax error on line 1: invalid UTF-8")
}
func TestSetContentTypePartImageExtensions(t *testing.T) {
f := NewFile()
// Test set content type part image extensions with unsupported charset content types

View File

@ -89,9 +89,9 @@ type PivotTableField struct {
// options. Note that the same fields can not in Columns, Rows and Filter
// fields at the same time.
//
// For example, create a pivot table on the range reference Sheet1!$G$2:$M$34
// with the range reference Sheet1!$A$1:$E$31 as the data source, summarize by
// sum for sales:
// For example, create a pivot table on the range reference Sheet1!G2:M34 with
// the range reference Sheet1!A1:E31 as the data source, summarize by sum for
// sales:
//
// package main
//
@ -242,15 +242,15 @@ func (f *File) adjustRange(rangeStr string) (string, []int, error) {
return rng[0], []int{x1, y1, x2, y2}, nil
}
// getPivotFieldsOrder provides a function to get order list of pivot table
// getTableFieldsOrder provides a function to get order list of pivot table
// fields.
func (f *File) getPivotFieldsOrder(opts *PivotTableOptions) ([]string, error) {
func (f *File) getTableFieldsOrder(sheetName, dataRange string) ([]string, error) {
var order []string
dataRange := f.getDefinedNameRefTo(opts.DataRange, opts.pivotTableSheetName)
if dataRange == "" {
dataRange = opts.DataRange
ref := f.getDefinedNameRefTo(dataRange, sheetName)
if ref == "" {
ref = dataRange
}
dataSheet, coordinates, err := f.adjustRange(dataRange)
dataSheet, coordinates, err := f.adjustRange(ref)
if err != nil {
return order, fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
}
@ -279,7 +279,7 @@ func (f *File) addPivotCache(pivotCacheXML string, opts *PivotTableOptions) erro
return fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
}
// data range has been checked
order, _ := f.getPivotFieldsOrder(opts)
order, _ := f.getTableFieldsOrder(opts.pivotTableSheetName, opts.DataRange)
hCell, _ := CoordinatesToCellName(coordinates[0], coordinates[1])
vCell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
pc := xlsxPivotCacheDefinition{
@ -541,7 +541,7 @@ func (f *File) addPivotColFields(pt *xlsxPivotTableDefinition, opts *PivotTableO
// addPivotFields create pivot fields based on the column order of the first
// row in the data region by given pivot table definition and option.
func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error {
order, err := f.getPivotFieldsOrder(opts)
order, err := f.getTableFieldsOrder(opts.pivotTableSheetName, opts.DataRange)
if err != nil {
return err
}
@ -647,7 +647,7 @@ func (f *File) countPivotCache() int {
// to a sequential index by given fields and pivot option.
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opts *PivotTableOptions) ([]int, error) {
var pivotFieldsIndex []int
orders, err := f.getPivotFieldsOrder(opts)
orders, err := f.getTableFieldsOrder(opts.pivotTableSheetName, opts.DataRange)
if err != nil {
return pivotFieldsIndex, err
}
@ -809,7 +809,7 @@ func (f *File) getPivotTable(sheet, pivotTableXML, pivotCacheRels string) (Pivot
opts.ShowLastColumn = si.ShowLastColumn
opts.PivotTableStyleName = si.Name
}
order, _ := f.getPivotFieldsOrder(&PivotTableOptions{DataRange: dataRange, pivotTableSheetName: pt.Name})
order, _ := f.getTableFieldsOrder(pt.Name, dataRange)
f.extractPivotTableFields(order, pt, &opts)
return opts, err
}

View File

@ -257,8 +257,8 @@ func TestPivotTable(t *testing.T) {
// Test adjust range with incorrect range
_, _, err = f.adjustRange("sheet1!")
assert.EqualError(t, err, "parameter is invalid")
// Test get pivot fields order with empty data range
_, err = f.getPivotFieldsOrder(&PivotTableOptions{})
// Test get table fields order with empty data range
_, err = f.getTableFieldsOrder("", "")
assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
// Test add pivot cache with empty data range
assert.EqualError(t, f.addPivotCache("", &PivotTableOptions{}), "parameter 'DataRange' parsing error: parameter is required")
@ -367,8 +367,8 @@ func TestAddPivotColFields(t *testing.T) {
func TestGetPivotFieldsOrder(t *testing.T) {
f := NewFile()
// Test get pivot fields order with not exist worksheet
_, err := f.getPivotFieldsOrder(&PivotTableOptions{DataRange: "SheetN!A1:E31"})
// Test get table fields order with not exist worksheet
_, err := f.getTableFieldsOrder("", "SheetN!A1:E31")
assert.EqualError(t, err, "sheet SheetN does not exist")
}

View File

@ -708,7 +708,7 @@ func (f *File) duplicateMergeCells(sheet string, ws *xlsxWorksheet, row, row2 in
// checkRow provides a function to check and fill each column element for all
// rows and make that is continuous in a worksheet of XML. For example:
//
// <row r="15" spans="1:22" x14ac:dyDescent="0.2">
// <row r="15">
// <c r="A15" s="2" />
// <c r="B15" s="2" />
// <c r="F15" s="1" />
@ -717,7 +717,7 @@ func (f *File) duplicateMergeCells(sheet string, ws *xlsxWorksheet, row, row2 in
//
// in this case, we should to change it to
//
// <row r="15" spans="1:22" x14ac:dyDescent="0.2">
// <row r="15">
// <c r="A15" s="2" />
// <c r="B15" s="2" />
// <c r="C15" s="2" />

View File

@ -38,10 +38,10 @@ func parseShapeOptions(opts *Shape) (*Shape, error) {
opts.Format.Locked = boolPtr(false)
}
if opts.Format.ScaleX == 0 {
opts.Format.ScaleX = defaultPictureScale
opts.Format.ScaleX = defaultDrawingScale
}
if opts.Format.ScaleY == 0 {
opts.Format.ScaleY = defaultPictureScale
opts.Format.ScaleY = defaultDrawingScale
}
if opts.Line.Width == nil {
opts.Line.Width = float64Ptr(defaultShapeLineWidth)
@ -322,29 +322,27 @@ func (f *File) AddShape(sheet string, opts *Shape) error {
return f.addContentTypePart(drawingID, "drawings")
}
// addDrawingShape provides a function to add preset geometry by given sheet,
// drawingXMLand format sets.
func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *Shape) error {
// twoCellAnchorShape create a two cell anchor shape size placeholder for a
// group, a shape, or a drawing element.
func (f *File) twoCellAnchorShape(sheet, drawingXML, cell string, width, height uint, format GraphicOptions) (*xlsxWsDr, *xdrCellAnchor, int, error) {
fromCol, fromRow, err := CellNameToCoordinates(cell)
if err != nil {
return err
return nil, nil, 0, err
}
width := int(float64(opts.Width) * opts.Format.ScaleX)
height := int(float64(opts.Height) * opts.Format.ScaleY)
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, fromCol, fromRow, opts.Format.OffsetX, opts.Format.OffsetY,
width, height)
w := int(float64(width) * format.ScaleX)
h := int(float64(height) * format.ScaleY)
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, fromCol, fromRow, format.OffsetX, format.OffsetY, w, h)
content, cNvPrID, err := f.drawingParser(drawingXML)
if err != nil {
return err
return content, nil, cNvPrID, err
}
twoCellAnchor := xdrCellAnchor{}
twoCellAnchor.EditAs = opts.Format.Positioning
twoCellAnchor.EditAs = format.Positioning
from := xlsxFrom{}
from.Col = colStart
from.ColOff = opts.Format.OffsetX * EMU
from.ColOff = format.OffsetX * EMU
from.Row = rowStart
from.RowOff = opts.Format.OffsetY * EMU
from.RowOff = format.OffsetY * EMU
to := xlsxTo{}
to.Col = colEnd
to.ColOff = x2 * EMU
@ -352,6 +350,17 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *Shape) erro
to.RowOff = y2 * EMU
twoCellAnchor.From = &from
twoCellAnchor.To = &to
return content, &twoCellAnchor, cNvPrID, err
}
// addDrawingShape provides a function to add preset geometry by given sheet,
// drawingXML and format sets.
func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *Shape) error {
content, twoCellAnchor, cNvPrID, err := f.twoCellAnchorShape(
sheet, drawingXML, cell, opts.Width, opts.Height, opts.Format)
if err != nil {
return err
}
var solidColor string
if len(opts.Fill.Color) == 1 {
solidColor = opts.Fill.Color[0]
@ -462,7 +471,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *Shape) erro
FLocksWithSheet: *opts.Format.Locked,
FPrintsWithSheet: *opts.Format.PrintObject,
}
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
content.TwoCellAnchor = append(content.TwoCellAnchor, twoCellAnchor)
f.Drawings.Store(drawingXML, content)
return err
}

551
slicer.go Normal file
View File

@ -0,0 +1,551 @@
// Copyright 2016 - 2023 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 XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and
// writing spreadsheet documents generated by Microsoft Excel™ 2007 and later.
// Supports complex components by high compatibility, and provided streaming
// API for generating or reading data from a worksheet with huge amounts of
// data. This library needs Go version 1.16 or later.
package excelize
import (
"bytes"
"encoding/xml"
"fmt"
"io"
"sort"
"strconv"
"strings"
"unicode"
)
// SlicerOptions represents the settings of the slicer.
//
// Name specifies the slicer name, should be an existing field name of the given
// table or pivot table, this setting is required.
//
// Table specifies the name of the table or pivot table, this setting is
// required.
//
// Cell specifies the left top cell coordinates the position for inserting the
// slicer, this setting is required.
//
// Caption specifies the caption of the slicer, this setting is optional.
//
// Macro used for set macro for the slicer, the workbook extension should be
// XLSM or XLTM
//
// Width specifies the width of the slicer, this setting is optional.
//
// Height specifies the height of the slicer, this setting is optional.
//
// DisplayHeader specifies if display header of the slicer, this setting is
// optional, the default setting is display.
//
// ItemDesc specifies descending (Z-A) item sorting, this setting is optional,
// and the default setting is false (represents ascending).
//
// Format specifies the format of the slicer, this setting is optional.
type SlicerOptions struct {
Name string
Table string
Cell string
Caption string
Macro string
Width uint
Height uint
DisplayHeader *bool
ItemDesc bool
Format GraphicOptions
}
// AddSlicer function inserts a slicer by giving the worksheet name and slicer
// settings. The pivot table slicer is not supported currently.
//
// For example, insert a slicer on the Sheet1!E1 with field Column1 for the
// table named Table1:
//
// err := f.AddSlicer("Sheet1", &excelize.SlicerOptions{
// Name: "Column1",
// Table: "Table1",
// Cell: "E1",
// Caption: "Column1",
// Width: 200,
// Height: 200,
// })
func (f *File) AddSlicer(sheet string, opts *SlicerOptions) error {
opts, err := parseSlicerOptions(opts)
if err != nil {
return err
}
table, colIdx, err := f.getSlicerSource(sheet, opts)
if err != nil {
return err
}
slicerID, err := f.addSheetSlicer(sheet)
if err != nil {
return err
}
slicerCacheName, err := f.setSlicerCache(colIdx, opts, table)
if err != nil {
return err
}
slicerName, err := f.addDrawingSlicer(sheet, opts)
if err != nil {
return err
}
return f.addSlicer(slicerID, xlsxSlicer{
Name: slicerName,
Cache: slicerCacheName,
Caption: opts.Caption,
ShowCaption: opts.DisplayHeader,
RowHeight: 251883,
})
}
// parseSlicerOptions provides a function to parse the format settings of the
// slicer with default value.
func parseSlicerOptions(opts *SlicerOptions) (*SlicerOptions, error) {
if opts == nil {
return nil, ErrParameterRequired
}
if opts.Name == "" || opts.Table == "" || opts.Cell == "" {
return nil, ErrParameterInvalid
}
if opts.Width == 0 {
opts.Width = defaultSlicerWidth
}
if opts.Height == 0 {
opts.Height = defaultSlicerHeight
}
if opts.Format.PrintObject == nil {
opts.Format.PrintObject = boolPtr(true)
}
if opts.Format.Locked == nil {
opts.Format.Locked = boolPtr(false)
}
if opts.Format.ScaleX == 0 {
opts.Format.ScaleX = defaultDrawingScale
}
if opts.Format.ScaleY == 0 {
opts.Format.ScaleY = defaultDrawingScale
}
return opts, nil
}
// countSlicers provides a function to get slicer files count storage in the
// folder xl/slicers.
func (f *File) countSlicers() int {
count := 0
f.Pkg.Range(func(k, v interface{}) bool {
if strings.Contains(k.(string), "xl/slicers/slicer") {
count++
}
return true
})
return count
}
// countSlicerCache provides a function to get slicer cache files count storage
// in the folder xl/SlicerCaches.
func (f *File) countSlicerCache() int {
count := 0
f.Pkg.Range(func(k, v interface{}) bool {
if strings.Contains(k.(string), "xl/slicerCaches/slicerCache") {
count++
}
return true
})
return count
}
// getSlicerSource returns the slicer data source table or pivot table settings
// and the index of the given slicer fields in the table or pivot table
// column.
func (f *File) getSlicerSource(sheet string, opts *SlicerOptions) (*Table, int, error) {
var (
table *Table
colIdx int
tables, err = f.GetTables(sheet)
)
if err != nil {
return table, colIdx, err
}
for _, tbl := range tables {
if tbl.Name == opts.Table {
table = &tbl
break
}
}
if table == nil {
return table, colIdx, newNoExistTableError(opts.Table)
}
order, _ := f.getTableFieldsOrder(sheet, fmt.Sprintf("%s!%s", sheet, table.Range))
if colIdx = inStrSlice(order, opts.Name, true); colIdx == -1 {
return table, colIdx, newInvalidSlicerNameError(opts.Name)
}
return table, colIdx, err
}
// addSheetSlicer adds a new slicer and updates the namespace and relationships
// parts of the worksheet by giving the worksheet name.
func (f *File) addSheetSlicer(sheet string) (int, error) {
var (
slicerID = f.countSlicers() + 1
ws, err = f.workSheetReader(sheet)
decodeExtLst = new(decodeExtLst)
slicerList = new(decodeSlicerList)
)
if err != nil {
return slicerID, err
}
if ws.ExtLst != nil {
if err = f.xmlNewDecoder(strings.NewReader("<extLst>" + ws.ExtLst.Ext + "</extLst>")).
Decode(decodeExtLst); err != nil && err != io.EOF {
return slicerID, err
}
for _, ext := range decodeExtLst.Ext {
if ext.URI == ExtURISlicerListX15 {
_ = f.xmlNewDecoder(strings.NewReader(ext.Content)).Decode(slicerList)
for _, slicer := range slicerList.Slicer {
if slicer.RID != "" {
sheetRelationshipsDrawingXML := f.getSheetRelationshipsTargetByID(sheet, slicer.RID)
slicerID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../slicers/slicer"), ".xml"))
return slicerID, err
}
}
}
}
}
sheetRelationshipsSlicerXML := "../slicers/slicer" + strconv.Itoa(slicerID) + ".xml"
sheetXMLPath, _ := f.getSheetXMLPath(sheet)
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
rID := f.addRels(sheetRels, SourceRelationshipSlicer, sheetRelationshipsSlicerXML, "")
f.addSheetNameSpace(sheet, NameSpaceSpreadSheetX14)
return slicerID, f.addSheetTableSlicer(ws, rID)
}
// addSheetTableSlicer adds a new table slicer for the worksheet by giving the
// worksheet relationships ID.
func (f *File) addSheetTableSlicer(ws *xlsxWorksheet, rID int) error {
var (
decodeExtLst = new(decodeExtLst)
err error
slicerListBytes, extLstBytes []byte
)
if ws.ExtLst != nil {
if err = f.xmlNewDecoder(strings.NewReader("<extLst>" + ws.ExtLst.Ext + "</extLst>")).
Decode(decodeExtLst); err != nil && err != io.EOF {
return err
}
}
slicerListBytes, _ = xml.Marshal(&xlsxX14SlicerList{
Slicer: []*xlsxX14Slicer{{RID: "rId" + strconv.Itoa(rID)}},
})
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxExt{
xmlns: []xml.Attr{{Name: xml.Name{Local: "xmlns:" + NameSpaceSpreadSheetX15.Name.Local}, Value: NameSpaceSpreadSheetX15.Value}},
URI: ExtURISlicerListX15, Content: string(slicerListBytes),
})
sort.Slice(decodeExtLst.Ext, func(i, j int) bool {
return inStrSlice(extensionURIPriority, decodeExtLst.Ext[i].URI, false) <
inStrSlice(extensionURIPriority, decodeExtLst.Ext[j].URI, false)
})
extLstBytes, err = xml.Marshal(decodeExtLst)
ws.ExtLst = &xlsxExtLst{Ext: strings.TrimSuffix(strings.TrimPrefix(string(extLstBytes), "<extLst>"), "</extLst>")}
return err
}
// addSlicer adds a new slicer to the workbook by giving the slicer ID and
// settings.
func (f *File) addSlicer(slicerID int, slicer xlsxSlicer) error {
slicerXML := "xl/slicers/slicer" + strconv.Itoa(slicerID) + ".xml"
slicers, err := f.slicerReader(slicerXML)
if err != nil {
return err
}
if err := f.addContentTypePart(slicerID, "slicer"); err != nil {
return err
}
slicers.Slicer = append(slicers.Slicer, slicer)
output, err := xml.Marshal(slicers)
f.saveFileList(slicerXML, output)
return err
}
// genSlicerNames generates a unique slicer cache name by giving the slicer name.
func (f *File) genSlicerCacheName(name string) string {
var (
cnt int
definedNames []string
slicerCacheName string
)
for _, dn := range f.GetDefinedName() {
if dn.Scope == "Workbook" {
definedNames = append(definedNames, dn.Name)
}
}
for i, c := range name {
if unicode.IsLetter(c) {
slicerCacheName += string(c)
continue
}
if i > 0 && (unicode.IsDigit(c) || c == '.') {
slicerCacheName += string(c)
continue
}
slicerCacheName += "_"
}
slicerCacheName = fmt.Sprintf("Slicer_%s", slicerCacheName)
for {
tmp := slicerCacheName
if cnt > 0 {
tmp = fmt.Sprintf("%s%d", slicerCacheName, cnt)
}
if inStrSlice(definedNames, tmp, true) == -1 {
slicerCacheName = tmp
break
}
cnt++
}
return slicerCacheName
}
// setSlicerCache check if a slicer cache already exists or add a new slicer
// cache by giving the column index, slicer, table options, and returns the
// slicer cache name.
func (f *File) setSlicerCache(colIdx int, opts *SlicerOptions, table *Table) (string, error) {
var ok bool
var slicerCacheName string
f.Pkg.Range(func(k, v interface{}) bool {
if strings.Contains(k.(string), "xl/slicerCaches/slicerCache") {
slicerCache := &xlsxSlicerCacheDefinition{}
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(v.([]byte)))).
Decode(slicerCache); err != nil && err != io.EOF {
return true
}
if slicerCache.ExtLst == nil {
return true
}
ext := new(xlsxExt)
_ = f.xmlNewDecoder(strings.NewReader(slicerCache.ExtLst.Ext)).Decode(ext)
if ext.URI == ExtURISlicerCacheDefinition {
tableSlicerCache := new(decodeTableSlicerCache)
_ = f.xmlNewDecoder(strings.NewReader(ext.Content)).Decode(tableSlicerCache)
if tableSlicerCache.TableID == table.tID && tableSlicerCache.Column == colIdx+1 {
ok, slicerCacheName = true, slicerCache.Name
return false
}
}
}
return true
})
if ok {
return slicerCacheName, nil
}
slicerCacheName = f.genSlicerCacheName(opts.Name)
return slicerCacheName, f.addSlicerCache(slicerCacheName, colIdx, opts, table)
}
// slicerReader provides a function to get the pointer to the structure
// after deserialization of xl/slicers/slicer%d.xml.
func (f *File) slicerReader(slicerXML string) (*xlsxSlicers, error) {
content, ok := f.Pkg.Load(slicerXML)
slicer := &xlsxSlicers{
XMLNSXMC: SourceRelationshipCompatibility.Value,
XMLNSX: NameSpaceSpreadSheet.Value,
XMLNSXR10: NameSpaceSpreadSheetXR10.Value,
}
if ok && content != nil {
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(content.([]byte)))).
Decode(slicer); err != nil && err != io.EOF {
return nil, err
}
}
return slicer, nil
}
// addSlicerCache adds a new slicer cache by giving the slicer cache name,
// column index, slicer, and table options.
func (f *File) addSlicerCache(slicerCacheName string, colIdx int, opts *SlicerOptions, table *Table) error {
var (
slicerCacheBytes, tableSlicerBytes, extLstBytes []byte
slicerCacheID = f.countSlicerCache() + 1
decodeExtLst = new(decodeExtLst)
slicerCache = xlsxSlicerCacheDefinition{
XMLNSXMC: SourceRelationshipCompatibility.Value,
XMLNSX: NameSpaceSpreadSheet.Value,
XMLNSX15: NameSpaceSpreadSheetX15.Value,
XMLNSXR10: NameSpaceSpreadSheetXR10.Value,
Name: slicerCacheName,
SourceName: opts.Name,
ExtLst: &xlsxExtLst{},
}
)
var sortOrder string
if opts.ItemDesc {
sortOrder = "descending"
}
tableSlicerBytes, _ = xml.Marshal(&xlsxTableSlicerCache{
TableID: table.tID,
Column: colIdx + 1,
SortOrder: sortOrder,
})
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxExt{
xmlns: []xml.Attr{{Name: xml.Name{Local: "xmlns:" + NameSpaceSpreadSheetX15.Name.Local}, Value: NameSpaceSpreadSheetX15.Value}},
URI: ExtURISlicerCacheDefinition, Content: string(tableSlicerBytes),
})
extLstBytes, _ = xml.Marshal(decodeExtLst)
slicerCache.ExtLst = &xlsxExtLst{Ext: strings.TrimSuffix(strings.TrimPrefix(string(extLstBytes), "<extLst>"), "</extLst>")}
slicerCacheXML := "xl/slicerCaches/slicerCache" + strconv.Itoa(slicerCacheID) + ".xml"
slicerCacheBytes, _ = xml.Marshal(slicerCache)
f.saveFileList(slicerCacheXML, slicerCacheBytes)
if err := f.addContentTypePart(slicerCacheID, "slicerCache"); err != nil {
return err
}
if err := f.addWorkbookSlicerCache(slicerCacheID, ExtURISlicerCachesX15); err != nil {
return err
}
return f.SetDefinedName(&DefinedName{Name: slicerCacheName, RefersTo: formulaErrorNA})
}
// addDrawingSlicer adds a slicer shape and fallback shape by giving the
// worksheet name, slicer options, and returns slicer name.
func (f *File) addDrawingSlicer(sheet string, opts *SlicerOptions) (string, error) {
var slicerName string
drawingID := f.countDrawings() + 1
drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
ws, err := f.workSheetReader(sheet)
if err != nil {
return slicerName, err
}
drawingID, drawingXML = f.prepareDrawing(ws, drawingID, sheet, drawingXML)
content, twoCellAnchor, cNvPrID, err := f.twoCellAnchorShape(sheet, drawingXML, opts.Cell, opts.Width, opts.Height, opts.Format)
if err != nil {
return slicerName, err
}
slicerName = fmt.Sprintf("%s %d", opts.Name, cNvPrID)
graphicFrame := xlsxGraphicFrame{
NvGraphicFramePr: xlsxNvGraphicFramePr{
CNvPr: &xlsxCNvPr{
ID: cNvPrID,
Name: slicerName,
},
},
Xfrm: xlsxXfrm{Off: xlsxOff{}, Ext: aExt{}},
Graphic: &xlsxGraphic{
GraphicData: &xlsxGraphicData{
URI: NameSpaceDrawingMLSlicer.Value,
Sle: &xlsxSle{XMLNS: NameSpaceDrawingMLSlicer.Value, Name: slicerName},
},
},
}
graphic, _ := xml.Marshal(graphicFrame)
sp := xdrSp{
Macro: opts.Macro,
NvSpPr: &xdrNvSpPr{
CNvPr: &xlsxCNvPr{
ID: cNvPrID,
},
CNvSpPr: &xdrCNvSpPr{
TxBox: true,
},
},
SpPr: &xlsxSpPr{
Xfrm: xlsxXfrm{Off: xlsxOff{X: 2914650, Y: 152400}, Ext: aExt{Cx: 1828800, Cy: 2238375}},
SolidFill: &xlsxInnerXML{Content: "<a:prstClr val=\"white\"/>"},
PrstGeom: xlsxPrstGeom{
Prst: "rect",
},
Ln: xlsxLineProperties{W: 1, SolidFill: &xlsxInnerXML{Content: "<a:prstClr val=\"black\"/>"}},
},
TxBody: &xdrTxBody{
BodyPr: &aBodyPr{VertOverflow: "clip", HorzOverflow: "clip"},
P: []*aP{
{R: &aR{T: "This shape represents a table slicer. Table slicers are not supported in this version of Excel."}},
{R: &aR{T: "If the shape was modified in an earlier version of Excel, or if the workbook was saved in Excel 2007 or earlier, the slicer can't be used."}},
},
},
}
shape, _ := xml.Marshal(sp)
twoCellAnchor.ClientData = &xdrClientData{
FLocksWithSheet: *opts.Format.Locked,
FPrintsWithSheet: *opts.Format.PrintObject,
}
choice := xlsxChoice{
XMLNSSle15: NameSpaceDrawingMLSlicerX15.Value,
Requires: NameSpaceDrawingMLSlicerX15.Name.Local,
Content: string(graphic),
}
fallback := xlsxFallback{
Content: string(shape),
}
choiceBytes, _ := xml.Marshal(choice)
shapeBytes, _ := xml.Marshal(fallback)
twoCellAnchor.AlternateContent = append(twoCellAnchor.AlternateContent, &xlsxAlternateContent{
XMLNSMC: SourceRelationshipCompatibility.Value,
Content: string(choiceBytes) + string(shapeBytes),
})
content.TwoCellAnchor = append(content.TwoCellAnchor, twoCellAnchor)
f.Drawings.Store(drawingXML, content)
return slicerName, f.addContentTypePart(drawingID, "drawings")
}
// addWorkbookSlicerCache add the association ID of the slicer cache in
// workbook.xml.
func (f *File) addWorkbookSlicerCache(slicerCacheID int, URI string) error {
var (
wb *xlsxWorkbook
err error
idx int
appendMode bool
decodeExtLst = new(decodeExtLst)
decodeSlicerCaches *decodeX15SlicerCaches
x15SlicerCaches = new(xlsxX15SlicerCaches)
ext *xlsxExt
slicerCacheBytes, slicerCachesBytes, extLstBytes []byte
)
if wb, err = f.workbookReader(); err != nil {
return err
}
rID := f.addRels(f.getWorkbookRelsPath(), SourceRelationshipSlicerCache, fmt.Sprintf("/xl/slicerCaches/slicerCache%d.xml", slicerCacheID), "")
if wb.ExtLst != nil { // append mode ext
if err = f.xmlNewDecoder(strings.NewReader("<extLst>" + wb.ExtLst.Ext + "</extLst>")).
Decode(decodeExtLst); err != nil && err != io.EOF {
return err
}
for idx, ext = range decodeExtLst.Ext {
if ext.URI == URI {
if URI == ExtURISlicerCachesX15 {
decodeSlicerCaches = new(decodeX15SlicerCaches)
_ = f.xmlNewDecoder(strings.NewReader(ext.Content)).Decode(decodeSlicerCaches)
slicerCache := xlsxX14SlicerCache{RID: fmt.Sprintf("rId%d", rID)}
slicerCacheBytes, _ = xml.Marshal(slicerCache)
x15SlicerCaches.Content = decodeSlicerCaches.Content + string(slicerCacheBytes)
x15SlicerCaches.XMLNS = NameSpaceSpreadSheetX14.Value
slicerCachesBytes, _ = xml.Marshal(x15SlicerCaches)
decodeExtLst.Ext[idx].Content = string(slicerCachesBytes)
appendMode = true
}
}
}
}
if !appendMode {
if URI == ExtURISlicerCachesX15 {
slicerCache := xlsxX14SlicerCache{RID: fmt.Sprintf("rId%d", rID)}
slicerCacheBytes, _ = xml.Marshal(slicerCache)
x15SlicerCaches.Content = string(slicerCacheBytes)
x15SlicerCaches.XMLNS = NameSpaceSpreadSheetX14.Value
slicerCachesBytes, _ = xml.Marshal(x15SlicerCaches)
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxExt{
xmlns: []xml.Attr{{Name: xml.Name{Local: "xmlns:" + NameSpaceSpreadSheetX15.Name.Local}, Value: NameSpaceSpreadSheetX15.Value}},
URI: ExtURISlicerCachesX15, Content: string(slicerCachesBytes),
})
}
}
extLstBytes, err = xml.Marshal(decodeExtLst)
wb.ExtLst = &xlsxExtLst{Ext: strings.TrimSuffix(strings.TrimPrefix(string(extLstBytes), "<extLst>"), "</extLst>")}
return err
}

247
slicer_test.go Normal file
View File

@ -0,0 +1,247 @@
package excelize
import (
"fmt"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestAddSlicer(t *testing.T) {
f := NewFile()
disable, colName := false, "_!@#$%^&*()-+=|\\/<>"
assert.NoError(t, f.SetCellValue("Sheet1", "B1", colName))
// Create table in a worksheet
assert.NoError(t, f.AddTable("Sheet1", &Table{
Name: "Table1",
Range: "A1:D5",
}))
assert.NoError(t, f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column1",
Table: "Table1",
Cell: "E1",
Caption: "Column1",
}))
assert.NoError(t, f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column1",
Table: "Table1",
Cell: "I1",
Caption: "Column1",
}))
assert.NoError(t, f.AddSlicer("Sheet1", &SlicerOptions{
Name: colName,
Table: "Table1",
Cell: "M1",
Caption: colName,
Macro: "Button1_Click",
Width: 200,
Height: 200,
DisplayHeader: &disable,
ItemDesc: true,
}))
// Test add a table slicer with empty slicer options
assert.Equal(t, ErrParameterRequired, f.AddSlicer("Sheet1", nil))
// Test add a table slicer with invalid slicer options
for _, opts := range []*SlicerOptions{
{Table: "Table1", Cell: "Q1"},
{Name: "Column", Cell: "Q1"},
{Name: "Column", Table: "Table1"},
} {
assert.Equal(t, ErrParameterInvalid, f.AddSlicer("Sheet1", opts))
}
// Test add a table slicer with not exist worksheet
assert.EqualError(t, f.AddSlicer("SheetN", &SlicerOptions{
Name: "Column2",
Table: "Table1",
Cell: "Q1",
}), "sheet SheetN does not exist")
// Test add a table slicer with not exist table name
assert.Equal(t, newNoExistTableError("Table2"), f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column2",
Table: "Table2",
Cell: "Q1",
}))
// Test add a table slicer with invalid slicer name
assert.Equal(t, newInvalidSlicerNameError("Column6"), f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column6",
Table: "Table1",
Cell: "Q1",
}))
file, err := os.ReadFile(filepath.Join("test", "vbaProject.bin"))
assert.NoError(t, err)
assert.NoError(t, f.AddVBAProject(file))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddSlicer.xlsm")))
assert.NoError(t, f.Close())
// Test add a table slicer with invalid worksheet extension list
f = NewFile()
assert.NoError(t, f.AddTable("Sheet1", &Table{
Name: "Table1",
Range: "A1:D5",
}))
ws, ok := f.Sheet.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
ws.(*xlsxWorksheet).ExtLst = &xlsxExtLst{Ext: "<>"}
assert.Error(t, f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column1",
Table: "Table1",
Cell: "E1",
}))
assert.NoError(t, f.Close())
// Test add a table slicer with unsupported charset slicer
f = NewFile()
assert.NoError(t, f.AddTable("Sheet1", &Table{
Name: "Table1",
Range: "A1:D5",
}))
f.Pkg.Store("xl/slicers/slicer2.xml", MacintoshCyrillicCharset)
assert.EqualError(t, f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column1",
Table: "Table1",
Cell: "E1",
}), "XML syntax error on line 1: invalid UTF-8")
assert.NoError(t, f.Close())
// Test add a table slicer with read workbook error
f = NewFile()
assert.NoError(t, f.AddTable("Sheet1", &Table{
Name: "Table1",
Range: "A1:D5",
}))
f.WorkBook.ExtLst = &xlsxExtLst{Ext: "<>"}
assert.Error(t, f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column1",
Table: "Table1",
Cell: "E1",
}))
assert.NoError(t, f.Close())
// Test add a table slicer with unsupported charset content types
f = NewFile()
assert.NoError(t, f.AddTable("Sheet1", &Table{
Name: "Table1",
Range: "A1:D5",
}))
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column1",
Table: "Table1",
Cell: "E1",
}), "XML syntax error on line 1: invalid UTF-8")
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, f.addSlicer(0, xlsxSlicer{}), "XML syntax error on line 1: invalid UTF-8")
assert.NoError(t, f.Close())
f = NewFile()
// Create table in a worksheet
assert.NoError(t, f.AddTable("Sheet1", &Table{
Name: "Table1",
Range: "A1:D5",
}))
f.Pkg.Store("xl/drawings/drawing2.xml", MacintoshCyrillicCharset)
assert.EqualError(t, f.AddSlicer("Sheet1", &SlicerOptions{
Name: "Column1",
Table: "Table1",
Cell: "E1",
Caption: "Column1",
}), "XML syntax error on line 1: invalid UTF-8")
assert.NoError(t, f.Close())
}
func TestAddSheetSlicer(t *testing.T) {
f := NewFile()
// Test add sheet slicer with not exist worksheet name
_, err := f.addSheetSlicer("SheetN")
assert.EqualError(t, err, "sheet SheetN does not exist")
assert.NoError(t, f.Close())
}
func TestAddSheetTableSlicer(t *testing.T) {
f := NewFile()
// Test add sheet table slicer with invalid worksheet extension
assert.Error(t, f.addSheetTableSlicer(&xlsxWorksheet{ExtLst: &xlsxExtLst{Ext: "<>"}}, 0))
// Test add sheet table slicer with existing worksheet extension
assert.NoError(t, f.addSheetTableSlicer(&xlsxWorksheet{ExtLst: &xlsxExtLst{Ext: fmt.Sprintf("<ext uri=\"%s\"></ext>", ExtURITimelineRefs)}}, 1))
assert.NoError(t, f.Close())
}
func TestSetSlicerCache(t *testing.T) {
f := NewFile()
f.Pkg.Store("xl/slicerCaches/slicerCache1.xml", MacintoshCyrillicCharset)
_, err := f.setSlicerCache(1, &SlicerOptions{}, &Table{})
assert.NoError(t, err)
assert.NoError(t, f.Close())
f = NewFile()
f.Pkg.Store("xl/slicerCaches/slicerCache2.xml", []byte(fmt.Sprintf(`<slicerCacheDefinition xmlns="%s" name="Slicer2" sourceName="B1"><extLst><ext uri="%s"/></extLst></slicerCacheDefinition>`, NameSpaceSpreadSheetX14.Value, ExtURISlicerCacheDefinition)))
_, err = f.setSlicerCache(1, &SlicerOptions{}, &Table{})
assert.NoError(t, err)
assert.NoError(t, f.Close())
f = NewFile()
f.Pkg.Store("xl/slicerCaches/slicerCache2.xml", []byte(fmt.Sprintf(`<slicerCacheDefinition xmlns="%s" name="Slicer1" sourceName="B1"><extLst><ext uri="%s"/></extLst></slicerCacheDefinition>`, NameSpaceSpreadSheetX14.Value, ExtURISlicerCacheDefinition)))
_, err = f.setSlicerCache(1, &SlicerOptions{}, &Table{})
assert.NoError(t, err)
assert.NoError(t, f.Close())
f = NewFile()
f.Pkg.Store("xl/slicerCaches/slicerCache2.xml", []byte(fmt.Sprintf(`<slicerCacheDefinition xmlns="%s" name="Slicer1" sourceName="B1"><extLst><ext uri="%s"><tableSlicerCache tableId="1" column="2"/></ext></extLst></slicerCacheDefinition>`, NameSpaceSpreadSheetX14.Value, ExtURISlicerCacheDefinition)))
_, err = f.setSlicerCache(1, &SlicerOptions{}, &Table{tID: 1})
assert.NoError(t, err)
assert.NoError(t, f.Close())
f = NewFile()
f.Pkg.Store("xl/slicerCaches/slicerCache2.xml", []byte(fmt.Sprintf(`<slicerCacheDefinition xmlns="%s" name="Slicer1" sourceName="B1"></slicerCacheDefinition>`, NameSpaceSpreadSheetX14.Value)))
_, err = f.setSlicerCache(1, &SlicerOptions{}, &Table{tID: 1})
assert.NoError(t, err)
assert.NoError(t, f.Close())
}
func TestAddSlicerCache(t *testing.T) {
f := NewFile()
f.ContentTypes = nil
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
assert.EqualError(t, f.addSlicerCache("Slicer1", 0, &SlicerOptions{}, &Table{}), "XML syntax error on line 1: invalid UTF-8")
assert.NoError(t, f.Close())
}
func TestAddDrawingSlicer(t *testing.T) {
f := NewFile()
// Test add a drawing slicer with not exist worksheet
_, err := f.addDrawingSlicer("SheetN", &SlicerOptions{
Name: "Column2",
Table: "Table1",
Cell: "Q1",
})
assert.EqualError(t, err, "sheet SheetN does not exist")
// Test add a drawing slicer with invalid cell reference
_, err = f.addDrawingSlicer("Sheet1", &SlicerOptions{
Name: "Column2",
Table: "Table1",
Cell: "A",
})
assert.EqualError(t, err, "cannot convert cell \"A\" to coordinates: invalid cell name \"A\"")
assert.NoError(t, f.Close())
}
func TestAddWorkbookSlicerCache(t *testing.T) {
// Test add a workbook slicer cache with with unsupported charset workbook
f := NewFile()
f.WorkBook = nil
f.Pkg.Store("xl/workbook.xml", MacintoshCyrillicCharset)
assert.EqualError(t, f.addWorkbookSlicerCache(1, ExtURISlicerCachesX15), "XML syntax error on line 1: invalid UTF-8")
assert.NoError(t, f.Close())
}
func TestGenSlicerCacheName(t *testing.T) {
f := NewFile()
assert.NoError(t, f.SetDefinedName(&DefinedName{Name: "Slicer_Column_1", RefersTo: formulaErrorNA}))
assert.Equal(t, "Slicer_Column_11", f.genSlicerCacheName("Column 1"))
assert.NoError(t, f.Close())
}

View File

@ -489,9 +489,9 @@ func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup,
err error
idx int
appendMode bool
decodeExtLst = new(decodeWorksheetExt)
decodeExtLst = new(decodeExtLst)
decodeSparklineGroups *decodeX14SparklineGroups
ext *xlsxWorksheetExt
ext *xlsxExt
sparklineGroupsBytes, sparklineGroupBytes, extLstBytes []byte
)
sparklineGroupBytes, _ = xml.Marshal(group)
@ -523,7 +523,7 @@ func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup,
XMLNSXM: NameSpaceSpreadSheetExcel2006Main.Value,
SparklineGroups: []*xlsxX14SparklineGroup{group},
})
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxWorksheetExt{
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxExt{
URI: ExtURISparklineGroups, Content: string(sparklineGroupsBytes),
})
}

View File

@ -2615,10 +2615,10 @@ func (f *File) appendCfRule(ws *xlsxWorksheet, rule *xlsxX14CfRule) error {
err error
idx int
appendMode bool
decodeExtLst = new(decodeWorksheetExt)
decodeExtLst = new(decodeExtLst)
condFmts *xlsxX14ConditionalFormattings
decodeCondFmts *decodeX14ConditionalFormattings
ext *xlsxWorksheetExt
ext *xlsxExt
condFmtBytes, condFmtsBytes, extLstBytes []byte
)
condFmtBytes, _ = xml.Marshal([]*xlsxX14ConditionalFormatting{
@ -2645,7 +2645,7 @@ func (f *File) appendCfRule(ws *xlsxWorksheet, rule *xlsxX14CfRule) error {
}
if !appendMode {
condFmtsBytes, _ = xml.Marshal(&xlsxX14ConditionalFormattings{Content: string(condFmtBytes)})
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxWorksheetExt{
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxExt{
URI: ExtURIConditionalFormattings, Content: string(condFmtsBytes),
})
}
@ -2781,7 +2781,7 @@ func extractCondFmtDataBar(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatO
}
}
}
extractExtLst := func(extLst *decodeWorksheetExt) {
extractExtLst := func(extLst *decodeExtLst) {
for _, ext := range extLst.Ext {
if ext.URI == ExtURIConditionalFormattings {
decodeCondFmts := new(decodeX14ConditionalFormattings)
@ -2797,7 +2797,7 @@ func extractCondFmtDataBar(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatO
if c.ExtLst != nil {
ext := decodeX14ConditionalFormattingExt{}
if err := xml.Unmarshal([]byte(c.ExtLst.Ext), &ext); err == nil && extLst != nil {
decodeExtLst := new(decodeWorksheetExt)
decodeExtLst := new(decodeExtLst)
if err = xml.Unmarshal([]byte("<extLst>"+extLst.Ext+"</extLst>"), decodeExtLst); err == nil {
extractExtLst(decodeExtLst)
}

View File

@ -151,6 +151,7 @@ func (f *File) GetTables(sheet string) ([]Table, error) {
}
table := Table{
rID: tbl.RID,
tID: t.ID,
Range: t.Ref,
Name: t.Name,
}
@ -216,7 +217,15 @@ func (f *File) countTables() int {
count := 0
f.Pkg.Range(func(k, v interface{}) bool {
if strings.Contains(k.(string), "xl/tables/table") {
count++
var t xlsxTable
if err := f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(v.([]byte)))).
Decode(&t); err != nil && err != io.EOF {
count++
return true
}
if count < t.ID {
count = t.ID
}
}
return true
})
@ -343,9 +352,9 @@ func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, opts *Tab
t.AutoFilter = nil
t.HeaderRowCount = intPtr(0)
}
table, _ := xml.Marshal(t)
table, err := xml.Marshal(t)
f.saveFileList(tableXML, table)
return nil
return err
}
// AutoFilter provides the method to add auto filter in a worksheet by given

View File

@ -14,6 +14,190 @@
package excelize
import "encoding/xml"
// Source relationship and namespace list, associated prefixes and schema in which it was
// introduced.
var (
NameSpaceDocumentPropertiesVariantTypes = xml.Attr{Name: xml.Name{Local: "vt", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"}
NameSpaceDrawing2016SVG = xml.Attr{Name: xml.Name{Local: "asvg", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2016/SVG/main"}
NameSpaceDrawingML = xml.Attr{Name: xml.Name{Local: "a", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/main"}
NameSpaceDrawingMLChart = xml.Attr{Name: xml.Name{Local: "c", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/chart"}
NameSpaceDrawingMLSlicer = xml.Attr{Name: xml.Name{Local: "sle", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2010/slicer"}
NameSpaceDrawingMLSlicerX15 = xml.Attr{Name: xml.Name{Local: "sle15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2012/slicer"}
NameSpaceDrawingMLSpreadSheet = xml.Attr{Name: xml.Name{Local: "xdr", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"}
NameSpaceMacExcel2008Main = xml.Attr{Name: xml.Name{Local: "mx", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/mac/excel/2008/main"}
NameSpaceSpreadSheet = xml.Attr{Name: xml.Name{Local: "xmlns"}, Value: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
NameSpaceSpreadSheetExcel2006Main = xml.Attr{Name: xml.Name{Local: "xne", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/excel/2006/main"}
NameSpaceSpreadSheetX14 = xml.Attr{Name: xml.Name{Local: "x14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"}
NameSpaceSpreadSheetX15 = xml.Attr{Name: xml.Name{Local: "x15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"}
NameSpaceSpreadSheetXR10 = xml.Attr{Name: xml.Name{Local: "xr10", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2016/revision10"}
SourceRelationship = xml.Attr{Name: xml.Name{Local: "r", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"}
SourceRelationshipChart20070802 = xml.Attr{Name: xml.Name{Local: "c14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"}
SourceRelationshipChart2014 = xml.Attr{Name: xml.Name{Local: "c16", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2014/chart"}
SourceRelationshipChart201506 = xml.Attr{Name: xml.Name{Local: "c16r2", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2015/06/chart"}
SourceRelationshipCompatibility = xml.Attr{Name: xml.Name{Local: "mc", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"}
)
// Source relationship and namespace.
const (
ContentTypeAddinMacro = "application/vnd.ms-excel.addin.macroEnabled.main+xml"
ContentTypeDrawing = "application/vnd.openxmlformats-officedocument.drawing+xml"
ContentTypeDrawingML = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
ContentTypeMacro = "application/vnd.ms-excel.sheet.macroEnabled.main+xml"
ContentTypeRelationships = "application/vnd.openxmlformats-package.relationships+xml"
ContentTypeSheetML = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
ContentTypeSlicer = "application/vnd.ms-excel.slicer+xml"
ContentTypeSlicerCache = "application/vnd.ms-excel.slicerCache+xml"
ContentTypeSpreadSheetMLChartsheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"
ContentTypeSpreadSheetMLComments = "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"
ContentTypeSpreadSheetMLPivotCacheDefinition = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"
ContentTypeSpreadSheetMLPivotTable = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"
ContentTypeSpreadSheetMLSharedStrings = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"
ContentTypeSpreadSheetMLTable = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
ContentTypeSpreadSheetMLWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"
ContentTypeTemplate = "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
ContentTypeTemplateMacro = "application/vnd.ms-excel.template.macroEnabled.main+xml"
ContentTypeVBA = "application/vnd.ms-office.vbaProject"
ContentTypeVML = "application/vnd.openxmlformats-officedocument.vmlDrawing"
NameSpaceDrawingMLMain = "http://schemas.openxmlformats.org/drawingml/2006/main"
NameSpaceDublinCore = "http://purl.org/dc/elements/1.1/"
NameSpaceDublinCoreMetadataInitiative = "http://purl.org/dc/dcmitype/"
NameSpaceDublinCoreTerms = "http://purl.org/dc/terms/"
NameSpaceExtendedProperties = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
SourceRelationshipExtendProperties = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipOfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
SourceRelationshipSlicer = "http://schemas.microsoft.com/office/2007/relationships/slicer"
SourceRelationshipSlicerCache = "http://schemas.microsoft.com/office/2007/relationships/slicerCache"
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
StrictNameSpaceDocumentPropertiesVariantTypes = "http://purl.oclc.org/ooxml/officeDocument/docPropsVTypes"
StrictNameSpaceDrawingMLMain = "http://purl.oclc.org/ooxml/drawingml/main"
StrictNameSpaceExtendedProperties = "http://purl.oclc.org/ooxml/officeDocument/extendedProperties"
StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main"
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"
StrictSourceRelationshipExtendProperties = "http://purl.oclc.org/ooxml/officeDocument/relationships/extendedProperties"
StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image"
StrictSourceRelationshipOfficeDocument = "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument"
// The following constants defined the extLst child element
// ([ISO/IEC29500-1:2016] section 18.2.10) of the workbook and worksheet
// elements extended by the addition of new child ext elements.
ExtURICalcFeatures = "{B58B0392-4F1F-4190-BB64-5DF3571DCE5F}"
ExtURIConditionalFormattingRuleID = "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"
ExtURIConditionalFormattings = "{78C0D931-6437-407d-A8EE-F0AAD7539E65}"
ExtURIDataModel = "{FCE2AD5D-F65C-4FA6-A056-5C36A1767C68}"
ExtURIDataValidations = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
ExtURIDrawingBlip = "{28A0092B-C50C-407E-A947-70E740481C1C}"
ExtURIExternalLinkPr = "{FCE6A71B-6B00-49CD-AB44-F6B1AE7CDE65}"
ExtURIIgnoredErrors = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"
ExtURIMacExcelMX = "{64002731-A6B0-56B0-2670-7721B7C09600}"
ExtURIModelTimeGroupings = "{9835A34E-60A6-4A7C-AAB8-D5F71C897F49}"
ExtURIPivotCacheDefinition = "{725AE2AE-9491-48be-B2B4-4EB974FC3084}"
ExtURIPivotCachesX14 = "{876F7934-8845-4945-9796-88D515C7AA90}"
ExtURIPivotCachesX15 = "{841E416B-1EF1-43b6-AB56-02D37102CBD5}"
ExtURIPivotTableReferences = "{983426D0-5260-488c-9760-48F4B6AC55F4}"
ExtURIProtectedRanges = "{FC87AEE6-9EDD-4A0A-B7FB-166176984837}"
ExtURISlicerCacheDefinition = "{2F2917AC-EB37-4324-AD4E-5DD8C200BD13}"
ExtURISlicerCacheHideItemsWithNoData = "{470722E0-AACD-4C17-9CDC-17EF765DBC7E}"
ExtURISlicerCachesX14 = "{BBE1A952-AA13-448e-AADC-164F8A28A991}"
ExtURISlicerCachesX15 = "{46BE6895-7355-4a93-B00E-2C351335B9C9}"
ExtURISlicerListX14 = "{A8765BA9-456A-4DAB-B4F3-ACF838C121DE}"
ExtURISlicerListX15 = "{3A4CF648-6AED-40f4-86FF-DC5316D8AED3}"
ExtURISparklineGroups = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"
ExtURISVG = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}"
ExtURITimelineCachePivotCaches = "{A2CB5862-8E78-49c6-8D9D-AF26E26ADB89}"
ExtURITimelineCacheRefs = "{D0CA8CA8-9F24-4464-BF8E-62219DCF47F9}"
ExtURITimelineRefs = "{7E03D99C-DC04-49d9-9315-930204A7B6E9}"
ExtURIWebExtensions = "{F7C9EE02-42E1-4005-9D12-6889AFFD525C}"
ExtURIWorkbookPrX14 = "{79F54976-1DA5-4618-B147-ACDE4B953A38}"
ExtURIWorkbookPrX15 = "{140A7094-0E35-4892-8432-C4D2E57EDEB5}"
)
// extensionURIPriority is the priority of URI in the extension lists.
var extensionURIPriority = []string{
ExtURIConditionalFormattings,
ExtURIDataValidations,
ExtURISparklineGroups,
ExtURISlicerListX14,
ExtURIProtectedRanges,
ExtURIIgnoredErrors,
ExtURIWebExtensions,
ExtURISlicerListX15,
ExtURITimelineRefs,
ExtURIExternalLinkPr,
}
// Excel specifications and limits
const (
MaxCellStyles = 65430
MaxColumns = 16384
MaxColumnWidth = 255
MaxFieldLength = 255
MaxFilePathLength = 207
MaxFormControlValue = 30000
MaxFontFamilyLength = 31
MaxFontSize = 409
MaxRowHeight = 409
MaxSheetNameLength = 31
MinColumns = 1
MinFontSize = 1
StreamChunkSize = 1 << 24
TotalCellChars = 32767
TotalRows = 1048576
TotalSheetHyperlinks = 65529
UnzipSizeLimit = 1000 << 24
// pivotTableVersion should be greater than 3. One or more of the
// PivotTables chosen are created in a version of Excel earlier than
// Excel 2007 or in compatibility mode. Slicer can only be used with
// PivotTables created in Excel 2007 or a newer version of Excel.
pivotTableVersion = 3
defaultDrawingScale = 1.0
defaultChartDimensionWidth = 480
defaultChartDimensionHeight = 260
defaultSlicerWidth = 200
defaultSlicerHeight = 200
defaultChartLegendPosition = "bottom"
defaultChartShowBlanksAs = "gap"
defaultShapeSize = 160
defaultShapeLineWidth = 1
)
// ColorMappingType is the type of color transformation.
type ColorMappingType byte
// Color transformation types enumeration.
const (
ColorMappingTypeLight1 ColorMappingType = iota
ColorMappingTypeDark1
ColorMappingTypeLight2
ColorMappingTypeDark2
ColorMappingTypeAccent1
ColorMappingTypeAccent2
ColorMappingTypeAccent3
ColorMappingTypeAccent4
ColorMappingTypeAccent5
ColorMappingTypeAccent6
ColorMappingTypeHyperlink
ColorMappingTypeFollowedHyperlink
ColorMappingTypeUnset int = -1
)
const (
defaultXMLPathContentTypes = "[Content_Types].xml"
defaultXMLPathDocPropsApp = "docProps/app.xml"
@ -27,6 +211,59 @@ const (
defaultTempFileSST = "sharedStrings"
)
// IndexedColorMapping is the table of default mappings from indexed color value
// to RGB value. Note that 0-7 are redundant of 8-15 to preserve backwards
// compatibility. A legacy indexing scheme for colors that is still required
// for some records, and for backwards compatibility with legacy formats. This
// element contains a sequence of RGB color values that correspond to color
// indexes (zero-based). When using the default indexed color palette, the
// values are not written out, but instead are implied. When the color palette
// has been modified from default, then the entire color palette is written
// out.
var IndexedColorMapping = []string{
"000000", "FFFFFF", "FF0000", "00FF00", "0000FF", "FFFF00", "FF00FF", "00FFFF",
"000000", "FFFFFF", "FF0000", "00FF00", "0000FF", "FFFF00", "FF00FF", "00FFFF",
"800000", "008000", "000080", "808000", "800080", "008080", "C0C0C0", "808080",
"9999FF", "993366", "FFFFCC", "CCFFFF", "660066", "FF8080", "0066CC", "CCCCFF",
"000080", "FF00FF", "FFFF00", "00FFFF", "800080", "800000", "008080", "0000FF",
"00CCFF", "CCFFFF", "CCFFCC", "FFFF99", "99CCFF", "FF99CC", "CC99FF", "FFCC99",
"3366FF", "33CCCC", "99CC00", "FFCC00", "FF9900", "FF6600", "666699", "969696",
"003366", "339966", "003300", "333300", "993300", "993366", "333399", "333333",
"000000", "FFFFFF",
}
// supportedImageTypes defined supported image types.
var supportedImageTypes = map[string]string{
".bmp": ".bmp", ".emf": ".emf", ".emz": ".emz", ".gif": ".gif",
".jpeg": ".jpeg", ".jpg": ".jpeg", ".png": ".png", ".svg": ".svg",
".tif": ".tiff", ".tiff": ".tiff", ".wmf": ".wmf", ".wmz": ".wmz",
}
// supportedContentTypes defined supported file format types.
var supportedContentTypes = map[string]string{
".xlam": ContentTypeAddinMacro,
".xlsm": ContentTypeMacro,
".xlsx": ContentTypeSheetML,
".xltm": ContentTypeTemplateMacro,
".xltx": ContentTypeTemplate,
}
// supportedUnderlineTypes defined supported underline types.
var supportedUnderlineTypes = []string{"none", "single", "double"}
// supportedDrawingUnderlineTypes defined supported underline types in drawing
// markup language.
var supportedDrawingUnderlineTypes = []string{
"none", "words", "sng", "dbl", "heavy", "dotted", "dottedHeavy", "dash", "dashHeavy", "dashLong", "dashLongHeavy", "dotDash", "dotDashHeavy", "dotDotDash", "dotDotDashHeavy", "wavy", "wavyHeavy",
"wavyDbl",
}
// supportedPositioning defined supported positioning types.
var supportedPositioning = []string{"absolute", "oneCell", "twoCell"}
// builtInDefinedNames defined built-in defined names are built with a _xlnm prefix.
var builtInDefinedNames = []string{"_xlnm.Print_Area", "_xlnm.Print_Titles", "_xlnm._FilterDatabase"}
const templateDocpropsApp = `<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><TotalTime>0</TotalTime><Application>Go Excelize</Application></Properties>`
const templateContentTypes = `<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/></Types>`

View File

@ -47,7 +47,7 @@ type decodeSp struct {
// appearance of the shape to be stored.
type decodeNvSpPr struct {
CNvPr *decodeCNvPr `xml:"cNvPr"`
ExtLst *decodeExt `xml:"extLst"`
ExtLst *decodeAExt `xml:"extLst"`
CNvSpPr *decodeCNvSpPr `xml:"cNvSpPr"`
}
@ -78,10 +78,11 @@ type decodeWsDr struct {
// information that does not affect the appearance of the picture to be
// stored.
type decodeCNvPr struct {
ID int `xml:"id,attr"`
Name string `xml:"name,attr"`
Descr string `xml:"descr,attr"`
Title string `xml:"title,attr,omitempty"`
XMLName xml.Name `xml:"cNvPr"`
ID int `xml:"id,attr"`
Name string `xml:"name,attr"`
Descr string `xml:"descr,attr"`
Title string `xml:"title,attr,omitempty"`
}
// decodePicLocks directly maps the picLocks (Picture Locks). This element
@ -124,8 +125,8 @@ type decodeOff struct {
Y int `xml:"y,attr"`
}
// decodeExt directly maps the ext element.
type decodeExt struct {
// decodeAExt directly maps the a:ext element.
type decodeAExt struct {
Cx int `xml:"cx,attr"`
Cy int `xml:"cy,attr"`
}
@ -143,8 +144,8 @@ type decodePrstGeom struct {
// frame. This transformation is applied to the graphic frame just as it would
// be for a shape or group shape.
type decodeXfrm struct {
Off decodeOff `xml:"off"`
Ext decodeExt `xml:"ext"`
Off decodeOff `xml:"off"`
Ext decodeAExt `xml:"ext"`
}
// decodeCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing

View File

@ -16,220 +16,6 @@ import (
"sync"
)
// Source relationship and namespace list, associated prefixes and schema in which it was
// introduced.
var (
NameSpaceDocumentPropertiesVariantTypes = xml.Attr{Name: xml.Name{Local: "vt", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"}
NameSpaceDrawing2016SVG = xml.Attr{Name: xml.Name{Local: "asvg", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2016/SVG/main"}
NameSpaceDrawingML = xml.Attr{Name: xml.Name{Local: "a", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/main"}
NameSpaceDrawingMLChart = xml.Attr{Name: xml.Name{Local: "c", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/chart"}
NameSpaceDrawingMLSpreadSheet = xml.Attr{Name: xml.Name{Local: "xdr", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"}
NameSpaceMacExcel2008Main = xml.Attr{Name: xml.Name{Local: "mx", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/mac/excel/2008/main"}
NameSpaceSpreadSheet = xml.Attr{Name: xml.Name{Local: "xmlns"}, Value: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
NameSpaceSpreadSheetExcel2006Main = xml.Attr{Name: xml.Name{Local: "xne", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/excel/2006/main"}
NameSpaceSpreadSheetX14 = xml.Attr{Name: xml.Name{Local: "x14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"}
NameSpaceSpreadSheetX15 = xml.Attr{Name: xml.Name{Local: "x15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"}
NameSpaceSpreadSheetXR10 = xml.Attr{Name: xml.Name{Local: "xr10", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2016/revision10"}
SourceRelationship = xml.Attr{Name: xml.Name{Local: "r", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"}
SourceRelationshipChart20070802 = xml.Attr{Name: xml.Name{Local: "c14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"}
SourceRelationshipChart2014 = xml.Attr{Name: xml.Name{Local: "c16", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2014/chart"}
SourceRelationshipChart201506 = xml.Attr{Name: xml.Name{Local: "c16r2", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2015/06/chart"}
SourceRelationshipCompatibility = xml.Attr{Name: xml.Name{Local: "mc", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"}
)
// Source relationship and namespace.
const (
ContentTypeAddinMacro = "application/vnd.ms-excel.addin.macroEnabled.main+xml"
ContentTypeDrawing = "application/vnd.openxmlformats-officedocument.drawing+xml"
ContentTypeDrawingML = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
ContentTypeMacro = "application/vnd.ms-excel.sheet.macroEnabled.main+xml"
ContentTypeSheetML = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
ContentTypeSlicer = "application/vnd.ms-excel.slicer+xml"
ContentTypeSlicerCache = "application/vnd.ms-excel.slicerCache+xml"
ContentTypeSpreadSheetMLChartsheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"
ContentTypeSpreadSheetMLComments = "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"
ContentTypeSpreadSheetMLPivotCacheDefinition = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"
ContentTypeSpreadSheetMLPivotTable = "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"
ContentTypeSpreadSheetMLSharedStrings = "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"
ContentTypeSpreadSheetMLTable = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
ContentTypeSpreadSheetMLWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"
ContentTypeTemplate = "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
ContentTypeTemplateMacro = "application/vnd.ms-excel.template.macroEnabled.main+xml"
ContentTypeVBA = "application/vnd.ms-office.vbaProject"
ContentTypeVML = "application/vnd.openxmlformats-officedocument.vmlDrawing"
NameSpaceDrawingMLMain = "http://schemas.openxmlformats.org/drawingml/2006/main"
NameSpaceDublinCore = "http://purl.org/dc/elements/1.1/"
NameSpaceDublinCoreMetadataInitiative = "http://purl.org/dc/dcmitype/"
NameSpaceDublinCoreTerms = "http://purl.org/dc/terms/"
NameSpaceExtendedProperties = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
SourceRelationshipExtendProperties = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipOfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
SourceRelationshipSlicer = "http://schemas.microsoft.com/office/2007/relationships/slicer"
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
StrictNameSpaceDocumentPropertiesVariantTypes = "http://purl.oclc.org/ooxml/officeDocument/docPropsVTypes"
StrictNameSpaceDrawingMLMain = "http://purl.oclc.org/ooxml/drawingml/main"
StrictNameSpaceExtendedProperties = "http://purl.oclc.org/ooxml/officeDocument/extendedProperties"
StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main"
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"
StrictSourceRelationshipExtendProperties = "http://purl.oclc.org/ooxml/officeDocument/relationships/extendedProperties"
StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image"
StrictSourceRelationshipOfficeDocument = "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument"
// ExtURIConditionalFormattings is the extLst child element
// ([ISO/IEC29500-1:2016] section 18.2.10) of the worksheet element
// ([ISO/IEC29500-1:2016] section 18.3.1.99) is extended by the addition of
// new child ext elements ([ISO/IEC29500-1:2016] section 18.2.7)
ExtURIConditionalFormattingRuleID = "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"
ExtURIConditionalFormattings = "{78C0D931-6437-407d-A8EE-F0AAD7539E65}"
ExtURIDataValidations = "{CCE6A557-97BC-4B89-ADB6-D9C93CAAB3DF}"
ExtURIDrawingBlip = "{28A0092B-C50C-407E-A947-70E740481C1C}"
ExtURIIgnoredErrors = "{01252117-D84E-4E92-8308-4BE1C098FCBB}"
ExtURIMacExcelMX = "{64002731-A6B0-56B0-2670-7721B7C09600}"
ExtURIPivotCacheDefinition = "{725AE2AE-9491-48be-B2B4-4EB974FC3084}"
ExtURIProtectedRanges = "{FC87AEE6-9EDD-4A0A-B7FB-166176984837}"
ExtURISlicerCachesListX14 = "{BBE1A952-AA13-448e-AADC-164F8A28A991}"
ExtURISlicerListX14 = "{A8765BA9-456A-4DAB-B4F3-ACF838C121DE}"
ExtURISlicerListX15 = "{3A4CF648-6AED-40f4-86FF-DC5316D8AED3}"
ExtURISparklineGroups = "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"
ExtURISVG = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}"
ExtURITimelineRefs = "{7E03D99C-DC04-49d9-9315-930204A7B6E9}"
ExtURIWebExtensions = "{F7C9EE02-42E1-4005-9D12-6889AFFD525C}"
)
// extensionURIPriority is the priority of URI in the extension lists.
var extensionURIPriority = []string{
ExtURIConditionalFormattings,
ExtURIDataValidations,
ExtURISparklineGroups,
ExtURISlicerListX14,
ExtURIProtectedRanges,
ExtURIIgnoredErrors,
ExtURIWebExtensions,
ExtURITimelineRefs,
}
// Excel specifications and limits
const (
MaxCellStyles = 65430
MaxColumns = 16384
MaxColumnWidth = 255
MaxFieldLength = 255
MaxFilePathLength = 207
MaxFormControlValue = 30000
MaxFontFamilyLength = 31
MaxFontSize = 409
MaxRowHeight = 409
MaxSheetNameLength = 31
MinColumns = 1
MinFontSize = 1
StreamChunkSize = 1 << 24
TotalCellChars = 32767
TotalRows = 1048576
TotalSheetHyperlinks = 65529
UnzipSizeLimit = 1000 << 24
// pivotTableVersion should be greater than 3. One or more of the
// PivotTables chosen are created in a version of Excel earlier than
// Excel 2007 or in compatibility mode. Slicer can only be used with
// PivotTables created in Excel 2007 or a newer version of Excel.
pivotTableVersion = 3
defaultPictureScale = 1.0
defaultChartDimensionWidth = 480
defaultChartDimensionHeight = 260
defaultChartLegendPosition = "bottom"
defaultChartShowBlanksAs = "gap"
defaultShapeSize = 160
defaultShapeLineWidth = 1
)
// ColorMappingType is the type of color transformation.
type ColorMappingType byte
// Color transformation types enumeration.
const (
ColorMappingTypeLight1 ColorMappingType = iota
ColorMappingTypeDark1
ColorMappingTypeLight2
ColorMappingTypeDark2
ColorMappingTypeAccent1
ColorMappingTypeAccent2
ColorMappingTypeAccent3
ColorMappingTypeAccent4
ColorMappingTypeAccent5
ColorMappingTypeAccent6
ColorMappingTypeHyperlink
ColorMappingTypeFollowedHyperlink
ColorMappingTypeUnset int = -1
)
// IndexedColorMapping is the table of default mappings from indexed color value
// to RGB value. Note that 0-7 are redundant of 8-15 to preserve backwards
// compatibility. A legacy indexing scheme for colors that is still required
// for some records, and for backwards compatibility with legacy formats. This
// element contains a sequence of RGB color values that correspond to color
// indexes (zero-based). When using the default indexed color palette, the
// values are not written out, but instead are implied. When the color palette
// has been modified from default, then the entire color palette is written
// out.
var IndexedColorMapping = []string{
"000000", "FFFFFF", "FF0000", "00FF00", "0000FF", "FFFF00", "FF00FF", "00FFFF",
"000000", "FFFFFF", "FF0000", "00FF00", "0000FF", "FFFF00", "FF00FF", "00FFFF",
"800000", "008000", "000080", "808000", "800080", "008080", "C0C0C0", "808080",
"9999FF", "993366", "FFFFCC", "CCFFFF", "660066", "FF8080", "0066CC", "CCCCFF",
"000080", "FF00FF", "FFFF00", "00FFFF", "800080", "800000", "008080", "0000FF",
"00CCFF", "CCFFFF", "CCFFCC", "FFFF99", "99CCFF", "FF99CC", "CC99FF", "FFCC99",
"3366FF", "33CCCC", "99CC00", "FFCC00", "FF9900", "FF6600", "666699", "969696",
"003366", "339966", "003300", "333300", "993300", "993366", "333399", "333333",
"000000", "FFFFFF",
}
// supportedImageTypes defined supported image types.
var supportedImageTypes = map[string]string{
".bmp": ".bmp", ".emf": ".emf", ".emz": ".emz", ".gif": ".gif",
".jpeg": ".jpeg", ".jpg": ".jpeg", ".png": ".png", ".svg": ".svg",
".tif": ".tiff", ".tiff": ".tiff", ".wmf": ".wmf", ".wmz": ".wmz",
}
// supportedContentTypes defined supported file format types.
var supportedContentTypes = map[string]string{
".xlam": ContentTypeAddinMacro,
".xlsm": ContentTypeMacro,
".xlsx": ContentTypeSheetML,
".xltm": ContentTypeTemplateMacro,
".xltx": ContentTypeTemplate,
}
// supportedUnderlineTypes defined supported underline types.
var supportedUnderlineTypes = []string{"none", "single", "double"}
// supportedDrawingUnderlineTypes defined supported underline types in drawing
// markup language.
var supportedDrawingUnderlineTypes = []string{
"none", "words", "sng", "dbl", "heavy", "dotted", "dottedHeavy", "dash", "dashHeavy", "dashLong", "dashLongHeavy", "dotDash", "dotDashHeavy", "dotDotDash", "dotDotDashHeavy", "wavy", "wavyHeavy",
"wavyDbl",
}
// supportedPositioning defined supported positioning types.
var supportedPositioning = []string{"absolute", "oneCell", "twoCell"}
// builtInDefinedNames defined built-in defined names are built with a _xlnm prefix.
var builtInDefinedNames = []string{"_xlnm.Print_Area", "_xlnm.Print_Titles", "_xlnm._FilterDatabase"}
// xlsxCNvPr directly maps the cNvPr (Non-Visual Drawing Properties). This
// element specifies non-visual canvas properties. This allows for additional
// information that does not affect the appearance of the picture to be stored.
@ -297,8 +83,8 @@ type xlsxOff struct {
Y int `xml:"y,attr"`
}
// xlsxExt directly maps the ext element.
type xlsxExt struct {
// aExt directly maps the a:ext element.
type aExt struct {
Cx int `xml:"cx,attr"`
Cy int `xml:"cy,attr"`
}
@ -317,7 +103,7 @@ type xlsxPrstGeom struct {
// be for a shape or group shape.
type xlsxXfrm struct {
Off xlsxOff `xml:"a:off"`
Ext xlsxExt `xml:"a:ext"`
Ext aExt `xml:"a:ext"`
}
// xlsxCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing
@ -375,7 +161,8 @@ type xlsxBlipFill struct {
// has a minimum value of greater than or equal to 0. This simple type has a
// maximum value of less than or equal to 20116800.
type xlsxLineProperties struct {
W int `xml:"w,attr,omitempty"`
W int `xml:"w,attr,omitempty"`
SolidFill *xlsxInnerXML `xml:"a:solidFill"`
}
// xlsxSpPr directly maps the spPr (Shape Properties). This element specifies
@ -384,9 +171,10 @@ type xlsxLineProperties struct {
// but are used here to describe the visual appearance of a picture within a
// document.
type xlsxSpPr struct {
Xfrm xlsxXfrm `xml:"a:xfrm"`
PrstGeom xlsxPrstGeom `xml:"a:prstGeom"`
Ln xlsxLineProperties `xml:"a:ln"`
Xfrm xlsxXfrm `xml:"a:xfrm"`
PrstGeom xlsxPrstGeom `xml:"a:prstGeom"`
SolidFill *xlsxInnerXML `xml:"a:solidFill"`
Ln xlsxLineProperties `xml:"a:ln"`
}
// xlsxPic elements encompass the definition of pictures within the DrawingML
@ -426,20 +214,20 @@ type xdrClientData struct {
FPrintsWithSheet bool `xml:"fPrintsWithSheet,attr"`
}
// xdrCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape Size)
// and twoCellAnchor (Two Cell Anchor Shape Size). This element specifies a two
// cell anchor placeholder for a group, a shape, or a drawing element. It moves
// with cells and its extents are in EMU units.
// xdrCellAnchor specifies a oneCellAnchor (One Cell Anchor Shape Size) and
// twoCellAnchor (Two Cell Anchor Shape Size) placeholder for a group, a shape,
// or a drawing element. It moves with cells and its extents are in EMU units.
type xdrCellAnchor struct {
EditAs string `xml:"editAs,attr,omitempty"`
Pos *xlsxPoint2D `xml:"xdr:pos"`
From *xlsxFrom `xml:"xdr:from"`
To *xlsxTo `xml:"xdr:to"`
Ext *xlsxExt `xml:"xdr:ext"`
Sp *xdrSp `xml:"xdr:sp"`
Pic *xlsxPic `xml:"xdr:pic,omitempty"`
GraphicFrame string `xml:",innerxml"`
ClientData *xdrClientData `xml:"xdr:clientData"`
EditAs string `xml:"editAs,attr,omitempty"`
Pos *xlsxPoint2D `xml:"xdr:pos"`
From *xlsxFrom `xml:"xdr:from"`
To *xlsxTo `xml:"xdr:to"`
Ext *aExt `xml:"xdr:ext"`
Sp *xdrSp `xml:"xdr:sp"`
Pic *xlsxPic `xml:"xdr:pic,omitempty"`
GraphicFrame string `xml:",innerxml"`
AlternateContent []*xlsxAlternateContent `xml:"mc:AlternateContent"`
ClientData *xdrClientData `xml:"xdr:clientData"`
}
// xlsxPoint2D describes the position of a drawing element within a spreadsheet.
@ -503,6 +291,12 @@ type xlsxGraphic struct {
type xlsxGraphicData struct {
URI string `xml:"uri,attr"`
Chart *xlsxChart `xml:"c:chart,omitempty"`
Sle *xlsxSle `xml:"sle:slicer"`
}
type xlsxSle struct {
XMLNS string `xml:"xmlns:sle,attr"`
Name string `xml:"name,attr"`
}
// xlsxChart (Chart) directly maps the c:chart element.
@ -520,6 +314,7 @@ type xlsxChart struct {
// This shape is specified along with all other shapes within either the shape
// tree or group shape elements.
type xdrSp struct {
XMLName xml.Name `xml:"xdr:sp"`
Macro string `xml:"macro,attr"`
Textlink string `xml:"textlink,attr"`
NvSpPr *xdrNvSpPr `xml:"xdr:nvSpPr"`

168
xmlSlicers.go Normal file
View File

@ -0,0 +1,168 @@
// Copyright 2016 - 2023 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 XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and
// writing spreadsheet documents generated by Microsoft Excel™ 2007 and later.
// Supports complex components by high compatibility, and provided streaming
// API for generating or reading data from a worksheet with huge amounts of
// data. This library needs Go version 1.16 or later.
package excelize
import "encoding/xml"
// xlsxSlicers directly maps the slicers element that specifies a slicer view on
// the worksheet.
type xlsxSlicers struct {
XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main slicers"`
XMLNSXMC string `xml:"xmlns:mc,attr"`
XMLNSX string `xml:"xmlns:x,attr"`
XMLNSXR10 string `xml:"xmlns:xr10,attr"`
Slicer []xlsxSlicer `xml:"slicer"`
}
// xlsxSlicer is a complex type that specifies a slicer view.
type xlsxSlicer struct {
Name string `xml:"name,attr"`
XR10UID string `xml:"xr10:uid,attr,omitempty"`
Cache string `xml:"cache,attr"`
Caption string `xml:"caption,attr,omitempty"`
StartItem *int `xml:"startItem,attr"`
ColumnCount *int `xml:"columnCount,attr"`
ShowCaption *bool `xml:"showCaption,attr"`
Level int `xml:"level,attr,omitempty"`
Style string `xml:"style,attr,omitempty"`
LockedPosition bool `xml:"lockedPosition,attr,omitempty"`
RowHeight int `xml:"rowHeight,attr"`
}
// slicerCacheDefinition directly maps the slicerCacheDefinition element that
// specifies a slicer cache.
type xlsxSlicerCacheDefinition struct {
XMLName xml.Name `xml:"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main slicerCacheDefinition"`
XMLNSXMC string `xml:"xmlns:mc,attr"`
XMLNSX string `xml:"xmlns:x,attr"`
XMLNSX15 string `xml:"xmlns:x15,attr,omitempty"`
XMLNSXR10 string `xml:"xmlns:xr10,attr"`
Name string `xml:"name,attr"`
XR10UID string `xml:"xr10:uid,attr,omitempty"`
SourceName string `xml:"sourceName,attr"`
PivotTables *xlsxSlicerCachePivotTables `xml:"pivotTables"`
Data *xlsxSlicerCacheData `xml:"data"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// xlsxSlicerCachePivotTables is a complex type that specifies a group of
// pivotTable elements that specify the PivotTable views that are filtered by
// the slicer cache.
type xlsxSlicerCachePivotTables struct {
PivotTable []xlsxSlicerCachePivotTable `xml:"pivotTable"`
}
// xlsxSlicerCachePivotTable is a complex type that specifies a PivotTable view
// filtered by a slicer cache.
type xlsxSlicerCachePivotTable struct {
TabID int `xml:"tabId,attr"`
Name string `xml:"name,attr"`
}
// xlsxSlicerCacheData is a complex type that specifies a data source for the
// slicer cache.
type xlsxSlicerCacheData struct {
OLAP *xlsxInnerXML `xml:"olap"`
Tabular *xlsxTabularSlicerCache `xml:"tabular"`
}
// xlsxTabularSlicerCache is a complex type that specifies non-OLAP slicer items
// that are cached within this slicer cache and properties of the slicer cache
// specific to non-OLAP slicer items.
type xlsxTabularSlicerCache struct {
PivotCacheID int `xml:"pivotCacheId,attr"`
SortOrder string `xml:"sortOrder,attr,omitempty"`
CustomListSort *bool `xml:"customListSort,attr"`
ShowMissing *bool `xml:"showMissing,attr"`
CrossFilter string `xml:"crossFilter,attr,omitempty"`
Items *xlsxTabularSlicerCacheItems `xml:"items"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// xlsxTabularSlicerCacheItems is a complex type that specifies non-OLAP slicer
// items that are cached within this slicer cache.
type xlsxTabularSlicerCacheItems struct {
Count int `xml:"count,attr,omitempty"`
I []xlsxTabularSlicerCacheItem `xml:"i"`
}
// xlsxTabularSlicerCacheItem is a complex type that specifies a non-OLAP slicer
// item that is cached within this slicer cache.
type xlsxTabularSlicerCacheItem struct {
X int `xml:"x,attr"`
S bool `xml:"s,attr,omitempty"`
ND bool `xml:"nd,attr,omitempty"`
}
// xlsxTableSlicerCache specifies a table data source for the slicer cache.
type xlsxTableSlicerCache struct {
XMLName xml.Name `xml:"x15:tableSlicerCache"`
TableID int `xml:"tableId,attr"`
Column int `xml:"column,attr"`
SortOrder string `xml:"sortOrder,attr,omitempty"`
CustomListSort *bool `xml:"customListSort,attr"`
CrossFilter string `xml:"crossFilter,attr,omitempty"`
ExtLst *xlsxExtLst `xml:"extLst"`
}
// xlsxX14SlicerList specifies a list of slicer.
type xlsxX14SlicerList struct {
XMLName xml.Name `xml:"x14:slicerList"`
Slicer []*xlsxX14Slicer `xml:"x14:slicer"`
}
// xlsxX14Slicer specifies a slicer view,
type xlsxX14Slicer struct {
XMLName xml.Name `xml:"x14:slicer"`
RID string `xml:"r:id,attr"`
}
// xlsxX15SlicerCaches directly maps the x14:slicerCache element.
type xlsxX14SlicerCache struct {
XMLName xml.Name `xml:"x14:slicerCache"`
RID string `xml:"r:id,attr"`
}
// xlsxX15SlicerCaches directly maps the x15:slicerCaches element.
type xlsxX15SlicerCaches struct {
XMLName xml.Name `xml:"x15:slicerCaches"`
XMLNS string `xml:"xmlns:x14,attr"`
Content string `xml:",innerxml"`
}
// decodeTableSlicerCache defines the structure used to parse the
// x15:tableSlicerCache element of the table slicer cache.
type decodeTableSlicerCache struct {
XMLName xml.Name `xml:"tableSlicerCache"`
TableID int `xml:"tableId,attr"`
Column int `xml:"column,attr"`
}
// decodeSlicerList defines the structure used to parse the x14:slicerList
// element of a list of slicer.
type decodeSlicerList struct {
XMLName xml.Name `xml:"slicerList"`
Slicer []*decodeSlicer `xml:"slicer"`
}
// decodeSlicer defines the structure used to parse the x14:slicer element of a
// slicer.
type decodeSlicer struct {
RID string `xml:"id,attr"`
}
// decodeX15SlicerCaches defines the structure used to parse the
// x15:slicerCaches element of a slicer cache.
type decodeX15SlicerCaches struct {
XMLName xml.Name `xml:"slicerCaches"`
Content string `xml:",innerxml"`
}

View File

@ -257,7 +257,7 @@ type xlsxDxf struct {
Alignment *xlsxAlignment `xml:"alignment"`
Border *xlsxBorder `xml:"border"`
Protection *xlsxProtection `xml:"protection"`
ExtLst *xlsxExt `xml:"extLst"`
ExtLst *aExt `xml:"extLst"`
}
// xlsxTableStyles directly maps the tableStyles element. This element
@ -312,7 +312,7 @@ type xlsxIndexedColors struct {
// a custom color has been selected while using this workbook.
type xlsxStyleColors struct {
IndexedColors *xlsxIndexedColors `xml:"indexedColors"`
MruColors xlsxInnerXML `xml:"mruColors"`
MruColors *xlsxInnerXML `xml:"mruColors"`
}
// Alignment directly maps the alignment settings of the cells.

View File

@ -198,6 +198,7 @@ type xlsxTableStyleInfo struct {
// Table directly maps the format settings of the table.
type Table struct {
tID int
rID string
Range string
Name string

View File

@ -16,7 +16,8 @@ import (
"sync"
)
// xlsxRelationships describe references from parts to other internal resources in the package or to external resources.
// xlsxRelationships describe references from parts to other internal resources
// in the package or to external resources.
type xlsxRelationships struct {
mu sync.Mutex
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`
@ -218,6 +219,63 @@ type xlsxExtLst struct {
Ext string `xml:",innerxml"`
}
// xlsxExt represents a the future feature data storage area. Each extension
// within an extension list shall be contained within an ext element.
// Extensions shall be versioned by namespace, using the uri attribute, and
// shall be allowed to appear in any order within the extension list. Any
// number of extensions shall be allowed within an extension list.
type xlsxExt struct {
XMLName xml.Name `xml:"ext"`
URI string `xml:"uri,attr"`
Content string `xml:",innerxml"`
xmlns []xml.Attr
}
// xlsxAlternateContent is a container for a sequence of multiple
// representations of a given piece of content. The program reading the file
// should only process one of these, and the one chosen should be based on
// which conditions match.
type xlsxAlternateContent struct {
XMLNSMC string `xml:"xmlns:mc,attr,omitempty"`
Content string `xml:",innerxml"`
}
// xlsxChoice element shall be an element in the Markup Compatibility namespace
// with local name "Choice". Parent elements of Choice elements shall be
// AlternateContent elements.
type xlsxChoice struct {
XMLName xml.Name `xml:"mc:Choice"`
XMLNSSle15 string `xml:"xmlns:sle15,attr,omitempty"`
Requires string `xml:"Requires,attr,omitempty"`
Content string `xml:",innerxml"`
}
// xlsxFallback element shall be an element in the Markup Compatibility
// namespace with local name "Fallback". Parent elements of Fallback elements
// shall be AlternateContent elements.
type xlsxFallback struct {
XMLName xml.Name `xml:"mc:Fallback"`
Content string `xml:",innerxml"`
}
// xlsxInnerXML holds parts of XML content currently not unmarshal.
type xlsxInnerXML struct {
Content string `xml:",innerxml"`
}
// decodeExtLst defines the structure used to parse the extLst element
// of the future feature data storage area.
type decodeExtLst struct {
XMLName xml.Name `xml:"extLst"`
Ext []*xlsxExt `xml:"ext"`
}
// decodeExt defines the structure used to parse the ext element.
type decodeExt struct {
URI string `xml:"uri,attr,omitempty"`
Content string `xml:",innerxml"`
}
// xlsxDefinedNames directly maps the definedNames element. This element defines
// the collection of defined names for this workbook. Defined names are
// descriptive names to represent cells, ranges of cells, formulas, or constant

View File

@ -699,33 +699,6 @@ type xlsxLegacyDrawingHF struct {
RID string `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"`
}
// xlsxAlternateContent is a container for a sequence of multiple
// representations of a given piece of content. The program reading the file
// should only process one of these, and the one chosen should be based on
// which conditions match.
type xlsxAlternateContent struct {
XMLNSMC string `xml:"xmlns:mc,attr,omitempty"`
Content string `xml:",innerxml"`
}
// xlsxInnerXML holds parts of XML content currently not unmarshal.
type xlsxInnerXML struct {
Content string `xml:",innerxml"`
}
// xlsxWorksheetExt directly maps the ext element in the worksheet.
type xlsxWorksheetExt struct {
XMLName xml.Name `xml:"ext"`
URI string `xml:"uri,attr"`
Content string `xml:",innerxml"`
}
// decodeWorksheetExt directly maps the ext element.
type decodeWorksheetExt struct {
XMLName xml.Name `xml:"extLst"`
Ext []*xlsxWorksheetExt `xml:"ext"`
}
// decodeX14SparklineGroups directly maps the sparklineGroups element.
type decodeX14SparklineGroups struct {
XMLName xml.Name `xml:"sparklineGroups"`
@ -733,8 +706,7 @@ type decodeX14SparklineGroups struct {
Content string `xml:",innerxml"`
}
// decodeX14ConditionalFormattingExt directly maps the ext
// element.
// decodeX14ConditionalFormattingExt directly maps the ext element.
type decodeX14ConditionalFormattingExt struct {
XMLName xml.Name `xml:"ext"`
ID string `xml:"id"`