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:
parent
5a039f3045
commit
e3b7dad69a
4
chart.go
4
chart.go
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
42
lib.go
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
|
|
32
picture.go
32
picture.go
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
4
rows.go
4
rows.go
|
@ -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" />
|
||||
|
|
41
shape.go
41
shape.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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),
|
||||
})
|
||||
}
|
||||
|
|
10
styles.go
10
styles.go
|
@ -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)
|
||||
}
|
||||
|
|
15
table.go
15
table.go
|
@ -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
|
||||
|
|
237
templates.go
237
templates.go
|
@ -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>`
|
||||
|
|
|
@ -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
|
||||
|
|
263
xmlDrawing.go
263
xmlDrawing.go
|
@ -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"`
|
||||
|
|
|
@ -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"`
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"`
|
||||
|
|
Loading…
Reference in New Issue