Skip to content

Commit

Permalink
This closes qax-os#1162, improve the compatibility with alternate con…
Browse files Browse the repository at this point in the history
…tent

Preserve alternate content in the workbook, worksheet, and drawingML
  • Loading branch information
xuri committed Mar 5, 2022
1 parent a1da0d7 commit a647451
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 79 deletions.
3 changes: 2 additions & 1 deletion comment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
package excelize

import (
"encoding/xml"
"path/filepath"
"strings"
"testing"
Expand All @@ -38,7 +39,7 @@ func TestAddComments(t *testing.T) {
}

f.Comments["xl/comments2.xml"] = nil
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>`))
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>`))
comments := f.GetComments()
assert.EqualValues(t, 2, len(comments["Sheet1"]))
assert.EqualValues(t, 1, len(comments["Sheet2"]))
Expand Down
6 changes: 6 additions & 0 deletions drawing.go
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,12 @@ func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
log.Printf("xml decode error: %s", err)
}
content.R = decodeWsDr.R
for _, v := range decodeWsDr.AlternateContent {
content.AlternateContent = append(content.AlternateContent, &xlsxAlternateContent{
Content: v.Content,
XMLNSMC: SourceRelationshipCompatibility.Value,
})
}
for _, v := range decodeWsDr.OneCellAnchor {
content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
EditAs: v.EditAs,
Expand Down
7 changes: 6 additions & 1 deletion drawing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
package excelize

import (
"encoding/xml"
"sync"
"testing"
)
Expand All @@ -22,9 +23,13 @@ func TestDrawingParser(t *testing.T) {
Pkg: sync.Map{},
}
f.Pkg.Store("charset", MacintoshCyrillicCharset)
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>`))
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>`))
// Test with one cell anchor
f.drawingParser("wsDr")
// Test with unsupported charset
f.drawingParser("charset")
// Test with alternate content
f.Drawings = sync.Map{}
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>`))
f.drawingParser("wsDr")
}
5 changes: 3 additions & 2 deletions rows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package excelize

import (
"bytes"
"encoding/xml"
"fmt"
"path/filepath"
"testing"
Expand Down Expand Up @@ -901,12 +902,12 @@ func TestErrSheetNotExistError(t *testing.T) {

func TestCheckRow(t *testing.T) {
f := NewFile()
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>`))
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>`))
_, err := f.GetRows("Sheet1")
assert.NoError(t, err)
assert.NoError(t, f.SetCellValue("Sheet1", "A1", false))
f = NewFile()
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>`))
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>`))
f.Sheet.Delete("xl/worksheets/sheet1.xml")
delete(f.checked, "xl/worksheets/sheet1.xml")
assert.EqualError(t, f.SetCellValue("Sheet1", "A1", false), newCellNameToCoordinatesError("-", newInvalidCellNameError("-")).Error())
Expand Down
7 changes: 7 additions & 0 deletions sheet.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,13 @@ func (f *File) workSheetWriter() {
if sheet.SheetPr != nil || sheet.Drawing != nil || sheet.Hyperlinks != nil || sheet.Picture != nil || sheet.TableParts != nil {
f.addNameSpaces(p.(string), SourceRelationship)
}
if sheet.DecodeAlternateContent != nil {
sheet.AlternateContent = &xlsxAlternateContent{
Content: sheet.DecodeAlternateContent.Content,
XMLNSMC: SourceRelationshipCompatibility.Value,
}
}
sheet.DecodeAlternateContent = nil
// reusing buffer
_ = encoder.Encode(sheet)
f.saveFileList(p.(string), replaceRelationshipsBytes(f.replaceNameSpaceBytes(p.(string), buffer.Bytes())))
Expand Down
17 changes: 16 additions & 1 deletion sheet_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package excelize

import (
"encoding/xml"
"fmt"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -404,6 +405,20 @@ func TestSetSheetName(t *testing.T) {
assert.Equal(t, "Sheet1", f.GetSheetName(0))
}

func TestWorksheetWriter(t *testing.T) {
f := NewFile()
// Test set cell value with alternate content
f.Sheet.Delete("xl/worksheets/sheet1.xml")
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>`
f.Pkg.Store("xl/worksheets/sheet1.xml", []byte(fmt.Sprintf(worksheet, 1)))
f.checked = nil
assert.NoError(t, f.SetCellValue("Sheet1", "A1", 2))
f.workSheetWriter()
value, ok := f.Pkg.Load("xl/worksheets/sheet1.xml")
assert.True(t, ok)
assert.Equal(t, fmt.Sprintf(worksheet, 2), string(value.([]byte)))
}

