summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2020-03-28 23:47:26 +0800
committerxuri <xuri.me@gmail.com>2020-03-28 23:47:26 +0800
commit6afc468a025984aa1b265b0228f032c5ed881a3b (patch)
tree6b51e97cbf9c5fc151bb14766c720731ec3bc2ad
parenta75c6f63bea6c8e438482cb79e1725f23d7f7f9c (diff)
Resolve #451, support create chart sheet
-rw-r--r--LICENSE1
-rw-r--r--chart.go68
-rw-r--r--chart_test.go23
-rw-r--r--drawing.go63
-rw-r--r--excelize.go23
-rw-r--r--picture.go16
-rw-r--r--sheet.go16
-rw-r--r--styles.go2
-rw-r--r--xmlChartSheet.go2
-rw-r--r--xmlDrawing.go101
-rw-r--r--xmlWorksheet.go3
11 files changed, 239 insertions, 79 deletions
diff --git a/LICENSE b/LICENSE
index 51ec1fb..fe738b9 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,6 @@
BSD 3-Clause License
Copyright (c) 2016-2020, 360 Enterprise Security Group, Endpoint Security, Inc.
-Copyright (c) 2011-2017, Geoffrey J. Teale
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/chart.go b/chart.go
index 69c2c95..df196e9 100644
--- a/chart.go
+++ b/chart.go
@@ -11,7 +11,9 @@ package excelize
import (
"encoding/json"
+ "encoding/xml"
"errors"
+ "fmt"
"strconv"
"strings"
)
@@ -768,6 +770,72 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
return err
}
+// AddChartSheet provides the method to create a chartsheet by given chart
+// format set (such as offset, scale, aspect ratio setting and print settings)
+// and properties set. In Excel a chartsheet is a worksheet that only contains
+// a chart.
+func (f *File) AddChartSheet(sheet, format string, combo ...string) error {
+ // Check if the worksheet already exists
+ if f.GetSheetIndex(sheet) != 0 {
+ return errors.New("already existing name worksheet")
+ }
+ formatSet, err := parseFormatChartSet(format)
+ if err != nil {
+ return err
+ }
+ comboCharts := []*formatChart{}
+ for _, comboFormat := range combo {
+ comboChart, err := parseFormatChartSet(comboFormat)
+ if err != nil {
+ return err
+ }
+ if _, ok := chartValAxNumFmtFormatCode[comboChart.Type]; !ok {
+ return errors.New("unsupported chart type " + comboChart.Type)
+ }
+ comboCharts = append(comboCharts, comboChart)
+ }
+ if _, ok := chartValAxNumFmtFormatCode[formatSet.Type]; !ok {
+ return errors.New("unsupported chart type " + formatSet.Type)
+ }
+ cs := xlsxChartsheet{
+ SheetViews: []*xlsxChartsheetViews{{
+ SheetView: []*xlsxChartsheetView{{ZoomScaleAttr: 100, ZoomToFitAttr: true}}},
+ },
+ }
+ wb := f.workbookReader()
+ sheetID := 0
+ for _, v := range wb.Sheets.Sheet {
+ if v.SheetID > sheetID {
+ sheetID = v.SheetID
+ }
+ }
+ sheetID++
+ path := "xl/chartsheets/sheet" + strconv.Itoa(sheetID) + ".xml"
+ f.sheetMap[trimSheetName(sheet)] = path
+ f.Sheet[path] = nil
+ drawingID := f.countDrawings() + 1
+ chartID := f.countCharts() + 1
+ drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
+ drawingID, drawingXML = f.prepareChartSheetDrawing(&cs, drawingID, sheet, drawingXML)
+ drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
+ drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
+ err = f.addSheetDrawingChart(sheet, drawingXML, formatSet.Dimension.Width, formatSet.Dimension.Height, drawingRID, &formatSet.Format)
+ if err != nil {
+ return err
+ }
+ f.addChart(formatSet, comboCharts)
+ f.addContentTypePart(chartID, "chart")
+ f.addContentTypePart(sheetID, "chartsheet")
+ f.addContentTypePart(drawingID, "drawings")
+ // Update xl/_rels/workbook.xml.rels
+ rID := f.addRels("xl/_rels/workbook.xml.rels", SourceRelationshipChartsheet, fmt.Sprintf("chartsheets/sheet%d.xml", sheetID), "")
+ // Update xl/workbook.xml
+ f.setWorkbook(sheet, sheetID, rID)
+ v, _ := xml.Marshal(cs)
+ f.saveFileList(path, replaceRelationshipsBytes(replaceWorkSheetsRelationshipsNameSpaceBytes(v)))
+ return err
+}
+
// DeleteChart provides a function to delete chart in XLSX by given worksheet
// and cell name.
func (f *File) DeleteChart(sheet, cell string) (err error) {
diff --git a/chart_test.go b/chart_test.go
index 98f3555..351e663 100644
--- a/chart_test.go
+++ b/chart_test.go
@@ -200,12 +200,31 @@ func TestAddChart(t *testing.T) {
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddChart.xlsx")))
// Test with unsupported chart type
assert.EqualError(t, f.AddChart("Sheet2", "BD32", `{"type":"unknown","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Bubble 3D Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`), "unsupported chart type unknown")
- // Test add combo chart with invalid format set.
+ // Test add combo chart with invalid format set
assert.EqualError(t, f.AddChart("Sheet2", "BD32", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`, ""), "unexpected end of JSON input")
- // Test add combo chart with unsupported chart type.
+ // Test add combo chart with unsupported chart type
assert.EqualError(t, f.AddChart("Sheet2", "BD64", `{"type":"barOfPie","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$A$30:$D$37","values":"Sheet1!$B$30:$B$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Bar of Pie Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"major_grid_lines":true},"y_axis":{"major_grid_lines":true}}`, `{"type":"unknown","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$A$30:$D$37","values":"Sheet1!$B$30:$B$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Bar of Pie Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"major_grid_lines":true},"y_axis":{"major_grid_lines":true}}`), "unsupported chart type unknown")
}
+func TestAddChartSheet(t *testing.T) {
+ categories := map[string]string{"A2": "Small", "A3": "Normal", "A4": "Large", "B1": "Apple", "C1": "Orange", "D1": "Pear"}
+ values := map[string]int{"B2": 2, "C2": 3, "D2": 3, "B3": 5, "C3": 2, "D3": 4, "B4": 6, "C4": 7, "D4": 8}
+ f := NewFile()
+ for k, v := range categories {
+ assert.NoError(t, f.SetCellValue("Sheet1", k, v))
+ }
+ for k, v := range values {
+ assert.NoError(t, f.SetCellValue("Sheet1", k, v))
+ }
+ assert.NoError(t, f.AddChartSheet("Chart1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`))
+
+ assert.EqualError(t, f.AddChartSheet("Sheet1", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), "already existing name worksheet")
+ // Test with unsupported chart type
+ assert.EqualError(t, f.AddChartSheet("Chart2", `{"type":"unknown","series":[{"name":"Sheet1!$A$2","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$2:$D$2"},{"name":"Sheet1!$A$3","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$3:$D$3"},{"name":"Sheet1!$A$4","categories":"Sheet1!$B$1:$D$1","values":"Sheet1!$B$4:$D$4"}],"title":{"name":"Fruit 3D Clustered Column Chart"}}`), "unsupported chart type unknown")
+
+ assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddChartSheet.xlsx")))
+}
+
func TestDeleteChart(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.NoError(t, err)
diff --git a/drawing.go b/drawing.go
index e51b6af..8ca1f49 100644
--- a/drawing.go
+++ b/drawing.go
@@ -38,6 +38,26 @@ func (f *File) prepareDrawing(xlsx *xlsxWorksheet, drawingID int, sheet, drawing
return drawingID, drawingXML
}
+// prepareChartSheetDrawing provides a function to prepare drawing ID and XML
+// by given drawingID, worksheet name and default drawingXML.
+func (f *File) prepareChartSheetDrawing(xlsx *xlsxChartsheet, drawingID int, sheet, drawingXML string) (int, string) {
+ sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
+ if xlsx.Drawing != nil {
+ // The worksheet already has a picture or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
+ sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID)
+ drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
+ drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
+ } else {
+ // Add first picture for given sheet.
+ sheetRels := "xl/chartsheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/chartsheets/") + ".rels"
+ rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
+ xlsx.Drawing = &xlsxDrawing{
+ RID: "rId" + strconv.Itoa(rID),
+ }
+ }
+ return drawingID, drawingXML
+}
+
// addChart provides a function to create chart as xl/charts/chart%d.xml by
// given format sets.
func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
@@ -1209,6 +1229,49 @@ func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rI
return err
}
+// addSheetDrawingChart provides a function to add chart graphic frame for
+// chartsheet by given sheet, drawingXML, width, height, relationship index
+// and format sets.
+func (f *File) addSheetDrawingChart(sheet, drawingXML string, width, height, rID int, formatSet *formatPicture) (err error) {
+ width = int(float64(width) * formatSet.XScale)
+ height = int(float64(height) * formatSet.YScale)
+
+ content, cNvPrID := f.drawingParser(drawingXML)
+ absoluteAnchor := xdrCellAnchor{
+ EditAs: formatSet.Positioning,
+ Pos: &xlsxPoint2D{},
+ Ext: &xlsxExt{},
+ }
+
+ graphicFrame := xlsxGraphicFrame{
+ NvGraphicFramePr: xlsxNvGraphicFramePr{
+ CNvPr: &xlsxCNvPr{
+ ID: cNvPrID,
+ Name: "Chart " + strconv.Itoa(cNvPrID),
+ },
+ },
+ Graphic: &xlsxGraphic{
+ GraphicData: &xlsxGraphicData{
+ URI: NameSpaceDrawingMLChart,
+ Chart: &xlsxChart{
+ C: NameSpaceDrawingMLChart,
+ R: SourceRelationship,
+ RID: "rId" + strconv.Itoa(rID),
+ },
+ },
+ },
+ }
+ graphic, _ := xml.Marshal(graphicFrame)
+ absoluteAnchor.GraphicFrame = string(graphic)
+ absoluteAnchor.ClientData = &xdrClientData{
+ FLocksWithSheet: formatSet.FLocksWithSheet,
+ FPrintsWithSheet: formatSet.FPrintsWithSheet,
+ }
+ content.AbsoluteAnchor = append(content.AbsoluteAnchor, &absoluteAnchor)
+ f.Drawings[drawingXML] = content
+ return err
+}
+
// deleteDrawing provides a function to delete chart graphic frame by given by
// given coordinates and graphic type.
func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (err error) {
diff --git a/excelize.go b/excelize.go
index 795120d..3dd4311 100644
--- a/excelize.go
+++ b/excelize.go
@@ -228,21 +228,10 @@ func (f *File) addRels(relPath, relType, target, targetMode string) int {
}
// replaceWorkSheetsRelationshipsNameSpaceBytes provides a function to replace
-// xl/worksheets/sheet%d.xml XML tags to self-closing for compatible Microsoft
-// Office Excel 2007.
-func replaceWorkSheetsRelationshipsNameSpaceBytes(workbookMarshal []byte) []byte {
- var oldXmlns = []byte(`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
- var newXmlns = []byte(`<worksheet` + templateNamespaceIDMap)
- workbookMarshal = bytes.Replace(workbookMarshal, oldXmlns, newXmlns, -1)
- return workbookMarshal
-}
-
-// replaceStyleRelationshipsNameSpaceBytes provides a function to replace
-// xl/styles.xml XML tags to self-closing for compatible Microsoft Office
-// Excel 2007.
-func replaceStyleRelationshipsNameSpaceBytes(contentMarshal []byte) []byte {
- var oldXmlns = []byte(`<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
- var newXmlns = []byte(`<styleSheet` + templateNamespaceIDMap)
+// XML tags to self-closing for compatible Microsoft Office Excel 2007.
+func replaceWorkSheetsRelationshipsNameSpaceBytes(contentMarshal []byte) []byte {
+ var oldXmlns = []byte(` xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">`)
+ var newXmlns = []byte(templateNamespaceIDMap)
contentMarshal = bytes.Replace(contentMarshal, oldXmlns, newXmlns, -1)
return contentMarshal
}
@@ -354,13 +343,13 @@ func (f *File) setContentTypePartVBAProjectExtensions() {
}
for idx, o := range content.Overrides {
if o.PartName == "/xl/workbook.xml" {
- content.Overrides[idx].ContentType = "application/vnd.ms-excel.sheet.macroEnabled.main+xml"
+ content.Overrides[idx].ContentType = ContentTypeMacro
}
}
if !ok {
content.Defaults = append(content.Defaults, xlsxDefault{
Extension: "bin",
- ContentType: "application/vnd.ms-office.vbaProject",
+ ContentType: ContentTypeVBA,
})
}
}
diff --git a/picture.go b/picture.go
index 3e24ce3..ddc0480 100644
--- a/picture.go
+++ b/picture.go
@@ -354,7 +354,7 @@ func (f *File) setContentTypePartVMLExtensions() {
if !vml {
content.Defaults = append(content.Defaults, xlsxDefault{
Extension: "vml",
- ContentType: "application/vnd.openxmlformats-officedocument.vmlDrawing",
+ ContentType: ContentTypeVML,
})
}
}
@@ -368,6 +368,7 @@ func (f *File) addContentTypePart(index int, contentType string) {
}
partNames := map[string]string{
"chart": "/xl/charts/chart" + strconv.Itoa(index) + ".xml",
+ "chartsheet": "/xl/chartsheets/sheet" + strconv.Itoa(index) + ".xml",
"comments": "/xl/comments" + strconv.Itoa(index) + ".xml",
"drawings": "/xl/drawings/drawing" + strconv.Itoa(index) + ".xml",
"table": "/xl/tables/table" + strconv.Itoa(index) + ".xml",
@@ -375,12 +376,13 @@ func (f *File) addContentTypePart(index int, contentType string) {
"pivotCache": "/xl/pivotCache/pivotCacheDefinition" + strconv.Itoa(index) + ".xml",
}
contentTypes := map[string]string{
- "chart": "application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
- "comments": "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
- "drawings": "application/vnd.openxmlformats-officedocument.drawing+xml",
- "table": "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml",
- "pivotTable": "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml",
- "pivotCache": "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml",
+ "chart": ContentTypeDrawingML,
+ "chartsheet": ContentTypeSpreadSheetMLChartsheet,
+ "comments": ContentTypeSpreadSheetMLComments,
+ "drawings": ContentTypeDrawing,
+ "table": ContentTypeSpreadSheetMLTable,
+ "pivotTable": ContentTypeSpreadSheetMLPivotTable,
+ "pivotCache": ContentTypeSpreadSheetMLPivotCacheDefinition,
}
s, ok := setContentType[contentType]
if ok {
diff --git a/sheet.go b/sheet.go
index 08b0e96..11f56d9 100644
--- a/sheet.go
+++ b/sheet.go
@@ -50,7 +50,7 @@ func (f *File) NewSheet(name string) int {
// Update docProps/app.xml
f.setAppXML()
// Update [Content_Types].xml
- f.setContentTypes(sheetID)
+ f.setContentTypes("/xl/worksheets/sheet"+strconv.Itoa(sheetID)+".xml", ContentTypeSpreadSheetMLWorksheet)
// Create new sheet /xl/worksheets/sheet%d.xml
f.setSheet(sheetID, name)
// Update xl/_rels/workbook.xml.rels
@@ -151,11 +151,11 @@ func trimCell(column []xlsxC) []xlsxC {
// setContentTypes provides a function to read and update property of contents
// type of XLSX.
-func (f *File) setContentTypes(index int) {
+func (f *File) setContentTypes(partName, contentType string) {
content := f.contentTypesReader()
content.Overrides = append(content.Overrides, xlsxOverride{
- PartName: "/xl/worksheets/sheet" + strconv.Itoa(index) + ".xml",
- ContentType: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
+ PartName: partName,
+ ContentType: contentType,
})
}
@@ -336,8 +336,8 @@ func (f *File) GetSheetIndex(name string) int {
return 0
}
-// GetSheetMap provides a function to get worksheet name and index map of XLSX.
-// For example:
+// GetSheetMap provides a function to get worksheet and chartsheet name and
+// index map of XLSX. For example:
//
// f, err := excelize.OpenFile("Book1.xlsx")
// if err != nil {
@@ -358,8 +358,8 @@ func (f *File) GetSheetMap() map[int]string {
return sheetMap
}
-// getSheetMap provides a function to get worksheet name and XML file path map
-// of XLSX.
+// getSheetMap provides a function to get worksheet and chartsheet name and
+// XML file path map of XLSX.
func (f *File) getSheetMap() map[string]string {
content := f.workbookReader()
rels := f.relsReader("xl/_rels/workbook.xml.rels")
diff --git a/styles.go b/styles.go
index f2171bb..8d8b464 100644
--- a/styles.go
+++ b/styles.go
@@ -1018,7 +1018,7 @@ func (f *File) stylesReader() *xlsxStyleSheet {
func (f *File) styleSheetWriter() {
if f.Styles != nil {
output, _ := xml.Marshal(f.Styles)
- f.saveFileList("xl/styles.xml", replaceStyleRelationshipsNameSpaceBytes(output))
+ f.saveFileList("xl/styles.xml", replaceWorkSheetsRelationshipsNameSpaceBytes(output))
}
}
diff --git a/xmlChartSheet.go b/xmlChartSheet.go
index 3417eac..fae5a16 100644
--- a/xmlChartSheet.go
+++ b/xmlChartSheet.go
@@ -24,7 +24,7 @@ type xlsxChartsheet struct {
PageMargins *xlsxPageMargins `xml:"pageMargins"`
PageSetup []*xlsxPageSetUp `xml:"pageSetup"`
HeaderFooter *xlsxHeaderFooter `xml:"headerFooter"`
- Drawing []*xlsxDrawing `xml:"drawing"`
+ Drawing *xlsxDrawing `xml:"drawing"`
DrawingHF []*xlsxDrawingHF `xml:"drawingHF"`
Picture []*xlsxPicture `xml:"picture"`
WebPublishItems []*xlsxInnerXML `xml:"webPublishItems"`
diff --git a/xmlDrawing.go b/xmlDrawing.go
index 2bad16a..142121d 100644
--- a/xmlDrawing.go
+++ b/xmlDrawing.go
@@ -13,40 +13,52 @@ import "encoding/xml"
// Source relationship and namespace.
const (
- SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
- SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
- SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
- SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
- SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
- SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
- SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
- SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
- SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
- SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
- SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
- SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
- SourceRelationshipChart201506 = "http://schemas.microsoft.com/office/drawing/2015/06/chart"
- SourceRelationshipChart20070802 = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"
- SourceRelationshipChart2014 = "http://schemas.microsoft.com/office/drawing/2014/chart"
- SourceRelationshipCompatibility = "http://schemas.openxmlformats.org/markup-compatibility/2006"
- NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main"
- NameSpaceDrawingMLChart = "http://schemas.openxmlformats.org/drawingml/2006/chart"
- NameSpaceDrawingMLSpreadSheet = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
- NameSpaceSpreadSheet = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
- NameSpaceSpreadSheetX14 = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
- NameSpaceSpreadSheetX15 = "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
- NameSpaceSpreadSheetExcel2006Main = "http://schemas.microsoft.com/office/excel/2006/main"
- NameSpaceMacExcel2008Main = "http://schemas.microsoft.com/office/mac/excel/2008/main"
- NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
- NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
- 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"
- StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image"
- StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main"
- NameSpaceDublinCore = "http://purl.org/dc/elements/1.1/"
- NameSpaceDublinCoreTerms = "http://purl.org/dc/terms/"
- NameSpaceDublinCoreMetadataIntiative = "http://purl.org/dc/dcmitype/"
+ SourceRelationship = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+ SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
+ SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
+ SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
+ SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
+ SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
+ SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
+ SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
+ SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
+ SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
+ SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
+ SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
+ SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
+ SourceRelationshipChart201506 = "http://schemas.microsoft.com/office/drawing/2015/06/chart"
+ SourceRelationshipChart20070802 = "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"
+ SourceRelationshipChart2014 = "http://schemas.microsoft.com/office/drawing/2014/chart"
+ SourceRelationshipCompatibility = "http://schemas.openxmlformats.org/markup-compatibility/2006"
+ NameSpaceDrawingML = "http://schemas.openxmlformats.org/drawingml/2006/main"
+ NameSpaceDrawingMLChart = "http://schemas.openxmlformats.org/drawingml/2006/chart"
+ NameSpaceDrawingMLSpreadSheet = "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
+ NameSpaceSpreadSheet = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
+ NameSpaceSpreadSheetX14 = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
+ NameSpaceSpreadSheetX15 = "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"
+ NameSpaceSpreadSheetExcel2006Main = "http://schemas.microsoft.com/office/excel/2006/main"
+ NameSpaceMacExcel2008Main = "http://schemas.microsoft.com/office/mac/excel/2008/main"
+ NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
+ NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"
+ 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"
+ StrictSourceRelationshipImage = "http://purl.oclc.org/ooxml/officeDocument/relationships/image"
+ StrictNameSpaceSpreadSheet = "http://purl.oclc.org/ooxml/spreadsheetml/main"
+ NameSpaceDublinCore = "http://purl.org/dc/elements/1.1/"
+ NameSpaceDublinCoreTerms = "http://purl.org/dc/terms/"
+ NameSpaceDublinCoreMetadataIntiative = "http://purl.org/dc/dcmitype/"
+ ContentTypeDrawing = "application/vnd.openxmlformats-officedocument.drawing+xml"
+ ContentTypeDrawingML = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
+ ContentTypeMacro = "application/vnd.ms-excel.sheet.macroEnabled.main+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"
+ ContentTypeSpreadSheetMLTable = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
+ ContentTypeSpreadSheetMLWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"
+ ContentTypeVBA = "application/vnd.ms-office.vbaProject"
+ ContentTypeVML = "application/vnd.openxmlformats-officedocument.vmlDrawing"
// 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
@@ -240,6 +252,7 @@ type xdrClientData struct {
// with cells and its extents are in EMU units.
type xdrCellAnchor struct {
EditAs string `xml:"editAs,attr,omitempty"`
+ Pos *xlsxPoint2D `xml:"xdr:pos"`
From *xlsxFrom `xml:"xdr:from"`
To *xlsxTo `xml:"xdr:to"`
Ext *xlsxExt `xml:"xdr:ext"`
@@ -249,15 +262,23 @@ type xdrCellAnchor struct {
ClientData *xdrClientData `xml:"xdr:clientData"`
}
+// xlsxPoint2D describes the position of a drawing element within a spreadsheet.
+type xlsxPoint2D struct {
+ XMLName xml.Name `xml:"xdr:pos"`
+ X int `xml:"x,attr"`
+ Y int `xml:"y,attr"`
+}
+
// xlsxWsDr directly maps the root element for a part of this content type shall
// wsDr.
type xlsxWsDr struct {
- XMLName xml.Name `xml:"xdr:wsDr"`
- OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"`
- TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"`
- A string `xml:"xmlns:a,attr,omitempty"`
- Xdr string `xml:"xmlns:xdr,attr,omitempty"`
- R string `xml:"xmlns:r,attr,omitempty"`
+ XMLName xml.Name `xml:"xdr:wsDr"`
+ AbsoluteAnchor []*xdrCellAnchor `xml:"xdr:absoluteAnchor"`
+ OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"`
+ TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"`
+ A string `xml:"xmlns:a,attr,omitempty"`
+ Xdr string `xml:"xmlns:xdr,attr,omitempty"`
+ R string `xml:"xmlns:r,attr,omitempty"`
}
// xlsxGraphicFrame (Graphic Frame) directly maps the xdr:graphicFrame element.
diff --git a/xmlWorksheet.go b/xmlWorksheet.go
index aa33819..316ffd7 100644
--- a/xmlWorksheet.go
+++ b/xmlWorksheet.go
@@ -12,8 +12,7 @@ package excelize
import "encoding/xml"
// xlsxWorksheet directly maps the worksheet element in the namespace
-// http://schemas.openxmlformats.org/spreadsheetml/2006/main - currently I have
-// not checked it for completeness - it does as much as I need.
+// http://schemas.openxmlformats.org/spreadsheetml/2006/main.
type xlsxWorksheet struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main worksheet"`
SheetPr *xlsxSheetPr `xml:"sheetPr"`