Browse Source

Extend pivot table funtionality (#692)

Add different pivot options
Add header options to pivot table opts
Add Style name options to pivot table opts
Eugene Androsov 5 years ago
parent
commit
97bffe608d
3 changed files with 117 additions and 37 deletions
  1. 94 28
      pivotTable.go
  2. 14 0
      xmlPivotCache.go
  3. 9 9
      xmlPivotTable.go

+ 94 - 28
pivotTable.go

@@ -21,12 +21,25 @@ import (
 
 
 // PivotTableOption directly maps the format settings of the pivot table.
 // PivotTableOption directly maps the format settings of the pivot table.
 type PivotTableOption struct {
 type PivotTableOption struct {
-	DataRange       string
-	PivotTableRange string
-	Rows            []PivotTableField
-	Columns         []PivotTableField
-	Data            []PivotTableField
-	Filter          []PivotTableField
+	DataRange           string
+	PivotTableRange     string
+	Rows                []PivotTableField
+	Columns             []PivotTableField
+	Data                []PivotTableField
+	Filter              []PivotTableField
+	RowGrandTotals      bool
+	ColGrandTotals      bool
+	ShowDrill           bool
+	UseAutoFormatting   bool
+	PageOverThenDown    bool
+	MergeItem           bool
+	CompactData         bool
+	ShowRowHeaders      bool
+	ShowColHeaders      bool
+	ShowRowStripes      bool
+	ShowColStripes      bool
+	ShowLastColumn      bool
+	PivotTableStyleName string
 }
 }
 
 
 // PivotTableField directly maps the field settings of the pivot table.
 // PivotTableField directly maps the field settings of the pivot table.
@@ -49,9 +62,10 @@ type PivotTableOption struct {
 // Name specifies the name of the data field. Maximum 255 characters
 // Name specifies the name of the data field. Maximum 255 characters
 // are allowed in data field name, excess characters will be truncated.
 // are allowed in data field name, excess characters will be truncated.
 type PivotTableField struct {
 type PivotTableField struct {
-	Data     string
-	Name     string
-	Subtotal string
+	Data            string
+	Name            string
+	Subtotal        string
+	DefaultSubtotal bool
 }
 }
 
 
 // AddPivotTable provides the method to add pivot table by given pivot table
 // AddPivotTable provides the method to add pivot table by given pivot table
@@ -233,12 +247,25 @@ func (f *File) addPivotCache(pivotCacheID int, pivotCacheXML string, opt *PivotT
 		},
 		},
 		CacheFields: &xlsxCacheFields{},
 		CacheFields: &xlsxCacheFields{},
 	}
 	}
+
 	for _, name := range order {
 	for _, name := range order {
+		defaultRowsSubtotal, rowOk := f.getPivotTableFieldNameDefaultSubtotal(name, opt.Rows)
+		defaultColumnsSubtotal, colOk := f.getPivotTableFieldNameDefaultSubtotal(name, opt.Columns)
+		sharedItems := xlsxSharedItems{
+			Count: 0,
+		}
+		s := xlsxString{}
+		if (rowOk && !defaultRowsSubtotal) || (colOk && !defaultColumnsSubtotal) {
+			s = xlsxString{
+				V: "",
+			}
+			sharedItems.Count++
+			sharedItems.S = &s
+		}
+
 		pc.CacheFields.CacheField = append(pc.CacheFields.CacheField, &xlsxCacheField{
 		pc.CacheFields.CacheField = append(pc.CacheFields.CacheField, &xlsxCacheField{
-			Name: name,
-			SharedItems: &xlsxSharedItems{
-				Count: 0,
-			},
+			Name:        name,
+			SharedItems: &sharedItems,
 		})
 		})
 	}
 	}
 	pc.CacheFields.Count = len(pc.CacheFields.CacheField)
 	pc.CacheFields.Count = len(pc.CacheFields.CacheField)
@@ -259,10 +286,24 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, op
 	hcell, _ := CoordinatesToCellName(coordinates[0], coordinates[1])
 	hcell, _ := CoordinatesToCellName(coordinates[0], coordinates[1])
 	vcell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
 	vcell, _ := CoordinatesToCellName(coordinates[2], coordinates[3])
 
 
+	pivotTableStyle := func() string {
+		if opt.PivotTableStyleName == "" {
+			return "PivotStyleLight16"
+		} else {
+			return opt.PivotTableStyleName
+		}
+	}
 	pt := xlsxPivotTableDefinition{
 	pt := xlsxPivotTableDefinition{
-		Name:        fmt.Sprintf("Pivot Table%d", pivotTableID),
-		CacheID:     cacheID,
-		DataCaption: "Values",
+		Name:              fmt.Sprintf("Pivot Table%d", pivotTableID),
+		CacheID:           cacheID,
+		RowGrandTotals:    &opt.RowGrandTotals,
+		ColGrandTotals:    &opt.ColGrandTotals,
+		ShowDrill:         &opt.ShowDrill,
+		UseAutoFormatting: &opt.UseAutoFormatting,
+		PageOverThenDown:  &opt.PageOverThenDown,
+		MergeItem:         &opt.MergeItem,
+		CompactData:       &opt.CompactData,
+		DataCaption:       "Values",
 		Location: &xlsxLocation{
 		Location: &xlsxLocation{
 			Ref:            hcell + ":" + vcell,
 			Ref:            hcell + ":" + vcell,
 			FirstDataCol:   1,
 			FirstDataCol:   1,
@@ -283,10 +324,12 @@ func (f *File) addPivotTable(cacheID, pivotTableID int, pivotTableXML string, op
 			I:     []*xlsxI{{}},
 			I:     []*xlsxI{{}},
 		},
 		},
 		PivotTableStyleInfo: &xlsxPivotTableStyleInfo{
 		PivotTableStyleInfo: &xlsxPivotTableStyleInfo{
-			Name:           "PivotStyleLight16",
-			ShowRowHeaders: true,
-			ShowColHeaders: true,
-			ShowLastColumn: true,
+			Name:           pivotTableStyle(),
+			ShowRowHeaders: opt.ShowRowHeaders,
+			ShowColHeaders: opt.ShowColHeaders,
+			ShowRowStripes: opt.ShowRowStripes,
+			ShowColStripes: opt.ShowColStripes,
+			ShowLastColumn: opt.ShowLastColumn,
 		},
 		},
 	}
 	}
 
 
@@ -440,17 +483,25 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOptio
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	x := 0
 	for _, name := range order {
 	for _, name := range order {
 		if inPivotTableField(opt.Rows, name) != -1 {
 		if inPivotTableField(opt.Rows, name) != -1 {
+			defaultSubtotal, ok := f.getPivotTableFieldNameDefaultSubtotal(name, opt.Rows)
+			var items []*xlsxItem
+			if !ok || !defaultSubtotal {
+				items = append(items, &xlsxItem{X: &x})
+			} else {
+				items = append(items, &xlsxItem{T: "default"})
+			}
+
 			pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
 			pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
 				Axis: "axisRow",
 				Axis: "axisRow",
 				Name: f.getPivotTableFieldName(name, opt.Rows),
 				Name: f.getPivotTableFieldName(name, opt.Rows),
 				Items: &xlsxItems{
 				Items: &xlsxItems{
-					Count: 1,
-					Item: []*xlsxItem{
-						{T: "default"},
-					},
+					Count: len(items),
+					Item:  items,
 				},
 				},
+				DefaultSubtotal: &defaultSubtotal,
 			})
 			})
 			continue
 			continue
 		}
 		}
@@ -468,15 +519,21 @@ func (f *File) addPivotFields(pt *xlsxPivotTableDefinition, opt *PivotTableOptio
 			continue
 			continue
 		}
 		}
 		if inPivotTableField(opt.Columns, name) != -1 {
 		if inPivotTableField(opt.Columns, name) != -1 {
+			defaultSubtotal, ok := f.getPivotTableFieldNameDefaultSubtotal(name, opt.Columns)
+			var items []*xlsxItem
+			if !ok || !defaultSubtotal {
+				items = append(items, &xlsxItem{X: &x})
+			} else {
+				items = append(items, &xlsxItem{T: "default"})
+			}
 			pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
 			pt.PivotFields.PivotField = append(pt.PivotFields.PivotField, &xlsxPivotField{
 				Axis: "axisCol",
 				Axis: "axisCol",
 				Name: f.getPivotTableFieldName(name, opt.Columns),
 				Name: f.getPivotTableFieldName(name, opt.Columns),
 				Items: &xlsxItems{
 				Items: &xlsxItems{
-					Count: 1,
-					Item: []*xlsxItem{
-						{T: "default"},
-					},
+					Count: len(items),
+					Item:  items,
 				},
 				},
+				DefaultSubtotal: &defaultSubtotal,
 			})
 			})
 			continue
 			continue
 		}
 		}
@@ -574,6 +631,15 @@ func (f *File) getPivotTableFieldName(name string, fields []PivotTableField) str
 	return ""
 	return ""
 }
 }
 
 
+func (f *File) getPivotTableFieldNameDefaultSubtotal(name string, fields []PivotTableField) (bool, bool) {
+	for _, field := range fields {
+		if field.Data == name {
+			return field.DefaultSubtotal, true
+		}
+	}
+	return false, false
+}
+
 // addWorkbookPivotCache add the association ID of the pivot cache in xl/workbook.xml.
 // addWorkbookPivotCache add the association ID of the pivot cache in xl/workbook.xml.
 func (f *File) addWorkbookPivotCache(RID int) int {
 func (f *File) addWorkbookPivotCache(RID int) int {
 	wb := f.workbookReader()
 	wb := f.workbookReader()

+ 14 - 0
xmlPivotCache.go

@@ -182,6 +182,20 @@ type xlsxError struct {
 
 
 // xlsxString represents a character value in a PivotTable.
 // xlsxString represents a character value in a PivotTable.
 type xlsxString struct {
 type xlsxString struct {
+	V    string      `xml:"v,attr"`
+	U    bool        `xml:"u,attr,omitempty"`
+	F    bool        `xml:"f,attr,omitempty"`
+	C    string      `xml:"c,attr,omitempty"`
+	Cp   int         `xml:"cp,attr,omitempty"`
+	In   int         `xml:"in,attr,omitempty"`
+	Bc   string      `xml:"bc,attr,omitempty"`
+	Fc   string      `xml:"fc,attr,omitempty"`
+	I    bool        `xml:"i,attr,omitempty"`
+	Un   bool        `xml:"un,attr,omitempty"`
+	St   bool        `xml:"st,attr,omitempty"`
+	B    bool        `xml:"b,attr,omitempty"`
+	Tpls *xlsxTuples `xml:"tpls"`
+	X    *attrValInt `xml:"x"`
 }
 }
 
 
 // xlsxDateTime represents a date-time value in the PivotTable.
 // xlsxDateTime represents a date-time value in the PivotTable.

+ 9 - 9
xmlPivotTable.go

@@ -48,7 +48,7 @@ type xlsxPivotTableDefinition struct {
 	VisualTotals            bool                     `xml:"visualTotals,attr,omitempty"`
 	VisualTotals            bool                     `xml:"visualTotals,attr,omitempty"`
 	ShowMultipleLabel       bool                     `xml:"showMultipleLabel,attr,omitempty"`
 	ShowMultipleLabel       bool                     `xml:"showMultipleLabel,attr,omitempty"`
 	ShowDataDropDown        bool                     `xml:"showDataDropDown,attr,omitempty"`
 	ShowDataDropDown        bool                     `xml:"showDataDropDown,attr,omitempty"`
-	ShowDrill               bool                     `xml:"showDrill,attr,omitempty"`
+	ShowDrill               *bool                    `xml:"showDrill,attr,omitempty"`
 	PrintDrill              bool                     `xml:"printDrill,attr,omitempty"`
 	PrintDrill              bool                     `xml:"printDrill,attr,omitempty"`
 	ShowMemberPropertyTips  bool                     `xml:"showMemberPropertyTips,attr,omitempty"`
 	ShowMemberPropertyTips  bool                     `xml:"showMemberPropertyTips,attr,omitempty"`
 	ShowDataTips            bool                     `xml:"showDataTips,attr,omitempty"`
 	ShowDataTips            bool                     `xml:"showDataTips,attr,omitempty"`
@@ -56,15 +56,15 @@ type xlsxPivotTableDefinition struct {
 	EnableDrill             bool                     `xml:"enableDrill,attr,omitempty"`
 	EnableDrill             bool                     `xml:"enableDrill,attr,omitempty"`
 	EnableFieldProperties   bool                     `xml:"enableFieldProperties,attr,omitempty"`
 	EnableFieldProperties   bool                     `xml:"enableFieldProperties,attr,omitempty"`
 	PreserveFormatting      bool                     `xml:"preserveFormatting,attr,omitempty"`
 	PreserveFormatting      bool                     `xml:"preserveFormatting,attr,omitempty"`
-	UseAutoFormatting       bool                     `xml:"useAutoFormatting,attr,omitempty"`
+	UseAutoFormatting       *bool                    `xml:"useAutoFormatting,attr,omitempty"`
 	PageWrap                int                      `xml:"pageWrap,attr,omitempty"`
 	PageWrap                int                      `xml:"pageWrap,attr,omitempty"`
-	PageOverThenDown        bool                     `xml:"pageOverThenDown,attr,omitempty"`
+	PageOverThenDown        *bool                    `xml:"pageOverThenDown,attr,omitempty"`
 	SubtotalHiddenItems     bool                     `xml:"subtotalHiddenItems,attr,omitempty"`
 	SubtotalHiddenItems     bool                     `xml:"subtotalHiddenItems,attr,omitempty"`
-	RowGrandTotals          bool                     `xml:"rowGrandTotals,attr,omitempty"`
-	ColGrandTotals          bool                     `xml:"colGrandTotals,attr,omitempty"`
+	RowGrandTotals          *bool                    `xml:"rowGrandTotals,attr,omitempty"`
+	ColGrandTotals          *bool                    `xml:"colGrandTotals,attr,omitempty"`
 	FieldPrintTitles        bool                     `xml:"fieldPrintTitles,attr,omitempty"`
 	FieldPrintTitles        bool                     `xml:"fieldPrintTitles,attr,omitempty"`
 	ItemPrintTitles         bool                     `xml:"itemPrintTitles,attr,omitempty"`
 	ItemPrintTitles         bool                     `xml:"itemPrintTitles,attr,omitempty"`
-	MergeItem               bool                     `xml:"mergeItem,attr,omitempty"`
+	MergeItem               *bool                    `xml:"mergeItem,attr,omitempty"`
 	ShowDropZones           bool                     `xml:"showDropZones,attr,omitempty"`
 	ShowDropZones           bool                     `xml:"showDropZones,attr,omitempty"`
 	CreatedVersion          int                      `xml:"createdVersion,attr,omitempty"`
 	CreatedVersion          int                      `xml:"createdVersion,attr,omitempty"`
 	Indent                  int                      `xml:"indent,attr,omitempty"`
 	Indent                  int                      `xml:"indent,attr,omitempty"`
@@ -74,7 +74,7 @@ type xlsxPivotTableDefinition struct {
 	Compact                 bool                     `xml:"compact,attr"`
 	Compact                 bool                     `xml:"compact,attr"`
 	Outline                 bool                     `xml:"outline,attr"`
 	Outline                 bool                     `xml:"outline,attr"`
 	OutlineData             bool                     `xml:"outlineData,attr,omitempty"`
 	OutlineData             bool                     `xml:"outlineData,attr,omitempty"`
-	CompactData             bool                     `xml:"compactData,attr,omitempty"`
+	CompactData             *bool                    `xml:"compactData,attr,omitempty"`
 	Published               bool                     `xml:"published,attr,omitempty"`
 	Published               bool                     `xml:"published,attr,omitempty"`
 	GridDropZones           bool                     `xml:"gridDropZones,attr,omitempty"`
 	GridDropZones           bool                     `xml:"gridDropZones,attr,omitempty"`
 	Immersive               bool                     `xml:"immersive,attr,omitempty"`
 	Immersive               bool                     `xml:"immersive,attr,omitempty"`
@@ -150,7 +150,7 @@ type xlsxPivotField struct {
 	DataSourceSort               bool               `xml:"dataSourceSort,attr,omitempty"`
 	DataSourceSort               bool               `xml:"dataSourceSort,attr,omitempty"`
 	NonAutoSortDefault           bool               `xml:"nonAutoSortDefault,attr,omitempty"`
 	NonAutoSortDefault           bool               `xml:"nonAutoSortDefault,attr,omitempty"`
 	RankBy                       int                `xml:"rankBy,attr,omitempty"`
 	RankBy                       int                `xml:"rankBy,attr,omitempty"`
-	DefaultSubtotal              bool               `xml:"defaultSubtotal,attr,omitempty"`
+	DefaultSubtotal              *bool              `xml:"defaultSubtotal,attr,omitempty"`
 	SumSubtotal                  bool               `xml:"sumSubtotal,attr,omitempty"`
 	SumSubtotal                  bool               `xml:"sumSubtotal,attr,omitempty"`
 	CountASubtotal               bool               `xml:"countASubtotal,attr,omitempty"`
 	CountASubtotal               bool               `xml:"countASubtotal,attr,omitempty"`
 	AvgSubtotal                  bool               `xml:"avgSubtotal,attr,omitempty"`
 	AvgSubtotal                  bool               `xml:"avgSubtotal,attr,omitempty"`
@@ -189,7 +189,7 @@ type xlsxItem struct {
 	F  bool   `xml:"f,attr,omitempty"`
 	F  bool   `xml:"f,attr,omitempty"`
 	M  bool   `xml:"m,attr,omitempty"`
 	M  bool   `xml:"m,attr,omitempty"`
 	C  bool   `xml:"c,attr,omitempty"`
 	C  bool   `xml:"c,attr,omitempty"`
-	X  int    `xml:"x,attr,omitempty"`
+	X  *int   `xml:"x,attr,omitempty"`
 	D  bool   `xml:"d,attr,omitempty"`
 	D  bool   `xml:"d,attr,omitempty"`
 	E  bool   `xml:"e,attr,omitempty"`
 	E  bool   `xml:"e,attr,omitempty"`
 }
 }