Kaynağa Gözat

Combine functions:
workBookRelsWriter, drawingRelsWriter into relsWriter;
drawingRelsReader, workbookRelsReader, workSheetRelsReader into relsReader;
addDrawingRelationships, addSheetRelationships into addRels

xuri 6 yıl önce
ebeveyn
işleme
8922f65978
17 değiştirilmiş dosya ile 189 ekleme ve 273 silme
  1. 1 1
      README.md
  2. 1 1
      README_zh.md
  3. 3 1
      cell.go
  4. 5 2
      chart.go
  5. 5 3
      comment.go
  6. 26 7
      excelize.go
  7. BIN
      excelize.png
  8. 0 0
      excelize.svg
  9. 3 6
      file.go
  10. 29 107
      picture.go
  11. 3 1
      shape.go
  12. 22 63
      sheet.go
  13. 3 1
      table.go
  14. 2 0
      xmlDrawing.go
  15. 2 2
      xmlPivotCache.go
  16. 78 72
      xmlPivotTable.go
  17. 6 6
      xmlWorkbook.go

+ 1 - 1
README.md

@@ -1,4 +1,4 @@
-<p align="center"><img width="650" src="./excelize.png" alt="Excelize logo"></p>
+<p align="center"><img width="650" src="./excelize.svg" alt="Excelize logo"></p>
 
 <p align="center">
     <a href="https://travis-ci.org/360EntSecGroup-Skylar/excelize"><img src="https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master" alt="Build Status"></a>

+ 1 - 1
README_zh.md

@@ -1,4 +1,4 @@
-<p align="center"><img width="650" src="./excelize.png" alt="Excelize logo"></p>
+<p align="center"><img width="650" src="./excelize.svg" alt="Excelize logo"></p>
 
 <p align="center">
     <a href="https://travis-ci.org/360EntSecGroup-Skylar/excelize"><img src="https://travis-ci.org/360EntSecGroup-Skylar/excelize.svg?branch=master" alt="Build Status"></a>

+ 3 - 1
cell.go

