Skip to content

Commit f0cb29c

Browse files
committed
This closes #1162, improve the compatibility with alternate content
Preserve alternate content in the workbook, worksheet, and drawingML
1 parent 129052a commit f0cb29c

File tree

11 files changed

+137
-79
lines changed

11 files changed

+137
-79
lines changed

comment_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package excelize
1313

1414
import (
15+
"encoding/xml"
1516
"path/filepath"
1617
"strings"
1718
"testing"
@@ -38,7 +39,7 @@ func TestAddComments(t *testing.T) {
3839
}
3940

4041
f.Comments["xl/comments2.xml"] = nil
41-
f.Pkg.Store("xl/comments2.xml", []byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><authors><author>Excelize: </author></authors><commentList><comment ref="B7" authorId="0"><text><t>Excelize: </t></text></comment></commentList></comments>`))
42+
f.Pkg.Store("xl/comments2.xml", []byte(xml.Header+`<comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><authors><author>Excelize: </author></authors><commentList><comment ref="B7" authorId="0"><text><t>Excelize: </t></text></comment></commentList></comments>`))
4243
comments := f.GetComments()
4344
assert.EqualValues(t, 2, len(comments["Sheet1"]))
4445
assert.EqualValues(t, 1, len(comments["Sheet2"]))

drawing.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,12 @@ func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
11601160
log.Printf("xml decode error: %s", err)
11611161
}
11621162
content.R = decodeWsDr.R
1163+
for _, v := range decodeWsDr.AlternateContent {
1164+
content.AlternateContent = append(content.AlternateContent, &xlsxAlternateContent{
1165+
Content: v.Content,
1166+
XMLNSMC: SourceRelationshipCompatibility.Value,
1167+
})
1168+
}
11631169
for _, v := range decodeWsDr.OneCellAnchor {
11641170
content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
11651171
EditAs: v.EditAs,

drawing_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package excelize
1313

1414
import (
15+
"encoding/xml"
1516
"sync"
1617
"testing"
1718
)
@@ -22,9 +23,13 @@ func TestDrawingParser(t *testing.T) {
2223
Pkg: sync.Map{},
2324
}
2425
f.Pkg.Store("charset", MacintoshCyrillicCharset)
25-
f.Pkg.Store("wsDr", []byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"><xdr:oneCellAnchor><xdr:graphicFrame/></xdr:oneCellAnchor></xdr:wsDr>`))
26+
f.Pkg.Store("wsDr", []byte(xml.Header+`<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"><xdr:oneCellAnchor><xdr:graphicFrame/></xdr:oneCellAnchor></xdr:wsDr>`))
2627
// Test with one cell anchor
2728
f.drawingParser("wsDr")
2829
// Test with unsupported charset
2930
f.drawingParser("charset")
31+
// Test with alternate content
32+
f.Drawings = sync.Map{}
33+
f.Pkg.Store("wsDr", []byte(xml.Header+`<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"><mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:Choice xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" Requires="a14"><xdr:twoCellAnchor editAs="oneCell"></xdr:twoCellAnchor></mc:Choice><mc:Fallback/></mc:AlternateContent></xdr:wsDr>`))
34+
f.drawingParser("wsDr")
3035
}

rows_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package excelize
22

33
import (
44
"bytes"
5+
"encoding/xml"
56
"fmt"
67
"path/filepath"
78
"testing"
@@ -901,12 +902,12 @@ func TestErrSheetNotExistError(t *testing.T) {
901902

902903
func TestCheckRow(t *testing.T) {
903904
f := NewFile()
904-
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ><sheetData><row r="2"><c><v>1</v></c><c r="F2"><v>2</v></c><c><v>3</v></c><c><v>4</v></c><c r="M2"><v>5</v></c></row></sheetData></worksheet>`))
905+
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(xml.Header+`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ><sheetData><row r="2"><c><v>1</v></c><c r="F2"><v>2</v></c><c><v>3</v></c><c><v>4</v></c><c r="M2"><v>5</v></c></row></sheetData></worksheet>`))
905906
_, err := f.GetRows("Sheet1")
906907
assert.NoError(t, err)
907908
assert.NoError(t, f.SetCellValue("Sheet1", "A1", false))
908909
f = NewFile()
909-
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ><sheetData><row r="2"><c><v>1</v></c><c r="-"><v>2</v></c><c><v>3</v></c><c><v>4</v></c><c r="M2"><v>5</v></c></row></sheetData></worksheet>`))
910+
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(xml.Header+`<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" ><sheetData><row r="2"><c><v>1</v></c><c r="-"><v>2</v></c><c><v>3</v></c><c><v>4</v></c><c r="M2"><v>5</v></c></row></sheetData></worksheet>`))
910911
f.Sheet.Delete("xl/worksheets/sheet1.xml")
911912
delete(f.checked, "xl/worksheets/sheet1.xml")
912913
assert.EqualError(t, f.SetCellValue("Sheet1", "A1", false), newCellNameToCoordinatesError("-", newInvalidCellNameError("-")).Error())

sheet.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,13 @@ func (f *File) workSheetWriter() {
158158
if sheet.SheetPr != nil || sheet.Drawing != nil || sheet.Hyperlinks != nil || sheet.Picture != nil || sheet.TableParts != nil {
159159
f.addNameSpaces(p.(string), SourceRelationship)
160160
}
161+
if sheet.DecodeAlternateContent != nil {
162+
sheet.AlternateContent = &xlsxAlternateContent{
163+
Content: sheet.DecodeAlternateContent.Content,
164+
XMLNSMC: SourceRelationshipCompatibility.Value,
165+
}
166+
}
167+
sheet.DecodeAlternateContent = nil
161168
// reusing buffer
162169
_ = encoder.Encode(sheet)
163170
f.saveFileList(p.(string), replaceRelationshipsBytes(f.replaceNameSpaceBytes(p.(string), buffer.Bytes())))

sheet_test.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package excelize
22

33
import (
4+
"encoding/xml"
45
"fmt"
56
"path/filepath"
67
"strconv"
@@ -404,6 +405,20 @@ func TestSetSheetName(t *testing.T) {
404405
assert.Equal(t, "Sheet1", f.GetSheetName(0))
405406
}
406407

408+
func TestWorksheetWriter(t *testing.T) {
409+
f := NewFile()
410+
// Test set cell value with alternate content
411+
f.Sheet.Delete("xl/worksheets/sheet1.xml")
412+
worksheet := xml.Header + `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheetData><row r="1"><c r="A1"><v>%d</v></c></row></sheetData><mc:AlternateContent xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"><mc:Choice xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" Requires="a14"><xdr:twoCellAnchor editAs="oneCell"></xdr:twoCellAnchor></mc:Choice><mc:Fallback/></mc:AlternateContent></worksheet>`
413+
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(worksheet, 1)))
414+
f.checked = nil
415+
assert.NoError(t, f.SetCellValue("Sheet1", "A1", 2))
416+
f.workSheetWriter()
417+
value, ok := f.Pkg.Load("xl/worksheets/sheet1.xml")
418+
assert.True(t, ok)
419+
assert.Equal(t, fmt.Sprintf(worksheet, 2), string(value.([]byte)))
420+
}
421+
407422
func TestGetWorkbookPath(t *testing.T) {
408423
f := NewFile()
409424
f.Pkg.Delete("_rels/.rels")
@@ -413,7 +428,7 @@ func TestGetWorkbookPath(t *testing.T) {
413428
func TestGetWorkbookRelsPath(t *testing.T) {
414429
f := NewFile()
415430
f.Pkg.Delete("xl/_rels/.rels")
416-
f.Pkg.Store("_rels/.rels", []byte(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument" Target="/workbook.xml"/></Relationships>`))
431+
f.Pkg.Store("_rels/.rels", []byte(xml.Header+`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument" Target="/workbook.xml"/></Relationships>`))
417432
assert.Equal(t, "_rels/workbook.xml.rels", f.getWorkbookRelsPath())
418433
}
419434

workbook.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ func (f *File) workbookReader() *xlsxWorkbook {
101101
// structure.
102102
func (f *File) workBookWriter() {
103103
if f.WorkBook != nil {
104+
if f.WorkBook.DecodeAlternateContent != nil {
105+
f.WorkBook.AlternateContent = &xlsxAlternateContent{
106+
Content: f.WorkBook.DecodeAlternateContent.Content,
107+
XMLNSMC: SourceRelationshipCompatibility.Value,
108+
}
109+
}
110+
f.WorkBook.DecodeAlternateContent = nil
104111
output, _ := xml.Marshal(f.WorkBook)
105112
f.saveFileList(f.getWorkbookPath(), replaceRelationshipsBytes(f.replaceNameSpaceBytes(f.getWorkbookPath(), output)))
106113
}

xmlDecodeDrawing.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ type decodeCNvSpPr struct {
6363
// changed after serialization and deserialization, two different structures
6464
// are defined. decodeWsDr just for deserialization.
6565
type decodeWsDr struct {
66-
A string `xml:"xmlns a,attr"`
67-
Xdr string `xml:"xmlns xdr,attr"`
68-
R string `xml:"xmlns r,attr"`
69-
OneCellAnchor []*decodeCellAnchor `xml:"oneCellAnchor,omitempty"`
70-
TwoCellAnchor []*decodeCellAnchor `xml:"twoCellAnchor,omitempty"`
71-
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing wsDr,omitempty"`
66+
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing wsDr,omitempty"`
67+
A string `xml:"xmlns a,attr"`
68+
Xdr string `xml:"xmlns xdr,attr"`
69+
R string `xml:"xmlns r,attr"`
70+
AlternateContent []*xlsxInnerXML `xml:"http://schemas.openxmlformats.org/markup-compatibility/2006 AlternateContent"`
71+
OneCellAnchor []*decodeCellAnchor `xml:"oneCellAnchor,omitempty"`
72+
TwoCellAnchor []*decodeCellAnchor `xml:"twoCellAnchor,omitempty"`
7273
}
7374

7475
// decodeTwoCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape

xmlDrawing.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -320,13 +320,14 @@ type xlsxPoint2D struct {
320320
// wsDr.
321321
type xlsxWsDr struct {
322322
sync.Mutex
323-
XMLName xml.Name `xml:"xdr:wsDr"`
324-
AbsoluteAnchor []*xdrCellAnchor `xml:"xdr:absoluteAnchor"`
325-
OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"`
326-
TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"`
327-
A string `xml:"xmlns:a,attr,omitempty"`
328-
Xdr string `xml:"xmlns:xdr,attr,omitempty"`
329-
R string `xml:"xmlns:r,attr,omitempty"`
323+
XMLName xml.Name `xml:"xdr:wsDr"`
324+
A string `xml:"xmlns:a,attr,omitempty"`
325+
Xdr string `xml:"xmlns:xdr,attr,omitempty"`
326+
R string `xml:"xmlns:r,attr,omitempty"`
327+
AlternateContent []*xlsxAlternateContent `xml:"mc:AlternateContent"`
328+
AbsoluteAnchor []*xdrCellAnchor `xml:"xdr:absoluteAnchor"`
329+
OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"`
330+
TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"`
330331
}
331332

332333
// xlsxGraphicFrame (Graphic Frame) directly maps the xdr:graphicFrame element.

xmlWorkbook.go

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,29 @@ type xlsxRelationship struct {
3535
// content of the workbook. The workbook's child elements each have their own
3636
// subclause references.
3737
type xlsxWorkbook struct {
38-
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main workbook"`
39-
Conformance string `xml:"conformance,attr,omitempty"`
40-
FileVersion *xlsxFileVersion `xml:"fileVersion"`
41-
FileSharing *xlsxExtLst `xml:"fileSharing"`
42-
WorkbookPr *xlsxWorkbookPr `xml:"workbookPr"`
43-
WorkbookProtection *xlsxWorkbookProtection `xml:"workbookProtection"`
44-
BookViews *xlsxBookViews `xml:"bookViews"`
45-
Sheets xlsxSheets `xml:"sheets"`
46-
FunctionGroups *xlsxExtLst `xml:"functionGroups"`
47-
ExternalReferences *xlsxExternalReferences `xml:"externalReferences"`
48-
DefinedNames *xlsxDefinedNames `xml:"definedNames"`
49-
CalcPr *xlsxCalcPr `xml:"calcPr"`
50-
OleSize *xlsxExtLst `xml:"oleSize"`
51-
CustomWorkbookViews *xlsxCustomWorkbookViews `xml:"customWorkbookViews"`
52-
PivotCaches *xlsxPivotCaches `xml:"pivotCaches"`
53-
SmartTagPr *xlsxExtLst `xml:"smartTagPr"`
54-
SmartTagTypes *xlsxExtLst `xml:"smartTagTypes"`
55-
WebPublishing *xlsxExtLst `xml:"webPublishing"`
56-
FileRecoveryPr *xlsxFileRecoveryPr `xml:"fileRecoveryPr"`
57-
WebPublishObjects *xlsxExtLst `xml:"webPublishObjects"`
58-
ExtLst *xlsxExtLst `xml:"extLst"`
38+
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main workbook"`
39+
Conformance string `xml:"conformance,attr,omitempty"`
40+
FileVersion *xlsxFileVersion `xml:"fileVersion"`
41+
FileSharing *xlsxExtLst `xml:"fileSharing"`
42+
AlternateContent *xlsxAlternateContent `xml:"mc:AlternateContent"`
43+
DecodeAlternateContent *xlsxInnerXML `xml:"http://schemas.openxmlformats.org/markup-compatibility/2006 AlternateContent"`
44+
WorkbookPr *xlsxWorkbookPr `xml:"workbookPr"`
45+
WorkbookProtection *xlsxWorkbookProtection `xml:"workbookProtection"`
46+
BookViews *xlsxBookViews `xml:"bookViews"`
47+
Sheets xlsxSheets `xml:"sheets"`
48+
FunctionGroups *xlsxExtLst `xml:"functionGroups"`
49+
ExternalReferences *xlsxExternalReferences `xml:"externalReferences"`
50+
DefinedNames *xlsxDefinedNames `xml:"definedNames"`
51+
CalcPr *xlsxCalcPr `xml:"calcPr"`
52+
OleSize *xlsxExtLst `xml:"oleSize"`
53+
CustomWorkbookViews *xlsxCustomWorkbookViews `xml:"customWorkbookViews"`
54+
PivotCaches *xlsxPivotCaches `xml:"pivotCaches"`
55+
SmartTagPr *xlsxExtLst `xml:"smartTagPr"`
56+
SmartTagTypes *xlsxExtLst `xml:"smartTagTypes"`
57+
WebPublishing *xlsxExtLst `xml:"webPublishing"`
58+
FileRecoveryPr *xlsxFileRecoveryPr `xml:"fileRecoveryPr"`
59+
WebPublishObjects *xlsxExtLst `xml:"webPublishObjects"`
60+
ExtLst *xlsxExtLst `xml:"extLst"`
5961
}
6062

6163
// xlsxFileRecoveryPr maps sheet recovery information. This element defines

0 commit comments

Comments
 (0)