func TestGetWorkbookPath(t *testing.T) {
f := NewFile()
f.Pkg.Delete("_rels/.rels")
Expand All @@ -413,7 +428,7 @@ func TestGetWorkbookPath(t *testing.T) {
func TestGetWorkbookRelsPath(t *testing.T) {
f := NewFile()
f.Pkg.Delete("xl/_rels/.rels")
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>`))
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>`))
assert.Equal(t, "_rels/workbook.xml.rels", f.getWorkbookRelsPath())
}

Expand Down
7 changes: 7 additions & 0 deletions workbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ func (f *File) workbookReader() *xlsxWorkbook {
// structure.
func (f *File) workBookWriter() {
if f.WorkBook != nil {
if f.WorkBook.DecodeAlternateContent != nil {
f.WorkBook.AlternateContent = &xlsxAlternateContent{
Content: f.WorkBook.DecodeAlternateContent.Content,
XMLNSMC: SourceRelationshipCompatibility.Value,
}
}
f.WorkBook.DecodeAlternateContent = nil
output, _ := xml.Marshal(f.WorkBook)
f.saveFileList(f.getWorkbookPath(), replaceRelationshipsBytes(f.replaceNameSpaceBytes(f.getWorkbookPath(), output)))
}
Expand Down
13 changes: 7 additions & 6 deletions xmlDecodeDrawing.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ type decodeCNvSpPr struct {
// changed after serialization and deserialization, two different structures
// are defined. decodeWsDr just for deserialization.
type decodeWsDr struct {
A string `xml:"xmlns a,attr"`
Xdr string `xml:"xmlns xdr,attr"`
R string `xml:"xmlns r,attr"`
OneCellAnchor []*decodeCellAnchor `xml:"oneCellAnchor,omitempty"`
TwoCellAnchor []*decodeCellAnchor `xml:"twoCellAnchor,omitempty"`
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing wsDr,omitempty"`
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing wsDr,omitempty"`
A string `xml:"xmlns a,attr"`
Xdr string `xml:"xmlns xdr,attr"`
R string `xml:"xmlns r,attr"`
AlternateContent []*xlsxInnerXML `xml:"http://schemas.openxmlformats.org/markup-compatibility/2006 AlternateContent"`
OneCellAnchor []*decodeCellAnchor `xml:"oneCellAnchor,omitempty"`
TwoCellAnchor []*decodeCellAnchor `xml:"twoCellAnchor,omitempty"`
}

// decodeTwoCellAnchor directly maps the oneCellAnchor (One Cell Anchor Shape
Expand Down
15 changes: 8 additions & 7 deletions xmlDrawing.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,13 +320,14 @@ type xlsxPoint2D struct {
// wsDr.
type xlsxWsDr struct {
sync.Mutex
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"`
XMLName xml.Name `xml:"xdr:wsDr"`
A string `xml:"xmlns:a,attr,omitempty"`
Xdr string `xml:"xmlns:xdr,attr,omitempty"`
R string `xml:"xmlns:r,attr,omitempty"`
AlternateContent []*xlsxAlternateContent `xml:"mc:AlternateContent"`
AbsoluteAnchor []*xdrCellAnchor `xml:"xdr:absoluteAnchor"`
OneCellAnchor []*xdrCellAnchor `xml:"xdr:oneCellAnchor"`
TwoCellAnchor []*xdrCellAnchor `xml:"xdr:twoCellAnchor"`
}

// xlsxGraphicFrame (Graphic Frame) directly maps the xdr:graphicFrame element.
Expand Down
44 changes: 23 additions & 21 deletions xmlWorkbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,27 +35,29 @@ type xlsxRelationship struct {
// content of the workbook. The workbook's child elements each have their own
// subclause references.
type xlsxWorkbook struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main workbook"`
Conformance string `xml:"conformance,attr,omitempty"`
FileVersion *xlsxFileVersion `xml:"fileVersion"`
FileSharing *xlsxExtLst `xml:"fileSharing"`
WorkbookPr *xlsxWorkbookPr `xml:"workbookPr"`
WorkbookProtection *xlsxWorkbookProtection `xml:"workbookProtection"`
BookViews *xlsxBookViews `xml:"bookViews"`
Sheets xlsxSheets `xml:"sheets"`
FunctionGroups *xlsxExtLst `xml:"functionGroups"`
ExternalReferences *xlsxExternalReferences `xml:"externalReferences"`
DefinedNames *xlsxDefinedNames `xml:"definedNames"`
CalcPr *xlsxCalcPr `xml:"calcPr"`
OleSize *xlsxExtLst `xml:"oleSize"`
CustomWorkbookViews *xlsxCustomWorkbookViews `xml:"customWorkbookViews"`
PivotCaches *xlsxPivotCaches `xml:"pivotCaches"`
SmartTagPr *xlsxExtLst `xml:"smartTagPr"`
SmartTagTypes *xlsxExtLst `xml:"smartTagTypes"`
WebPublishing *xlsxExtLst `xml:"webPublishing"`
FileRecoveryPr *xlsxFileRecoveryPr `xml:"fileRecoveryPr"`
WebPublishObjects *xlsxExtLst `xml:"webPublishObjects"`
ExtLst *xlsxExtLst `xml:"extLst"`
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main workbook"`
Conformance string `xml:"conformance,attr,omitempty"`
FileVersion *xlsxFileVersion `xml:"fileVersion"`
FileSharing *xlsxExtLst `xml:"fileSharing"`
AlternateContent *xlsxAlternateContent `xml:"mc:AlternateContent"`
DecodeAlternateContent *xlsxInnerXML `xml:"http://schemas.openxmlformats.org/markup-compatibility/2006 AlternateContent"`
WorkbookPr *xlsxWorkbookPr `xml:"workbookPr"`
WorkbookProtection *xlsxWorkbookProtection `xml:"workbookProtection"`
BookViews *xlsxBookViews `xml:"bookViews"`
Sheets xlsxSheets `xml:"sheets"`
FunctionGroups *xlsxExtLst `xml:"functionGroups"`
ExternalReferences *xlsxExternalReferences `xml:"externalReferences"`
DefinedNames *xlsxDefinedNames `xml:"definedNames"`
CalcPr *xlsxCalcPr `xml:"calcPr"`
OleSize *xlsxExtLst `xml:"oleSize"`
CustomWorkbookViews *xlsxCustomWorkbookViews `xml:"customWorkbookViews"`
PivotCaches *xlsxPivotCaches `xml:"pivotCaches"`
SmartTagPr *xlsxExtLst `xml:"smartTagPr"`
SmartTagTypes *xlsxExtLst `xml:"smartTagTypes"`
WebPublishing *xlsxExtLst `xml:"webPublishing"`
FileRecoveryPr *xlsxFileRecoveryPr `xml:"fileRecoveryPr"`
WebPublishObjects *xlsxExtLst `xml:"webPublishObjects"`
ExtLst *xlsxExtLst `xml:"extLst"`
}

// xlsxFileRecoveryPr maps sheet recovery information. This element defines
Expand Down
Loading

0 comments on commit a647451

Please sign in to comment.