@@ -378,7 +378,9 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string) error {
 		linkData = xlsxHyperlink{
 			Ref: axis,
 		}
-		rID := f.addSheetRelationships(sheet, SourceRelationshipHyperLink, link, linkType)
+		sheetPath, _ := f.sheetMap[trimSheetName(sheet)]
+		sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
+		rID := f.addRels(sheetRels, SourceRelationshipHyperLink, link, linkType)
 		linkData.RID = "rId" + strconv.Itoa(rID)
 	case "Location":
 		linkData = xlsxHyperlink{

+ 5 - 2
chart.go

@@ -727,7 +727,8 @@ func (f *File) AddChart(sheet, cell, format string) error {
 	chartID := f.countCharts() + 1
 	drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
 	drawingID, drawingXML = f.prepareDrawing(xlsx, drawingID, sheet, drawingXML)
-	drawingRID := f.addDrawingRelationships(drawingID, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
+	drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
+	drawingRID := f.addRels(drawingRels, SourceRelationshipChart, "../charts/chart"+strconv.Itoa(chartID)+".xml", "")
 	err = f.addDrawingChart(sheet, drawingXML, cell, formatSet.Dimension.Width, formatSet.Dimension.Height, drawingRID, &formatSet.Format)
 	if err != nil {
 		return err
@@ -761,7 +762,9 @@ func (f *File) prepareDrawing(xlsx *xlsxWorksheet, drawingID int, sheet, drawing
 		drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
 	} else {
 		// Add first picture for given sheet.
-		rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
+		sheetPath, _ := f.sheetMap[trimSheetName(sheet)]
+		sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
+		rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
 		f.addSheetDrawing(sheet, rID)
 	}
 	return drawingID, drawingXML

+ 5 - 3
comment.go

@@ -60,7 +60,7 @@ func (f *File) GetComments() (comments map[string][]Comment) {
 // given worksheet index.
 func (f *File) getSheetComments(sheetID int) string {
 	var rels = "xl/worksheets/_rels/sheet" + strconv.Itoa(sheetID) + ".xml.rels"
-	if sheetRels := f.workSheetRelsReader(rels); sheetRels != nil {
+	if sheetRels := f.relsReader(rels); sheetRels != nil {
 		for _, v := range sheetRels.Relationships {
 			if v.Type == SourceRelationshipComments {
 				return v.Target
@@ -98,8 +98,10 @@ func (f *File) AddComment(sheet, cell, format string) error {
 		drawingVML = strings.Replace(sheetRelationshipsDrawingVML, "..", "xl", -1)
 	} else {
 		// Add first comment for given sheet.
-		rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "")
-		f.addSheetRelationships(sheet, SourceRelationshipComments, sheetRelationshipsComments, "")
+		sheetPath, _ := f.sheetMap[trimSheetName(sheet)]
+		sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
+		rID := f.addRels(sheetRels, SourceRelationshipDrawingVML, sheetRelationshipsDrawingVML, "")
+		f.addRels(sheetRels, SourceRelationshipComments, sheetRelationshipsComments, "")
 		f.addSheetLegacyDrawing(sheet, rID)
 	}
 	commentsXML := "xl/comments" + strconv.Itoa(commentID) + ".xml"

+ 26 - 7
excelize.go

@@ -31,7 +31,6 @@ type File struct {
 	CalcChain        *xlsxCalcChain
 	Comments         map[string]*xlsxComments
 	ContentTypes     *xlsxTypes
-	DrawingRels      map[string]*xlsxWorkbookRels
 	Drawings         map[string]*xlsxWsDr
 	Path             string
 	SharedStrings    *xlsxSST
@@ -42,8 +41,7 @@ type File struct {
 	DecodeVMLDrawing map[string]*decodeVmlDrawing
 	VMLDrawing       map[string]*vmlDrawing
 	WorkBook         *xlsxWorkbook
-	WorkBookRels     *xlsxWorkbookRels
-	WorkSheetRels    map[string]*xlsxWorkbookRels
+	Relationships    map[string]*xlsxRelationships
 	XLSX             map[string][]byte
 }
 
@@ -93,13 +91,12 @@ func OpenReader(r io.Reader) (*File, error) {
 	f := &File{
 		checked:          make(map[string]bool),
 		Comments:         make(map[string]*xlsxComments),
-		DrawingRels:      make(map[string]*xlsxWorkbookRels),
 		Drawings:         make(map[string]*xlsxWsDr),
 		Sheet:            make(map[string]*xlsxWorksheet),
 		SheetCount:       sheetCount,
 		DecodeVMLDrawing: make(map[string]*decodeVmlDrawing),
 		VMLDrawing:       make(map[string]*vmlDrawing),
-		WorkSheetRels:    make(map[string]*xlsxWorkbookRels),
+		Relationships:    make(map[string]*xlsxRelationships),
 		XLSX:             file,
 	}
 	f.CalcChain = f.calcChainReader()
@@ -176,6 +173,28 @@ func checkSheet(xlsx *xlsxWorksheet) {
 	xlsx.SheetData = sheetData
 }
 
+// addRels provides a function to add relationships by given XML path,
+// relationship type, target and target mode.
+func (f *File) addRels(relPath, relType, target, targetMode string) int {
+	rels := f.relsReader(relPath)
+	rID := 0
+	if rels == nil {
+		rels = &xlsxRelationships{}
+	}
+	rID = len(rels.Relationships) + 1
+	var ID bytes.Buffer
+	ID.WriteString("rId")
+	ID.WriteString(strconv.Itoa(rID))
+	rels.Relationships = append(rels.Relationships, xlsxRelationship{
+		ID:         ID.String(),
+		Type:       relType,
+		Target:     target,
+		TargetMode: targetMode,
+	})
+	f.Relationships[relPath] = rels
+	return rID
+}
+
 // replaceWorkSheetsRelationshipsNameSpaceBytes provides a function to replace
 // xl/worksheets/sheet%d.xml XML tags to self-closing for compatible Microsoft
 // Office Excel 2007.
@@ -265,7 +284,7 @@ func (f *File) AddVBAProject(bin string) error {
 		return errors.New("unsupported VBA project extension")
 	}
 	f.setContentTypePartVBAProjectExtensions()
-	wb := f.workbookRelsReader()
+	wb := f.relsReader("xl/_rels/workbook.xml.rels")
 	var rID int
 	var ok bool
 	for _, rel := range wb.Relationships {
@@ -280,7 +299,7 @@ func (f *File) AddVBAProject(bin string) error {
 	}
 	rID++
 	if !ok {
-		wb.Relationships = append(wb.Relationships, xlsxWorkbookRelation{
+		wb.Relationships = append(wb.Relationships, xlsxRelationship{
 			ID:     "rId" + strconv.Itoa(rID),
 			Target: "vbaProject.bin",
 			Type:   SourceRelationshipVBAProject,

BIN
excelize.png


Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
excelize.svg


+ 3 - 6
file.go

@@ -42,14 +42,13 @@ func NewFile() *File {
 	f.CalcChain = f.calcChainReader()
 	f.Comments = make(map[string]*xlsxComments)
 	f.ContentTypes = f.contentTypesReader()
-	f.DrawingRels = make(map[string]*xlsxWorkbookRels)
 	f.Drawings = make(map[string]*xlsxWsDr)
 	f.Styles = f.stylesReader()
 	f.DecodeVMLDrawing = make(map[string]*decodeVmlDrawing)
 	f.VMLDrawing = make(map[string]*vmlDrawing)
 	f.WorkBook = f.workbookReader()
-	f.WorkBookRels = f.workbookRelsReader()
-	f.WorkSheetRels = make(map[string]*xlsxWorkbookRels)
+	f.Relationships = make(map[string]*xlsxRelationships)
+	f.Relationships["xl/_rels/workbook.xml.rels"] = f.relsReader("xl/_rels/workbook.xml.rels")
 	f.Sheet["xl/worksheets/sheet1.xml"], _ = f.workSheetReader("Sheet1")
 	f.sheetMap["Sheet1"] = "xl/worksheets/sheet1.xml"
 	f.Theme = f.themeReader()
@@ -97,13 +96,11 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
 	f.calcChainWriter()
 	f.commentsWriter()
 	f.contentTypesWriter()
-	f.drawingRelsWriter()
 	f.drawingsWriter()
 	f.vmlDrawingWriter()
 	f.workBookWriter()
-	f.workBookRelsWriter()
 	f.workSheetWriter()
-	f.workSheetRelsWriter()
+	f.relsWriter()
 	f.styleSheetWriter()
 
 	for path, content := range f.XLSX {

+ 29 - 107
picture.go

@@ -155,14 +155,15 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
 	drawingID := f.countDrawings() + 1
 	drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
 	drawingID, drawingXML = f.prepareDrawing(xlsx, drawingID, sheet, drawingXML)
+	drawingRels := "xl/drawings/_rels/drawing" + strconv.Itoa(drawingID) + ".xml.rels"
 	mediaStr := ".." + strings.TrimPrefix(f.addMedia(file, ext), "xl")
-	drawingRID := f.addDrawingRelationships(drawingID, SourceRelationshipImage, mediaStr, hyperlinkType)
+	drawingRID := f.addRels(drawingRels, SourceRelationshipImage, mediaStr, hyperlinkType)
 	// Add picture with hyperlink.
 	if formatSet.Hyperlink != "" && formatSet.HyperlinkType != "" {
 		if formatSet.HyperlinkType == "External" {
 			hyperlinkType = formatSet.HyperlinkType
 		}
-		drawingHyperlinkRID = f.addDrawingRelationships(drawingID, SourceRelationshipHyperLink, formatSet.Hyperlink, hyperlinkType)
+		drawingHyperlinkRID = f.addRels(drawingRels, SourceRelationshipHyperLink, formatSet.Hyperlink, hyperlinkType)
 	}
 	err = f.addDrawingPicture(sheet, drawingXML, cell, name, img.Width, img.Height, drawingRID, drawingHyperlinkRID, formatSet)
 	if err != nil {
@@ -172,37 +173,6 @@ func (f *File) AddPictureFromBytes(sheet, cell, format, name, extension string,
 	return err
 }
 
-// addSheetRelationships provides a function to add
-// xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name, relationship
-// type and target.
-func (f *File) addSheetRelationships(sheet, relType, target, targetMode string) int {
-	name, ok := f.sheetMap[trimSheetName(sheet)]
-	if !ok {
-		name = strings.ToLower(sheet) + ".xml"
-	}
-	var rels = "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels"
-	sheetRels := f.workSheetRelsReader(rels)
-	if sheetRels == nil {
-		sheetRels = &xlsxWorkbookRels{}
-	}
-	var rID = 1
-	var ID bytes.Buffer
-	ID.WriteString("rId")
-	ID.WriteString(strconv.Itoa(rID))
-	ID.Reset()
-	rID = len(sheetRels.Relationships) + 1
-	ID.WriteString("rId")
-	ID.WriteString(strconv.Itoa(rID))
-	sheetRels.Relationships = append(sheetRels.Relationships, xlsxWorkbookRelation{
-		ID:         ID.String(),
-		Type:       relType,
-		Target:     target,
-		TargetMode: targetMode,
-	})
-	f.WorkSheetRels[rels] = sheetRels
-	return rID
-}
-
 // deleteSheetRelationships provides a function to delete relationships in
 // xl/worksheets/_rels/sheet%d.xml.rels by given worksheet name and
 // relationship index.
@@ -212,16 +182,16 @@ func (f *File) deleteSheetRelationships(sheet, rID string) {
 		name = strings.ToLower(sheet) + ".xml"
 	}
 	var rels = "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels"
-	sheetRels := f.workSheetRelsReader(rels)
+	sheetRels := f.relsReader(rels)
 	if sheetRels == nil {
-		sheetRels = &xlsxWorkbookRels{}
+		sheetRels = &xlsxRelationships{}
 	}
 	for k, v := range sheetRels.Relationships {
 		if v.ID == rID {
 			sheetRels.Relationships = append(sheetRels.Relationships[:k], sheetRels.Relationships[k+1:]...)
 		}
 	}
-	f.WorkSheetRels[rels] = sheetRels
+	f.Relationships[rels] = sheetRels
 }
 
 // addSheetLegacyDrawing provides a function to add legacy drawing element to
@@ -325,33 +295,6 @@ func (f *File) addDrawingPicture(sheet, drawingXML, cell, file string, width, he
 	return err
 }
 
-// addDrawingRelationships provides a function to add image part relationships
-// in the file xl/drawings/_rels/drawing%d.xml.rels by given drawing index,
-// relationship type and target.
-func (f *File) addDrawingRelationships(index int, relType, target, targetMode string) int {
-	var rels = "xl/drawings/_rels/drawing" + strconv.Itoa(index) + ".xml.rels"
-	var rID = 1
-	var ID bytes.Buffer
-	ID.WriteString("rId")
-	ID.WriteString(strconv.Itoa(rID))
-	drawingRels := f.drawingRelsReader(rels)
-	if drawingRels == nil {
-		drawingRels = &xlsxWorkbookRels{}
-	}
-	ID.Reset()
-	rID = len(drawingRels.Relationships) + 1
-	ID.WriteString("rId")
-	ID.WriteString(strconv.Itoa(rID))
-	drawingRels.Relationships = append(drawingRels.Relationships, xlsxWorkbookRelation{
-		ID:         ID.String(),
-		Type:       relType,
-		Target:     target,
-		TargetMode: targetMode,
-	})
-	f.DrawingRels[rels] = drawingRels
-	return rID
-}
-
 // countMedia provides a function to get media files count storage in the
 // folder xl/media/image.
 func (f *File) countMedia() int {
@@ -429,16 +372,20 @@ func (f *File) addContentTypePart(index int, contentType string) {
 		"drawings": f.setContentTypePartImageExtensions,
 	}
 	partNames := map[string]string{
-		"chart":    "/xl/charts/chart" + 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",
+		"chart":      "/xl/charts/chart" + 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",
+		"pivotTable": "/xl/pivotTables/pivotTable" + strconv.Itoa(index) + ".xml",
+		"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",
+		"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",
 	}
 	s, ok := setContentType[contentType]
 	if ok {
@@ -465,9 +412,9 @@ func (f *File) getSheetRelationshipsTargetByID(sheet, rID string) string {
 		name = strings.ToLower(sheet) + ".xml"
 	}
 	var rels = "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels"
-	sheetRels := f.workSheetRelsReader(rels)
+	sheetRels := f.relsReader(rels)
 	if sheetRels == nil {
-		sheetRels = &xlsxWorkbookRels{}
+		sheetRels = &xlsxRelationships{}
 	}
 	for _, v := range sheetRels.Relationships {
 		if v.ID == rID {
@@ -529,12 +476,12 @@ func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string)
 	for _, anchor := range wsDr.TwoCellAnchor {
 		if anchor.From != nil && anchor.Pic != nil {
 			if anchor.From.Col == col && anchor.From.Row == row {
-				xlsxWorkbookRelation := f.getDrawingRelationships(drawingRelationships,
+				xlsxRelationship := f.getDrawingRelationships(drawingRelationships,
 					anchor.Pic.BlipFill.Blip.Embed)
-				_, ok := supportImageTypes[filepath.Ext(xlsxWorkbookRelation.Target)]
+				_, ok := supportImageTypes[filepath.Ext(xlsxRelationship.Target)]
 				if ok {
-					return filepath.Base(xlsxWorkbookRelation.Target),
-						[]byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target,
+					return filepath.Base(xlsxRelationship.Target),
+						[]byte(f.XLSX[strings.Replace(xlsxRelationship.Target,
 							"..", "xl", -1)]), nil
 				}
 			}
@@ -548,10 +495,10 @@ func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string)
 		_ = xml.Unmarshal([]byte("<decodeTwoCellAnchor>"+anchor.Content+"</decodeTwoCellAnchor>"), &decodeTwoCellAnchor)
 		if decodeTwoCellAnchor.From != nil && decodeTwoCellAnchor.Pic != nil {
 			if decodeTwoCellAnchor.From.Col == col && decodeTwoCellAnchor.From.Row == row {
-				xlsxWorkbookRelation := f.getDrawingRelationships(drawingRelationships, decodeTwoCellAnchor.Pic.BlipFill.Blip.Embed)
-				_, ok := supportImageTypes[filepath.Ext(xlsxWorkbookRelation.Target)]
+				xlsxRelationship := f.getDrawingRelationships(drawingRelationships, decodeTwoCellAnchor.Pic.BlipFill.Blip.Embed)
+				_, ok := supportImageTypes[filepath.Ext(xlsxRelationship.Target)]
 				if ok {
-					return filepath.Base(xlsxWorkbookRelation.Target), []byte(f.XLSX[strings.Replace(xlsxWorkbookRelation.Target, "..", "xl", -1)]), nil
+					return filepath.Base(xlsxRelationship.Target), []byte(f.XLSX[strings.Replace(xlsxRelationship.Target, "..", "xl", -1)]), nil
 				}
 			}
 		}
@@ -562,8 +509,8 @@ func (f *File) getPicture(row, col int, drawingXML, drawingRelationships string)
 // getDrawingRelationships provides a function to get drawing relationships
 // from xl/drawings/_rels/drawing%s.xml.rels by given file name and
 // relationship ID.
-func (f *File) getDrawingRelationships(rels, rID string) *xlsxWorkbookRelation {
-	if drawingRels := f.drawingRelsReader(rels); drawingRels != nil {
+func (f *File) getDrawingRelationships(rels, rID string) *xlsxRelationship {
+	if drawingRels := f.relsReader(rels); drawingRels != nil {
 		for _, v := range drawingRels.Relationships {
 			if v.ID == rID {
 				return &v
@@ -573,31 +520,6 @@ func (f *File) getDrawingRelationships(rels, rID string) *xlsxWorkbookRelation {
 	return nil
 }
 
-// drawingRelsReader provides a function to get the pointer to the structure
-// after deserialization of xl/drawings/_rels/drawing%d.xml.rels.
-func (f *File) drawingRelsReader(rel string) *xlsxWorkbookRels {
-	if f.DrawingRels[rel] == nil {
-		_, ok := f.XLSX[rel]
-		if ok {
-			d := xlsxWorkbookRels{}
-			_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(rel)), &d)
-			f.DrawingRels[rel] = &d
-		}
-	}
-	return f.DrawingRels[rel]
-}
-
-// drawingRelsWriter provides a function to save
-// xl/drawings/_rels/drawing%d.xml.rels after serialize structure.
-func (f *File) drawingRelsWriter() {
-	for path, d := range f.DrawingRels {
-		if d != nil {
-			v, _ := xml.Marshal(d)
-			f.saveFileList(path, v)
-		}
-	}
-}
-
 // drawingsWriter provides a function to save xl/drawings/drawing%d.xml after
 // serialize structure.
 func (f *File) drawingsWriter() {

+ 3 - 1
shape.go

@@ -275,7 +275,9 @@ func (f *File) AddShape(sheet, cell, format string) error {
 		drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
 	} else {
 		// Add first shape for given sheet.
-		rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
+		name, _ := f.sheetMap[trimSheetName(sheet)]
+		sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(name, "xl/worksheets/") + ".rels"
+		rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
 		f.addSheetDrawing(sheet, rID)
 	}
 	err = f.addDrawingShape(sheet, drawingXML, cell, formatSet)

+ 22 - 63
sheet.go

@@ -52,7 +52,7 @@ func (f *File) NewSheet(name string) int {
 	// Create new sheet /xl/worksheets/sheet%d.xml
 	f.setSheet(sheetID, name)
 	// Update xl/_rels/workbook.xml.rels
-	rID := f.addXlsxWorkbookRels(sheetID)
+	rID := f.addRels("xl/_rels/workbook.xml.rels", SourceRelationshipWorkSheet, fmt.Sprintf("worksheets/sheet%d.xml", sheetID), "")
 	// Update xl/workbook.xml
 	f.setWorkbook(name, sheetID, rID)
 	return sheetID
@@ -163,50 +163,18 @@ func (f *File) setWorkbook(name string, sheetID, rid int) {
 	})
 }
 
-// workbookRelsReader provides a function to read and unmarshal workbook
-// relationships of XLSX file.
-func (f *File) workbookRelsReader() *xlsxWorkbookRels {
-	if f.WorkBookRels == nil {
-		var content xlsxWorkbookRels
-		_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML("xl/_rels/workbook.xml.rels")), &content)
-		f.WorkBookRels = &content
-	}
-	return f.WorkBookRels
-}
-
-// workBookRelsWriter provides a function to save xl/_rels/workbook.xml.rels after
+// relsWriter provides a function to save relationships after
 // serialize structure.
-func (f *File) workBookRelsWriter() {
-	if f.WorkBookRels != nil {
-		output, _ := xml.Marshal(f.WorkBookRels)
-		f.saveFileList("xl/_rels/workbook.xml.rels", output)
-	}
-}
-
-// addXlsxWorkbookRels update workbook relationships property of XLSX.
-func (f *File) addXlsxWorkbookRels(sheet int) int {
-	content := f.workbookRelsReader()
-	rID := 0
-	for _, v := range content.Relationships {
-		t, _ := strconv.Atoi(strings.TrimPrefix(v.ID, "rId"))
-		if t > rID {
-			rID = t
+func (f *File) relsWriter() {
+	for path, rel := range f.Relationships {
+		if rel != nil {
+			output, _ := xml.Marshal(rel)
+			if strings.HasPrefix(path, "xl/worksheets/sheet/rels/sheet") {
+				output = replaceWorkSheetsRelationshipsNameSpaceBytes(output)
+			}
+			f.saveFileList(path, replaceRelationshipsBytes(output))
 		}
 	}
-	rID++
-	ID := bytes.Buffer{}
-	ID.WriteString("rId")
-	ID.WriteString(strconv.Itoa(rID))
-	target := bytes.Buffer{}
-	target.WriteString("worksheets/sheet")
-	target.WriteString(strconv.Itoa(sheet))
-	target.WriteString(".xml")
-	content.Relationships = append(content.Relationships, xlsxWorkbookRelation{
-		ID:     ID.String(),
-		Target: target.String(),
-		Type:   SourceRelationshipWorkSheet,
-	})
-	return rID
 }
 
 // setAppXML update docProps/app.xml file of XML.
@@ -365,7 +333,7 @@ func (f *File) GetSheetMap() map[int]string {
 // of XLSX.
 func (f *File) getSheetMap() map[string]string {
 	content := f.workbookReader()
-	rels := f.workbookRelsReader()
+	rels := f.relsReader("xl/_rels/workbook.xml.rels")
 	maps := map[string]string{}
 	for _, v := range content.Sheets.Sheet {
 		for _, rel := range rels.Relationships {
@@ -396,7 +364,9 @@ func (f *File) SetSheetBackground(sheet, picture string) error {
 	}
 	file, _ := ioutil.ReadFile(picture)
 	name := f.addMedia(file, ext)
-	rID := f.addSheetRelationships(sheet, SourceRelationshipImage, strings.Replace(name, "xl", "..", 1), "")
+	sheetPath, _ := f.sheetMap[trimSheetName(sheet)]
+	sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
+	rID := f.addRels(sheetRels, SourceRelationshipImage, strings.Replace(name, "xl", "..", 1), "")
 	f.addSheetPicture(sheet, rID)
 	f.setContentTypePartImageExtensions()
 	return err
@@ -413,7 +383,7 @@ func (f *File) DeleteSheet(name string) {
 	}
 	sheetName := trimSheetName(name)
 	wb := f.workbookReader()
-	wbRels := f.workbookRelsReader()
+	wbRels := f.relsReader("xl/_rels/workbook.xml.rels")
 	for idx, sheet := range wb.Sheets.Sheet {
 		if sheet.Name == sheetName {
 			wb.Sheets.Sheet = append(wb.Sheets.Sheet[:idx], wb.Sheets.Sheet[idx+1:]...)
@@ -443,7 +413,7 @@ func (f *File) DeleteSheet(name string) {
 // relationships by given relationships ID in the file
 // xl/_rels/workbook.xml.rels.
 func (f *File) deleteSheetFromWorkbookRels(rID string) string {
-	content := f.workbookRelsReader()
+	content := f.relsReader("xl/_rels/workbook.xml.rels")
 	for k, v := range content.Relationships {
 		if v.ID == rID {
 			content.Relationships = append(content.Relationships[:k], content.Relationships[k+1:]...)
@@ -1387,29 +1357,18 @@ func (f *File) UngroupSheets() error {
 	return nil
 }
 
-// workSheetRelsReader provides a function to get the pointer to the structure
+// relsReader provides a function to get the pointer to the structure
 // after deserialization of xl/worksheets/_rels/sheet%d.xml.rels.
-func (f *File) workSheetRelsReader(path string) *xlsxWorkbookRels {
-	if f.WorkSheetRels[path] == nil {
+func (f *File) relsReader(path string) *xlsxRelationships {
+	if f.Relationships[path] == nil {
 		_, ok := f.XLSX[path]
 		if ok {
-			c := xlsxWorkbookRels{}
+			c := xlsxRelationships{}
 			_ = xml.Unmarshal(namespaceStrictToTransitional(f.readXML(path)), &c)
-			f.WorkSheetRels[path] = &c
-		}
-	}
-	return f.WorkSheetRels[path]
-}
-
-// workSheetRelsWriter provides a function to save
-// xl/worksheets/_rels/sheet%d.xml.rels after serialize structure.
-func (f *File) workSheetRelsWriter() {
-	for p, r := range f.WorkSheetRels {
-		if r != nil {
-			v, _ := xml.Marshal(r)
-			f.saveFileList(p, v)
+			f.Relationships[path] = &c
 		}
 	}
+	return f.Relationships[path]
 }
 
 // fillSheetData ensures there are enough rows, and columns in the chosen

+ 3 - 1
table.go

@@ -77,7 +77,9 @@ func (f *File) AddTable(sheet, hcell, vcell, format string) error {
 	sheetRelationshipsTableXML := "../tables/table" + strconv.Itoa(tableID) + ".xml"
 	tableXML := strings.Replace(sheetRelationshipsTableXML, "..", "xl", -1)
 	// Add first table for given sheet.
-	rID := f.addSheetRelationships(sheet, SourceRelationshipTable, sheetRelationshipsTableXML, "")
+	sheetPath, _ := f.sheetMap[trimSheetName(sheet)]
+	sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
+	rID := f.addRels(sheetRels, SourceRelationshipTable, sheetRelationshipsTableXML, "")
 	f.addSheetTable(sheet, rID)
 	err = f.addTable(sheet, tableXML, hcol, hrow, vcol, vrow, tableID, formatSet)
 	if err != nil {

+ 2 - 0
xmlDrawing.go

@@ -22,6 +22,8 @@ const (
 	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"

+ 2 - 2
xmlPivotCache.go

@@ -2,11 +2,11 @@ package excelize
 
 import "encoding/xml"
 
-// pivotCacheDefinition represents the pivotCacheDefinition part. This part
+// xlsxPivotCacheDefinition represents the pivotCacheDefinition part. This part
 // defines each field in the source data, including the name, the string
 // resources of the instance data (for shared items), and information about
 // the type of data that appears in the field.
-type xmlPivotCacheDefinition struct {
+type xlsxPivotCacheDefinition struct {
 	XMLName               xml.Name               `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main pivotCacheDefinition"`
 	RID                   string                 `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr,omitempty"`
 	Invalid               bool                   `xml:"invalid,attr,omitempty"`

+ 78 - 72
xmlPivotTable.go

@@ -15,78 +15,84 @@ import "encoding/xml"
 // non-null PivotTables. There exists one pivotTableDefinition for each
 // PivotTableDefinition part
 type xlsxPivotTableDefinition struct {
-	XMLName                xml.Name                 `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main pivotTableDefinition"`
-	Name                   string                   `xml:"name,attr"`
-	CacheID                int                      `xml:"cacheId,attr"`
-	DataOnRows             bool                     `xml:"dataOnRows,attr"`
-	DataPosition           int                      `xml:"dataPosition,attr"`
-	DataCaption            string                   `xml:"dataCaption,attr"`
-	GrandTotalCaption      string                   `xml:"grandTotalCaption,attr"`
-	ErrorCaption           string                   `xml:"errorCaption,attr"`
-	ShowError              bool                     `xml:"showError,attr"`
-	MissingCaption         string                   `xml:"missingCaption,attr"`
-	ShowMissing            bool                     `xml:"showMissing,attr"`
-	PageStyle              string                   `xml:"pageStyle,attr"`
-	PivotTableStyle        string                   `xml:"pivotTableStyle,attr"`
-	VacatedStyle           string                   `xml:"vacatedStyle,attr"`
-	Tag                    string                   `xml:"tag,attr"`
-	UpdatedVersion         int                      `xml:"updatedVersion,attr"`
-	MinRefreshableVersion  int                      `xml:"minRefreshableVersion,attr"`
-	AsteriskTotals         bool                     `xml:"asteriskTotals,attr"`
-	ShowItems              bool                     `xml:"showItems,attr"`
-	EditData               bool                     `xml:"editData,attr"`
-	DisableFieldList       bool                     `xml:"disableFieldList,attr"`
-	ShowCalcMbrs           bool                     `xml:"showCalcMbrs,attr"`
-	VisualTotals           bool                     `xml:"visualTotals,attr"`
-	ShowMultipleLabel      bool                     `xml:"showMultipleLabel,attr"`
-	ShowDataDropDown       bool                     `xml:"showDataDropDown,attr"`
-	ShowDrill              bool                     `xml:"showDrill,attr"`
-	PrintDrill             bool                     `xml:"printDrill,attr"`
-	ShowMemberPropertyTips bool                     `xml:"showMemberPropertyTips,attr"`
-	ShowDataTips           bool                     `xml:"showDataTips,attr"`
-	EnableWizard           bool                     `xml:"enableWizard,attr"`
-	EnableDrill            bool                     `xml:"enableDrill,attr"`
-	EnableFieldProperties  bool                     `xml:"enableFieldProperties,attr"`
-	PreserveFormatting     bool                     `xml:"preserveFormatting,attr"`
-	UseAutoFormatting      bool                     `xml:"useAutoFormatting,attr"`
-	PageWrap               int                      `xml:"pageWrap,attr"`
-	PageOverThenDown       bool                     `xml:"pageOverThenDown,attr"`
-	SubtotalHiddenItems    bool                     `xml:"subtotalHiddenItems,attr"`
-	RowGrandTotals         bool                     `xml:"rowGrandTotals,attr"`
-	ColGrandTotals         bool                     `xml:"colGrandTotals,attr"`
-	FieldPrintTitles       bool                     `xml:"fieldPrintTitles,attr"`
-	ItemPrintTitles        bool                     `xml:"itemPrintTitles,attr"`
-	MergeItem              bool                     `xml:"mergeItem,attr"`
-	ShowDropZones          bool                     `xml:"showDropZones,attr"`
-	CreatedVersion         int                      `xml:"createdVersion,attr"`
-	Indent                 int                      `xml:"indent,attr"`
-	ShowEmptyRow           bool                     `xml:"showEmptyRow,attr"`
-	ShowEmptyCol           bool                     `xml:"showEmptyCol,attr"`
-	ShowHeaders            bool                     `xml:"showHeaders,attr"`
-	Compact                bool                     `xml:"compact,attr"`
-	Outline                bool                     `xml:"outline,attr"`
-	OutlineData            bool                     `xml:"outlineData,attr"`
-	CompactData            bool                     `xml:"compactData,attr"`
-	Published              bool                     `xml:"published,attr"`
-	GridDropZones          bool                     `xml:"gridDropZones,attr"`
-	Immersive              bool                     `xml:"immersive,attr"`
-	MultipleFieldFilters   bool                     `xml:"multipleFieldFilters,attr"`
-	ChartFormat            int                      `xml:"chartFormat,attr"`
-	RowHeaderCaption       string                   `xml:"rowHeaderCaption,attr"`
-	ColHeaderCaption       string                   `xml:"colHeaderCaption,attr"`
-	FieldListSortAscending bool                     `xml:"fieldListSortAscending,attr"`
-	MdxSubqueries          bool                     `xml:"mdxSubqueries,attr"`
-	CustomListSort         bool                     `xml:"customListSort,attr"`
-	Location               *xlsxLocation            `xml:"location"`
-	PivotFields            *xlsxPivotFields         `xml:"pivotFields"`
-	RowFields              *xlsxRowFields           `xml:"rowFields"`
-	RowItems               *xlsxRowItems            `xml:"rowItems"`
-	ColFields              *xlsxColFields           `xml:"colFields"`
-	ColItems               *xlsxColItems            `xml:"colItems"`
-	PageFields             *xlsxPageFields          `xml:"pageFields"`
-	DataFields             *xlsxDataFields          `xml:"dataFields"`
-	ConditionalFormats     *xlsxConditionalFormats  `xml:"conditionalFormats"`
-	PivotTableStyleInfo    *xlsxPivotTableStyleInfo `xml:"pivotTableStyleInfo"`
+	XMLName                 xml.Name                 `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main pivotTableDefinition"`
+	Name                    string                   `xml:"name,attr"`
+	CacheID                 int                      `xml:"cacheId,attr"`
+	ApplyNumberFormats      bool                     `xml:"applyNumberFormats,attr,omitempty"`
+	ApplyBorderFormats      bool                     `xml:"applyBorderFormats,attr,omitempty"`
+	ApplyFontFormats        bool                     `xml:"applyFontFormats,attr,omitempty"`
+	ApplyPatternFormats     bool                     `xml:"applyPatternFormats,attr,omitempty"`
+	ApplyAlignmentFormats   bool                     `xml:"applyAlignmentFormats,attr,omitempty"`
+	ApplyWidthHeightFormats bool                     `xml:"applyWidthHeightFormats,attr,omitempty"`
+	DataOnRows              bool                     `xml:"dataOnRows,attr,omitempty"`
+	DataPosition            int                      `xml:"dataPosition,attr,omitempty"`
+	DataCaption             string                   `xml:"dataCaption,attr"`
+	GrandTotalCaption       string                   `xml:"grandTotalCaption,attr,omitempty"`
+	ErrorCaption            string                   `xml:"errorCaption,attr,omitempty"`
+	ShowError               bool                     `xml:"showError,attr,omitempty"`
+	MissingCaption          string                   `xml:"missingCaption,attr,omitempty"`
+	ShowMissing             bool                     `xml:"showMissing,attr,omitempty"`
+	PageStyle               string                   `xml:"pageStyle,attr,omitempty"`
+	PivotTableStyle         string                   `xml:"pivotTableStyle,attr,omitempty"`
+	VacatedStyle            string                   `xml:"vacatedStyle,attr,omitempty"`
+	Tag                     string                   `xml:"tag,attr,omitempty"`
+	UpdatedVersion          int                      `xml:"updatedVersion,attr"`
+	MinRefreshableVersion   int                      `xml:"minRefreshableVersion,attr"`
+	AsteriskTotals          bool                     `xml:"asteriskTotals,attr,omitempty"`
+	ShowItems               bool                     `xml:"showItems,attr,omitempty"`
+	EditData                bool                     `xml:"editData,attr,omitempty"`
+	DisableFieldList        bool                     `xml:"disableFieldList,attr,omitempty"`
+	ShowCalcMbrs            bool                     `xml:"showCalcMbrs,attr,omitempty"`
+	VisualTotals            bool                     `xml:"visualTotals,attr,omitempty"`
+	ShowMultipleLabel       bool                     `xml:"showMultipleLabel,attr,omitempty"`
+	ShowDataDropDown        bool                     `xml:"showDataDropDown,attr,omitempty"`
+	ShowDrill               bool                     `xml:"showDrill,attr,omitempty"`
+	PrintDrill              bool                     `xml:"printDrill,attr,omitempty"`
+	ShowMemberPropertyTips  bool                     `xml:"showMemberPropertyTips,attr,omitempty"`
+	ShowDataTips            bool                     `xml:"showDataTips,attr,omitempty"`
+	EnableWizard            bool                     `xml:"enableWizard,attr,omitempty"`
+	EnableDrill             bool                     `xml:"enableDrill,attr,omitempty"`
+	EnableFieldProperties   bool                     `xml:"enableFieldProperties,attr,omitempty"`
+	PreserveFormatting      bool                     `xml:"preserveFormatting,attr,omitempty"`
+	UseAutoFormatting       bool                     `xml:"useAutoFormatting,attr"`
+	PageWrap                int                      `xml:"pageWrap,attr,omitempty"`
+	PageOverThenDown        bool                     `xml:"pageOverThenDown,attr,omitempty"`
+	SubtotalHiddenItems     bool                     `xml:"subtotalHiddenItems,attr,omitempty"`
+	RowGrandTotals          bool                     `xml:"rowGrandTotals,attr,omitempty"`
+	ColGrandTotals          bool                     `xml:"colGrandTotals,attr,omitempty"`
+	FieldPrintTitles        bool                     `xml:"fieldPrintTitles,attr,omitempty"`
+	ItemPrintTitles         bool                     `xml:"itemPrintTitles,attr"`
+	MergeItem               bool                     `xml:"mergeItem,attr,omitempty"`
+	ShowDropZones           bool                     `xml:"showDropZones,attr,omitempty"`
+	CreatedVersion          int                      `xml:"createdVersion,attr"`
+	Indent                  int                      `xml:"indent,attr,omitempty"`
+	ShowEmptyRow            bool                     `xml:"showEmptyRow,attr,omitempty"`
+	ShowEmptyCol            bool                     `xml:"showEmptyCol,attr,omitempty"`
+	ShowHeaders             bool                     `xml:"showHeaders,attr,omitempty"`
+	Compact                 bool                     `xml:"compact,attr,omitempty"`
+	Outline                 bool                     `xml:"outline,attr,omitempty"`
+	OutlineData             bool                     `xml:"outlineData,attr,omitempty"`
+	CompactData             bool                     `xml:"compactData,attr,omitempty"`
+	Published               bool                     `xml:"published,attr,omitempty"`
+	GridDropZones           bool                     `xml:"gridDropZones,attr"`
+	Immersive               bool                     `xml:"immersive,attr,omitempty"`
+	MultipleFieldFilters    bool                     `xml:"multipleFieldFilters,attr,omitempty"`
+	ChartFormat             int                      `xml:"chartFormat,attr,omitempty"`
+	RowHeaderCaption        string                   `xml:"rowHeaderCaption,attr,omitempty"`
+	ColHeaderCaption        string                   `xml:"colHeaderCaption,attr,omitempty"`
+	FieldListSortAscending  bool                     `xml:"fieldListSortAscending,attr,omitempty"`
+	MdxSubqueries           bool                     `xml:"mdxSubqueries,attr,omitempty"`
+	CustomListSort          bool                     `xml:"customListSort,attr,omitempty"`
+	Location                *xlsxLocation            `xml:"location"`
+	PivotFields             *xlsxPivotFields         `xml:"pivotFields"`
+	RowFields               *xlsxRowFields           `xml:"rowFields"`
+	RowItems                *xlsxRowItems            `xml:"rowItems"`
+	ColFields               *xlsxColFields           `xml:"colFields"`
+	ColItems                *xlsxColItems            `xml:"colItems"`
+	PageFields              *xlsxPageFields          `xml:"pageFields"`
+	DataFields              *xlsxDataFields          `xml:"dataFields"`
+	ConditionalFormats      *xlsxConditionalFormats  `xml:"conditionalFormats"`
+	PivotTableStyleInfo     *xlsxPivotTableStyleInfo `xml:"pivotTableStyleInfo"`
 }
 
 // xlsxLocation represents location information for the PivotTable.

+ 6 - 6
xmlWorkbook.go

@@ -11,14 +11,14 @@ package excelize
 
 import "encoding/xml"
 
-// xmlxWorkbookRels contains xmlxWorkbookRelations which maps sheet id and sheet XML.
-type xlsxWorkbookRels struct {
-	XMLName       xml.Name               `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`
-	Relationships []xlsxWorkbookRelation `xml:"Relationship"`
+// xlsxRelationships describe references from parts to other internal resources in the package or to external resources.
+type xlsxRelationships struct {
+	XMLName       xml.Name           `xml:"http://schemas.openxmlformats.org/package/2006/relationships Relationships"`
+	Relationships []xlsxRelationship `xml:"Relationship"`
 }
 
-// xmlxWorkbookRelation maps sheet id and xl/worksheets/_rels/sheet%d.xml.rels
-type xlsxWorkbookRelation struct {
+// xlsxRelationship contains relations which maps id and XML.
+type xlsxRelationship struct {
 	ID         string `xml:"Id,attr"`
 	Target     string `xml:",attr"`
 	Type       string `xml:",attr"`

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor