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)
|
opts.Format.Locked = boolPtr(false)
|
||||||
}
|
}
|
||||||
if opts.Format.ScaleX == 0 {
|
if opts.Format.ScaleX == 0 {
|
||||||
opts.Format.ScaleX = defaultPictureScale
|
opts.Format.ScaleX = defaultDrawingScale
|
||||||
}
|
}
|
||||||
if opts.Format.ScaleY == 0 {
|
if opts.Format.ScaleY == 0 {
|
||||||
opts.Format.ScaleY = defaultPictureScale
|
opts.Format.ScaleY = defaultDrawingScale
|
||||||
}
|
}
|
||||||
if opts.Legend.Position == "" {
|
if opts.Legend.Position == "" {
|
||||||
opts.Legend.Position = defaultChartLegendPosition
|
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"},
|
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37", Sizes: "Sheet1!$B$37:$D$37"},
|
||||||
}
|
}
|
||||||
format := GraphicOptions{
|
format := GraphicOptions{
|
||||||
ScaleX: defaultPictureScale,
|
ScaleX: defaultDrawingScale,
|
||||||
ScaleY: defaultPictureScale,
|
ScaleY: defaultDrawingScale,
|
||||||
OffsetX: 15,
|
OffsetX: 15,
|
||||||
OffsetY: 10,
|
OffsetY: 10,
|
||||||
PrintObject: boolPtr(true),
|
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"},
|
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37"},
|
||||||
}
|
}
|
||||||
format := GraphicOptions{
|
format := GraphicOptions{
|
||||||
ScaleX: defaultPictureScale,
|
ScaleX: defaultDrawingScale,
|
||||||
ScaleY: defaultPictureScale,
|
ScaleY: defaultDrawingScale,
|
||||||
OffsetX: 15,
|
OffsetX: 15,
|
||||||
OffsetY: 10,
|
OffsetY: 10,
|
||||||
PrintObject: boolPtr(true),
|
PrintObject: boolPtr(true),
|
||||||
|
|
|
@ -1356,7 +1356,7 @@ func (f *File) addSheetDrawingChart(drawingXML string, rID int, opts *GraphicOpt
|
||||||
absoluteAnchor := xdrCellAnchor{
|
absoluteAnchor := xdrCellAnchor{
|
||||||
EditAs: opts.Positioning,
|
EditAs: opts.Positioning,
|
||||||
Pos: &xlsxPoint2D{},
|
Pos: &xlsxPoint2D{},
|
||||||
Ext: &xlsxExt{},
|
Ext: &aExt{},
|
||||||
}
|
}
|
||||||
|
|
||||||
graphicFrame := xlsxGraphicFrame{
|
graphicFrame := xlsxGraphicFrame{
|
||||||
|
|
|
@ -34,6 +34,12 @@ func newInvalidCellNameError(cell string) error {
|
||||||
return fmt.Errorf("invalid cell name %q", cell)
|
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
|
// newInvalidExcelDateError defined the error message on receiving the data
|
||||||
// with negative values.
|
// with negative values.
|
||||||
func newInvalidExcelDateError(dateValue float64) error {
|
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.
|
// 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
|
var workbookRefTo, worksheetRefTo string
|
||||||
for _, definedName := range f.GetDefinedName() {
|
for _, definedName := range f.GetDefinedName() {
|
||||||
if definedName.Name == definedNameName {
|
if definedName.Name == definedNameName {
|
||||||
|
@ -431,17 +431,17 @@ func float64Ptr(f float64) *float64 { return &f }
|
||||||
func stringPtr(s string) *string { return &s }
|
func stringPtr(s string) *string { return &s }
|
||||||
|
|
||||||
// Value extracts string data type text from a attribute value.
|
// Value extracts string data type text from a attribute value.
|
||||||
func (attr *attrValString) Value() string {
|
func (avb *attrValString) Value() string {
|
||||||
if attr != nil && attr.Val != nil {
|
if avb != nil && avb.Val != nil {
|
||||||
return *attr.Val
|
return *avb.Val
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value extracts boolean data type value from a attribute value.
|
// Value extracts boolean data type value from a attribute value.
|
||||||
func (attr *attrValBool) Value() bool {
|
func (avb *attrValBool) Value() bool {
|
||||||
if attr != nil && attr.Val != nil {
|
if avb != nil && avb.Val != nil {
|
||||||
return *attr.Val
|
return *avb.Val
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -517,6 +517,34 @@ func (avb *attrValBool) UnmarshalXML(d *xml.Decoder, start xml.StartElement) err
|
||||||
return nil
|
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
|
// namespaceStrictToTransitional provides a method to convert Strict and
|
||||||
// Transitional namespaces.
|
// Transitional namespaces.
|
||||||
func namespaceStrictToTransitional(content []byte) []byte {
|
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())
|
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) {
|
func TestBytesReplace(t *testing.T) {
|
||||||
s := []byte{0x01}
|
s := []byte{0x01}
|
||||||
assert.EqualValues(t, s, bytesReplace(s, []byte{}, []byte{}, 0))
|
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{
|
return &GraphicOptions{
|
||||||
PrintObject: boolPtr(true),
|
PrintObject: boolPtr(true),
|
||||||
Locked: boolPtr(true),
|
Locked: boolPtr(true),
|
||||||
ScaleX: defaultPictureScale,
|
ScaleX: defaultDrawingScale,
|
||||||
ScaleY: defaultPictureScale,
|
ScaleY: defaultDrawingScale,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if opts.PrintObject == nil {
|
if opts.PrintObject == nil {
|
||||||
|
@ -41,10 +41,10 @@ func parseGraphicOptions(opts *GraphicOptions) *GraphicOptions {
|
||||||
opts.Locked = boolPtr(true)
|
opts.Locked = boolPtr(true)
|
||||||
}
|
}
|
||||||
if opts.ScaleX == 0 {
|
if opts.ScaleX == 0 {
|
||||||
opts.ScaleX = defaultPictureScale
|
opts.ScaleX = defaultDrawingScale
|
||||||
}
|
}
|
||||||
if opts.ScaleY == 0 {
|
if opts.ScaleY == 0 {
|
||||||
opts.ScaleY = defaultPictureScale
|
opts.ScaleY = defaultDrawingScale
|
||||||
}
|
}
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
@ -440,6 +440,28 @@ func (f *File) addMedia(file []byte, ext string) string {
|
||||||
return media
|
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
|
// setContentTypePartImageExtensions provides a function to set the content
|
||||||
// type for relationship parts and the Main Document part.
|
// type for relationship parts and the Main Document part.
|
||||||
func (f *File) setContentTypePartImageExtensions() error {
|
func (f *File) setContentTypePartImageExtensions() error {
|
||||||
|
@ -542,7 +564,7 @@ func (f *File) addContentTypePart(index int, contentType string) error {
|
||||||
PartName: partNames[contentType],
|
PartName: partNames[contentType],
|
||||||
ContentType: contentTypes[contentType],
|
ContentType: contentTypes[contentType],
|
||||||
})
|
})
|
||||||
return err
|
return f.setContentTypePartRelsExtensions()
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSheetRelationshipsTargetByID provides a function to get Target attribute
|
// 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())
|
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) {
|
func TestSetContentTypePartImageExtensions(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
// Test set content type part image extensions with unsupported charset content types
|
// 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
|
// options. Note that the same fields can not in Columns, Rows and Filter
|
||||||
// fields at the same time.
|
// fields at the same time.
|
||||||
//
|
//
|
||||||
// For example, create a pivot table on the range reference Sheet1!$G$2:$M$34
|
// For example, create a pivot table on the range reference Sheet1!G2:M34 with
|
||||||
// with the range reference Sheet1!$A$1:$E$31 as the data source, summarize by
|
// the range reference Sheet1!A1:E31 as the data source, summarize by sum for
|
||||||
// sum for sales:
|
// sales:
|
||||||
//
|
//
|
||||||
// package main
|
// package main
|
||||||
//
|
//
|
||||||
|
@ -242,15 +242,15 @@ func (f *File) adjustRange(rangeStr string) (string, []int, error) {
|
||||||
return rng[0], []int{x1, y1, x2, y2}, nil
|
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.
|
// fields.
|
||||||
func (f *File) getPivotFieldsOrder(opts *PivotTableOptions) ([]string, error) {
|
func (f *File) getTableFieldsOrder(sheetName, dataRange string) ([]string, error) {
|
||||||
var order []string
|
var order []string
|
||||||
dataRange := f.getDefinedNameRefTo(opts.DataRange, opts.pivotTableSheetName)
|
ref := f.getDefinedNameRefTo(dataRange, sheetName)
|
||||||
if dataRange == "" {
|
if ref == "" {
|
||||||
dataRange = opts.DataRange
|
ref = dataRange
|
||||||
}
|
}
|
||||||
dataSheet, coordinates, err := f.adjustRange(dataRange)
|
dataSheet, coordinates, err := f.adjustRange(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return order, fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
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())
|
return fmt.Errorf("parameter 'DataRange' parsing error: %s", err.Error())
|
||||||
}
|
}
|
||||||
// data range has been checked
|
// data range has been checked
|
||||||
order, _ := f.getPivotFieldsOrder(opts)
|
order, _ := f.getTableFieldsOrder(opts.pivotTableSheetName, opts.DataRange)
|
||||||
hCell, _ := CoordinatesToCellName(coordinates[0], coordinates[1])
|
hCell, _ := CoordinatesToCellName(coordinates[0], coordinates[1])
|
||||||
vCell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
|
vCell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
|
||||||
pc := xlsxPivotCacheDefinition{
|
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
|
// addPivotFields create pivot fields based on the column order of the first
|
||||||
// row in the data region by given pivot table definition and option.
|
// row in the data region by given pivot table definition and option.
|
||||||
func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opts *PivotTableOptions) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -647,7 +647,7 @@ func (f *File) countPivotCache() int {
|
||||||
// to a sequential index by given fields and pivot option.
|
// to a sequential index by given fields and pivot option.
|
||||||
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opts *PivotTableOptions) ([]int, error) {
|
func (f *File) getPivotFieldsIndex(fields []PivotTableField, opts *PivotTableOptions) ([]int, error) {
|
||||||
var pivotFieldsIndex []int
|
var pivotFieldsIndex []int
|
||||||
orders, err := f.getPivotFieldsOrder(opts)
|
orders, err := f.getTableFieldsOrder(opts.pivotTableSheetName, opts.DataRange)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return pivotFieldsIndex, err
|
return pivotFieldsIndex, err
|
||||||
}
|
}
|
||||||
|
@ -809,7 +809,7 @@ func (f *File) getPivotTable(sheet, pivotTableXML, pivotCacheRels string) (Pivot
|
||||||
opts.ShowLastColumn = si.ShowLastColumn
|
opts.ShowLastColumn = si.ShowLastColumn
|
||||||
opts.PivotTableStyleName = si.Name
|
opts.PivotTableStyleName = si.Name
|
||||||
}
|
}
|
||||||
order, _ := f.getPivotFieldsOrder(&PivotTableOptions{DataRange: dataRange, pivotTableSheetName: pt.Name})
|
order, _ := f.getTableFieldsOrder(pt.Name, dataRange)
|
||||||
f.extractPivotTableFields(order, pt, &opts)
|
f.extractPivotTableFields(order, pt, &opts)
|
||||||
return opts, err
|
return opts, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,8 +257,8 @@ func TestPivotTable(t *testing.T) {
|
||||||
// Test adjust range with incorrect range
|
// Test adjust range with incorrect range
|
||||||
_, _, err = f.adjustRange("sheet1!")
|
_, _, err = f.adjustRange("sheet1!")
|
||||||
assert.EqualError(t, err, "parameter is invalid")
|
assert.EqualError(t, err, "parameter is invalid")
|
||||||
// Test get pivot fields order with empty data range
|
// Test get table fields order with empty data range
|
||||||
_, err = f.getPivotFieldsOrder(&PivotTableOptions{})
|
_, err = f.getTableFieldsOrder("", "")
|
||||||
assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
|
assert.EqualError(t, err, `parameter 'DataRange' parsing error: parameter is required`)
|
||||||
// Test add pivot cache with empty data range
|
// Test add pivot cache with empty data range
|
||||||
assert.EqualError(t, f.addPivotCache("", &PivotTableOptions{}), "parameter 'DataRange' parsing error: parameter is required")
|
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) {
|
func TestGetPivotFieldsOrder(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
// Test get pivot fields order with not exist worksheet
|
// Test get table fields order with not exist worksheet
|
||||||
_, err := f.getPivotFieldsOrder(&PivotTableOptions{DataRange: "SheetN!A1:E31"})
|
_, err := f.getTableFieldsOrder("", "SheetN!A1:E31")
|
||||||
assert.EqualError(t, err, "sheet SheetN does not exist")
|
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
|
// 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:
|
// 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="A15" s="2" />
|
||||||
// <c r="B15" s="2" />
|
// <c r="B15" s="2" />
|
||||||
// <c r="F15" s="1" />
|
// <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
|
// 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="A15" s="2" />
|
||||||
// <c r="B15" s="2" />
|
// <c r="B15" s="2" />
|
||||||
// <c r="C15" 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)
|
opts.Format.Locked = boolPtr(false)
|
||||||
}
|
}
|
||||||
if opts.Format.ScaleX == 0 {
|
if opts.Format.ScaleX == 0 {
|
||||||
opts.Format.ScaleX = defaultPictureScale
|
opts.Format.ScaleX = defaultDrawingScale
|
||||||
}
|
}
|
||||||
if opts.Format.ScaleY == 0 {
|
if opts.Format.ScaleY == 0 {
|
||||||
opts.Format.ScaleY = defaultPictureScale
|
opts.Format.ScaleY = defaultDrawingScale
|
||||||
}
|
}
|
||||||
if opts.Line.Width == nil {
|
if opts.Line.Width == nil {
|
||||||
opts.Line.Width = float64Ptr(defaultShapeLineWidth)
|
opts.Line.Width = float64Ptr(defaultShapeLineWidth)
|
||||||
|
@ -322,29 +322,27 @@ func (f *File) AddShape(sheet string, opts *Shape) error {
|
||||||
return f.addContentTypePart(drawingID, "drawings")
|
return f.addContentTypePart(drawingID, "drawings")
|
||||||
}
|
}
|
||||||
|
|
||||||
// addDrawingShape provides a function to add preset geometry by given sheet,
|
// twoCellAnchorShape create a two cell anchor shape size placeholder for a
|
||||||
// drawingXMLand format sets.
|
// group, a shape, or a drawing element.
|
||||||
func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *Shape) error {
|
func (f *File) twoCellAnchorShape(sheet, drawingXML, cell string, width, height uint, format GraphicOptions) (*xlsxWsDr, *xdrCellAnchor, int, error) {
|
||||||
fromCol, fromRow, err := CellNameToCoordinates(cell)
|
fromCol, fromRow, err := CellNameToCoordinates(cell)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
width := int(float64(opts.Width) * opts.Format.ScaleX)
|
w := int(float64(width) * format.ScaleX)
|
||||||
height := int(float64(opts.Height) * opts.Format.ScaleY)
|
h := int(float64(height) * format.ScaleY)
|
||||||
|
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, fromCol, fromRow, format.OffsetX, format.OffsetY, w, h)
|
||||||
colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, fromCol, fromRow, opts.Format.OffsetX, opts.Format.OffsetY,
|
|
||||||
width, height)
|
|
||||||
content, cNvPrID, err := f.drawingParser(drawingXML)
|
content, cNvPrID, err := f.drawingParser(drawingXML)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return content, nil, cNvPrID, err
|
||||||
}
|
}
|
||||||
twoCellAnchor := xdrCellAnchor{}
|
twoCellAnchor := xdrCellAnchor{}
|
||||||
twoCellAnchor.EditAs = opts.Format.Positioning
|
twoCellAnchor.EditAs = format.Positioning
|
||||||
from := xlsxFrom{}
|
from := xlsxFrom{}
|
||||||
from.Col = colStart
|
from.Col = colStart
|
||||||
from.ColOff = opts.Format.OffsetX * EMU
|
from.ColOff = format.OffsetX * EMU
|
||||||
from.Row = rowStart
|
from.Row = rowStart
|
||||||
from.RowOff = opts.Format.OffsetY * EMU
|
from.RowOff = format.OffsetY * EMU
|
||||||
to := xlsxTo{}
|
to := xlsxTo{}
|
||||||
to.Col = colEnd
|
to.Col = colEnd
|
||||||
to.ColOff = x2 * EMU
|
to.ColOff = x2 * EMU
|
||||||
|
@ -352,6 +350,17 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *Shape) erro
|
||||||
to.RowOff = y2 * EMU
|
to.RowOff = y2 * EMU
|
||||||
twoCellAnchor.From = &from
|
twoCellAnchor.From = &from
|
||||||
twoCellAnchor.To = &to
|
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
|
var solidColor string
|
||||||
if len(opts.Fill.Color) == 1 {
|
if len(opts.Fill.Color) == 1 {
|
||||||
solidColor = opts.Fill.Color[0]
|
solidColor = opts.Fill.Color[0]
|
||||||
|
@ -462,7 +471,7 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *Shape) erro
|
||||||
FLocksWithSheet: *opts.Format.Locked,
|
FLocksWithSheet: *opts.Format.Locked,
|
||||||
FPrintsWithSheet: *opts.Format.PrintObject,
|
FPrintsWithSheet: *opts.Format.PrintObject,
|
||||||
}
|
}
|
||||||
content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
content.TwoCellAnchor = append(content.TwoCellAnchor, twoCellAnchor)
|
||||||
f.Drawings.Store(drawingXML, content)
|
f.Drawings.Store(drawingXML, content)
|
||||||
return err
|
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
|
err error
|
||||||
idx int
|
idx int
|
||||||
appendMode bool
|
appendMode bool
|
||||||
decodeExtLst = new(decodeWorksheetExt)
|
decodeExtLst = new(decodeExtLst)
|
||||||
decodeSparklineGroups *decodeX14SparklineGroups
|
decodeSparklineGroups *decodeX14SparklineGroups
|
||||||
ext *xlsxWorksheetExt
|
ext *xlsxExt
|
||||||
sparklineGroupsBytes, sparklineGroupBytes, extLstBytes []byte
|
sparklineGroupsBytes, sparklineGroupBytes, extLstBytes []byte
|
||||||
)
|
)
|
||||||
sparklineGroupBytes, _ = xml.Marshal(group)
|
sparklineGroupBytes, _ = xml.Marshal(group)
|
||||||
|
@ -523,7 +523,7 @@ func (f *File) appendSparkline(ws *xlsxWorksheet, group *xlsxX14SparklineGroup,
|
||||||
XMLNSXM: NameSpaceSpreadSheetExcel2006Main.Value,
|
XMLNSXM: NameSpaceSpreadSheetExcel2006Main.Value,
|
||||||
SparklineGroups: []*xlsxX14SparklineGroup{group},
|
SparklineGroups: []*xlsxX14SparklineGroup{group},
|
||||||
})
|
})
|
||||||
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxWorksheetExt{
|
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxExt{
|
||||||
URI: ExtURISparklineGroups, Content: string(sparklineGroupsBytes),
|
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
|
err error
|
||||||
idx int
|
idx int
|
||||||
appendMode bool
|
appendMode bool
|
||||||
decodeExtLst = new(decodeWorksheetExt)
|
decodeExtLst = new(decodeExtLst)
|
||||||
condFmts *xlsxX14ConditionalFormattings
|
condFmts *xlsxX14ConditionalFormattings
|
||||||
decodeCondFmts *decodeX14ConditionalFormattings
|
decodeCondFmts *decodeX14ConditionalFormattings
|
||||||
ext *xlsxWorksheetExt
|
ext *xlsxExt
|
||||||
condFmtBytes, condFmtsBytes, extLstBytes []byte
|
condFmtBytes, condFmtsBytes, extLstBytes []byte
|
||||||
)
|
)
|
||||||
condFmtBytes, _ = xml.Marshal([]*xlsxX14ConditionalFormatting{
|
condFmtBytes, _ = xml.Marshal([]*xlsxX14ConditionalFormatting{
|
||||||
|
@ -2645,7 +2645,7 @@ func (f *File) appendCfRule(ws *xlsxWorksheet, rule *xlsxX14CfRule) error {
|
||||||
}
|
}
|
||||||
if !appendMode {
|
if !appendMode {
|
||||||
condFmtsBytes, _ = xml.Marshal(&xlsxX14ConditionalFormattings{Content: string(condFmtBytes)})
|
condFmtsBytes, _ = xml.Marshal(&xlsxX14ConditionalFormattings{Content: string(condFmtBytes)})
|
||||||
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxWorksheetExt{
|
decodeExtLst.Ext = append(decodeExtLst.Ext, &xlsxExt{
|
||||||
URI: ExtURIConditionalFormattings, Content: string(condFmtsBytes),
|
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 {
|
for _, ext := range extLst.Ext {
|
||||||
if ext.URI == ExtURIConditionalFormattings {
|
if ext.URI == ExtURIConditionalFormattings {
|
||||||
decodeCondFmts := new(decodeX14ConditionalFormattings)
|
decodeCondFmts := new(decodeX14ConditionalFormattings)
|
||||||
|
@ -2797,7 +2797,7 @@ func extractCondFmtDataBar(c *xlsxCfRule, extLst *xlsxExtLst) ConditionalFormatO
|
||||||
if c.ExtLst != nil {
|
if c.ExtLst != nil {
|
||||||
ext := decodeX14ConditionalFormattingExt{}
|
ext := decodeX14ConditionalFormattingExt{}
|
||||||
if err := xml.Unmarshal([]byte(c.ExtLst.Ext), &ext); err == nil && extLst != nil {
|
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 {
|
if err = xml.Unmarshal([]byte("<extLst>"+extLst.Ext+"</extLst>"), decodeExtLst); err == nil {
|
||||||
extractExtLst(decodeExtLst)
|
extractExtLst(decodeExtLst)
|
||||||
}
|
}
|
||||||
|
|
15
table.go
15
table.go
|
@ -151,6 +151,7 @@ func (f *File) GetTables(sheet string) ([]Table, error) {
|
||||||
}
|
}
|
||||||
table := Table{
|
table := Table{
|
||||||
rID: tbl.RID,
|
rID: tbl.RID,
|
||||||
|
tID: t.ID,
|
||||||
Range: t.Ref,
|
Range: t.Ref,
|
||||||
Name: t.Name,
|
Name: t.Name,
|
||||||
}
|
}
|
||||||
|
@ -216,7 +217,15 @@ func (f *File) countTables() int {
|
||||||
count := 0
|
count := 0
|
||||||
f.Pkg.Range(func(k, v interface{}) bool {
|
f.Pkg.Range(func(k, v interface{}) bool {
|
||||||
if strings.Contains(k.(string), "xl/tables/table") {
|
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
|
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.AutoFilter = nil
|
||||||
t.HeaderRowCount = intPtr(0)
|
t.HeaderRowCount = intPtr(0)
|
||||||
}
|
}
|
||||||
table, _ := xml.Marshal(t)
|
table, err := xml.Marshal(t)
|
||||||
f.saveFileList(tableXML, table)
|
f.saveFileList(tableXML, table)
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutoFilter provides the method to add auto filter in a worksheet by given
|
// 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
|
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 (
|
const (
|
||||||
defaultXMLPathContentTypes = "[Content_Types].xml"
|
defaultXMLPathContentTypes = "[Content_Types].xml"
|
||||||
defaultXMLPathDocPropsApp = "docProps/app.xml"
|
defaultXMLPathDocPropsApp = "docProps/app.xml"
|
||||||
|
@ -27,6 +211,59 @@ const (
|
||||||
defaultTempFileSST = "sharedStrings"
|
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 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>`
|
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.
|
// appearance of the shape to be stored.
|
||||||
type decodeNvSpPr struct {
|
type decodeNvSpPr struct {
|
||||||
CNvPr *decodeCNvPr `xml:"cNvPr"`
|
CNvPr *decodeCNvPr `xml:"cNvPr"`
|
||||||
ExtLst *decodeExt `xml:"extLst"`
|
ExtLst *decodeAExt `xml:"extLst"`
|
||||||
CNvSpPr *decodeCNvSpPr `xml:"cNvSpPr"`
|
CNvSpPr *decodeCNvSpPr `xml:"cNvSpPr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,10 +78,11 @@ type decodeWsDr struct {
|
||||||
// information that does not affect the appearance of the picture to be
|
// information that does not affect the appearance of the picture to be
|
||||||
// stored.
|
// stored.
|
||||||
type decodeCNvPr struct {
|
type decodeCNvPr struct {
|
||||||
ID int `xml:"id,attr"`
|
XMLName xml.Name `xml:"cNvPr"`
|
||||||
Name string `xml:"name,attr"`
|
ID int `xml:"id,attr"`
|
||||||
Descr string `xml:"descr,attr"`
|
Name string `xml:"name,attr"`
|
||||||
Title string `xml:"title,attr,omitempty"`
|
Descr string `xml:"descr,attr"`
|
||||||
|
Title string `xml:"title,attr,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodePicLocks directly maps the picLocks (Picture Locks). This element
|
// decodePicLocks directly maps the picLocks (Picture Locks). This element
|
||||||
|
@ -124,8 +125,8 @@ type decodeOff struct {
|
||||||
Y int `xml:"y,attr"`
|
Y int `xml:"y,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeExt directly maps the ext element.
|
// decodeAExt directly maps the a:ext element.
|
||||||
type decodeExt struct {
|
type decodeAExt struct {
|
||||||
Cx int `xml:"cx,attr"`
|
Cx int `xml:"cx,attr"`
|
||||||
Cy int `xml:"cy,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
|
// frame. This transformation is applied to the graphic frame just as it would
|
||||||
// be for a shape or group shape.
|
// be for a shape or group shape.
|
||||||
type decodeXfrm struct {
|
type decodeXfrm struct {
|
||||||
Off decodeOff `xml:"off"`
|
Off decodeOff `xml:"off"`
|
||||||
Ext decodeExt `xml:"ext"`
|
Ext decodeAExt `xml:"ext"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing
|
// decodeCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing
|
||||||
|
|
263
xmlDrawing.go
263
xmlDrawing.go
|
@ -16,220 +16,6 @@ import (
|
||||||
"sync"
|
"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
|
// xlsxCNvPr directly maps the cNvPr (Non-Visual Drawing Properties). This
|
||||||
// element specifies non-visual canvas properties. This allows for additional
|
// element specifies non-visual canvas properties. This allows for additional
|
||||||
// information that does not affect the appearance of the picture to be stored.
|
// 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"`
|
Y int `xml:"y,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxExt directly maps the ext element.
|
// aExt directly maps the a:ext element.
|
||||||
type xlsxExt struct {
|
type aExt struct {
|
||||||
Cx int `xml:"cx,attr"`
|
Cx int `xml:"cx,attr"`
|
||||||
Cy int `xml:"cy,attr"`
|
Cy int `xml:"cy,attr"`
|
||||||
}
|
}
|
||||||
|
@ -317,7 +103,7 @@ type xlsxPrstGeom struct {
|
||||||
// be for a shape or group shape.
|
// be for a shape or group shape.
|
||||||
type xlsxXfrm struct {
|
type xlsxXfrm struct {
|
||||||
Off xlsxOff `xml:"a:off"`
|
Off xlsxOff `xml:"a:off"`
|
||||||
Ext xlsxExt `xml:"a:ext"`
|
Ext aExt `xml:"a:ext"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxCNvPicPr directly maps the cNvPicPr (Non-Visual Picture Drawing
|
// 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
|
// 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.
|
// maximum value of less than or equal to 20116800.
|
||||||
type xlsxLineProperties struct {
|
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
|
// 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
|
// but are used here to describe the visual appearance of a picture within a
|
||||||
// document.
|
// document.
|
||||||
type xlsxSpPr struct {
|
type xlsxSpPr struct {
|
||||||
Xfrm xlsxXfrm `xml:"a:xfrm"`
|
Xfrm xlsxXfrm `xml:"a:xfrm"`
|
||||||
PrstGeom xlsxPrstGeom `xml:"a:prstGeom"`
|
PrstGeom xlsxPrstGeom `xml:"a:prstGeom"`
|
||||||
Ln xlsxLineProperties `xml:"a:ln"`
|
SolidFill *xlsxInnerXML `xml:"a:solidFill"`
|
||||||
|
Ln xlsxLineProperties `xml:"a:ln"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxPic elements encompass the definition of pictures within the DrawingML
|
// xlsxPic elements encompass the definition of pictures within the DrawingML
|
||||||
|
@ -426,20 +214,20 @@ type xdrClientData struct {
|
||||||
FPrintsWithSheet bool `xml:"fPrintsWithSheet,attr"`
|
FPrintsWithSheet bool `xml:"fPrintsWithSheet,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xdrCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape Size)
|
// xdrCellAnchor specifies a oneCellAnchor (One Cell Anchor Shape Size) and
|
||||||
// and twoCellAnchor (Two Cell Anchor Shape Size). This element specifies a two
|
// twoCellAnchor (Two Cell Anchor Shape Size) placeholder for a group, a shape,
|
||||||
// cell anchor placeholder for a group, a shape, or a drawing element. It moves
|
// or a drawing element. It moves with cells and its extents are in EMU units.
|
||||||
// with cells and its extents are in EMU units.
|
|
||||||
type xdrCellAnchor struct {
|
type xdrCellAnchor struct {
|
||||||
EditAs string `xml:"editAs,attr,omitempty"`
|
EditAs string `xml:"editAs,attr,omitempty"`
|
||||||
Pos *xlsxPoint2D `xml:"xdr:pos"`
|
Pos *xlsxPoint2D `xml:"xdr:pos"`
|
||||||
From *xlsxFrom `xml:"xdr:from"`
|
From *xlsxFrom `xml:"xdr:from"`
|
||||||
To *xlsxTo `xml:"xdr:to"`
|
To *xlsxTo `xml:"xdr:to"`
|
||||||
Ext *xlsxExt `xml:"xdr:ext"`
|
Ext *aExt `xml:"xdr:ext"`
|
||||||
Sp *xdrSp `xml:"xdr:sp"`
|
Sp *xdrSp `xml:"xdr:sp"`
|
||||||
Pic *xlsxPic `xml:"xdr:pic,omitempty"`
|
Pic *xlsxPic `xml:"xdr:pic,omitempty"`
|
||||||
GraphicFrame string `xml:",innerxml"`
|
GraphicFrame string `xml:",innerxml"`
|
||||||
ClientData *xdrClientData `xml:"xdr:clientData"`
|
AlternateContent []*xlsxAlternateContent `xml:"mc:AlternateContent"`
|
||||||
|
ClientData *xdrClientData `xml:"xdr:clientData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxPoint2D describes the position of a drawing element within a spreadsheet.
|
// xlsxPoint2D describes the position of a drawing element within a spreadsheet.
|
||||||
|
@ -503,6 +291,12 @@ type xlsxGraphic struct {
|
||||||
type xlsxGraphicData struct {
|
type xlsxGraphicData struct {
|
||||||
URI string `xml:"uri,attr"`
|
URI string `xml:"uri,attr"`
|
||||||
Chart *xlsxChart `xml:"c:chart,omitempty"`
|
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.
|
// 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
|
// This shape is specified along with all other shapes within either the shape
|
||||||
// tree or group shape elements.
|
// tree or group shape elements.
|
||||||
type xdrSp struct {
|
type xdrSp struct {
|
||||||
|
XMLName xml.Name `xml:"xdr:sp"`
|
||||||
Macro string `xml:"macro,attr"`
|
Macro string `xml:"macro,attr"`
|
||||||
Textlink string `xml:"textlink,attr"`
|
Textlink string `xml:"textlink,attr"`
|
||||||
NvSpPr *xdrNvSpPr `xml:"xdr:nvSpPr"`
|
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"`
|
Alignment *xlsxAlignment `xml:"alignment"`
|
||||||
Border *xlsxBorder `xml:"border"`
|
Border *xlsxBorder `xml:"border"`
|
||||||
Protection *xlsxProtection `xml:"protection"`
|
Protection *xlsxProtection `xml:"protection"`
|
||||||
ExtLst *xlsxExt `xml:"extLst"`
|
ExtLst *aExt `xml:"extLst"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// xlsxTableStyles directly maps the tableStyles element. This element
|
// 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.
|
// a custom color has been selected while using this workbook.
|
||||||
type xlsxStyleColors struct {
|
type xlsxStyleColors struct {
|
||||||
IndexedColors *xlsxIndexedColors `xml:"indexedColors"`
|
IndexedColors *xlsxIndexedColors `xml:"indexedColors"`
|
||||||
MruColors xlsxInnerXML `xml:"mruColors"`
|
MruColors *xlsxInnerXML `xml:"mruColors"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alignment directly maps the alignment settings of the cells.
|
// 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.
|
// Table directly maps the format settings of the table.
|
||||||
type Table struct {
|
type Table struct {
|
||||||
|
tID int
|
||||||
rID string
|
rID string
|
||||||
Range string
|
Range string
|
||||||
Name string
|
Name string
|
||||||
|
|
|
@ -16,7 +16,8 @@ import (
|
||||||
"sync"
|
"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 {
|
type xlsxRelationships struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`
|
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`
|
||||||
|
@ -218,6 +219,63 @@ type xlsxExtLst struct {
|
||||||
Ext string `xml:",innerxml"`
|
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
|
// xlsxDefinedNames directly maps the definedNames element. This element defines
|
||||||
// the collection of defined names for this workbook. Defined names are
|
// the collection of defined names for this workbook. Defined names are
|
||||||
// descriptive names to represent cells, ranges of cells, formulas, or constant
|
// 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"`
|
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.
|
// decodeX14SparklineGroups directly maps the sparklineGroups element.
|
||||||
type decodeX14SparklineGroups struct {
|
type decodeX14SparklineGroups struct {
|
||||||
XMLName xml.Name `xml:"sparklineGroups"`
|
XMLName xml.Name `xml:"sparklineGroups"`
|
||||||
|
@ -733,8 +706,7 @@ type decodeX14SparklineGroups struct {
|
||||||
Content string `xml:",innerxml"`
|
Content string `xml:",innerxml"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeX14ConditionalFormattingExt directly maps the ext
|
// decodeX14ConditionalFormattingExt directly maps the ext element.
|
||||||
// element.
|
|
||||||
type decodeX14ConditionalFormattingExt struct {
|
type decodeX14ConditionalFormattingExt struct {
|
||||||
XMLName xml.Name `xml:"ext"`
|
XMLName xml.Name `xml:"ext"`
|
||||||
ID string `xml:"id"`
|
ID string `xml:"id"`
|
||||||
|
|
Loading…
Reference in New Issue