Skip to content

Commit 6b1e592

Browse files
committed
This closes #1095, support to set and get document application properties
1 parent 089cd36 commit 6b1e592

File tree

8 files changed

+212
-52
lines changed

8 files changed

+212
-52
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Excelize is a library written in pure Go providing a set of functions that allow
2323
go get github.com/xuri/excelize
2424
```
2525

26-
- If your packages are managed using [Go Modules](https://blog.golang.org/using-go-modules), please install with following command.
26+
- If your packages are managed using [Go Modules](https://go.dev/blog/using-go-modules), please install with following command.
2727

2828
```bash
2929
go get github.com/xuri/excelize/v2

README_zh.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基
2323
go get github.com/xuri/excelize
2424
```
2525

26-
- 如果您使用 [Go Modules](https://blog.golang.org/using-go-modules) 管理软件包,请使用下面的命令来安装最新版本。
26+
- 如果您使用 [Go Modules](https://go.dev/blog/using-go-modules) 管理软件包,请使用下面的命令来安装最新版本。
2727

2828
```bash
2929
go get github.com/xuri/excelize/v2

calc.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@ type formulaFuncs struct {
626626
// WEIBULL
627627
// WEIBULL.DIST
628628
// XIRR
629+
// XLOOKUP
629630
// XNPV
630631
// XOR
631632
// YEAR

docProps.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,106 @@ import (
1919
"reflect"
2020
)
2121

22+
// SetAppProps provides a function to set document application properties. The
23+
// properties that can be set are:
24+
//
25+
// Property | Description
26+
// -------------------+--------------------------------------------------------------------------
27+
// Application | The name of the application that created this document.
28+
// |
29+
// ScaleCrop | Indicates the display mode of the document thumbnail. Set this element
30+
// | to TRUE to enable scaling of the document thumbnail to the display. Set
31+
// | this element to FALSE to enable cropping of the document thumbnail to
32+
// | show only sections that will fit the display.
33+
// |
34+
// DocSecurity | Security level of a document as a numeric value. Document security is
35+
// | defined as:
36+
// | 1 - Document is password protected.
37+
// | 2 - Document is recommended to be opened as read-only.
38+
// | 3 - Document is enforced to be opened as read-only.
39+
// | 4 - Document is locked for annotation.
40+
// |
41+
// Company | The name of a company associated with the document.
42+
// |
43+
// LinksUpToDate | Indicates whether hyperlinks in a document are up-to-date. Set this
44+
// | element to TRUE to indicate that hyperlinks are updated. Set this
45+
// | element to FALSE to indicate that hyperlinks are outdated.
46+
// |
47+
// HyperlinksChanged | Specifies that one or more hyperlinks in this part were updated
48+
// | exclusively in this part by a producer. The next producer to open this
49+
// | document shall update the hyperlink relationships with the new
50+
// | hyperlinks specified in this part.
51+
// |
52+
// AppVersion | Specifies the version of the application which produced this document.
53+
// | The content of this element shall be of the form XX.YYYY where X and Y
54+
// | represent numerical values, or the document shall be considered
55+
// | non-conformant.
56+
//
57+
// For example:
58+
//
59+
// err := f.SetAppProps(&excelize.AppProperties{
60+
// Application: "Microsoft Excel",
61+
// ScaleCrop: true,
62+
// DocSecurity: 3,
63+
// Company: "Company Name",
64+
// LinksUpToDate: true,
65+
// HyperlinksChanged: true,
66+
// AppVersion: "16.0000",
67+
// })
68+
//
69+
func (f *File) SetAppProps(appProperties *AppProperties) (err error) {
70+
var (
71+
app *xlsxProperties
72+
fields []string
73+
output []byte
74+
immutable, mutable reflect.Value
75+
field string
76+
)
77+
app = new(xlsxProperties)
78+
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("docProps/app.xml")))).
79+
Decode(app); err != nil && err != io.EOF {
80+
err = fmt.Errorf("xml decode error: %s", err)
81+
return
82+
}
83+
fields = []string{"Application", "ScaleCrop", "DocSecurity", "Company", "LinksUpToDate", "HyperlinksChanged", "AppVersion"}
84+
immutable, mutable = reflect.ValueOf(*appProperties), reflect.ValueOf(app).Elem()
85+
for _, field = range fields {
86+
immutableField := immutable.FieldByName(field)
87+
switch immutableField.Kind() {
88+
case reflect.Bool:
89+
mutable.FieldByName(field).SetBool(immutableField.Bool())
90+
case reflect.Int:
91+
mutable.FieldByName(field).SetInt(immutableField.Int())
92+
default:
93+
mutable.FieldByName(field).SetString(immutableField.String())
94+
}
95+
}
96+
app.Vt = NameSpaceDocumentPropertiesVariantTypes.Value
97+
output, err = xml.Marshal(app)
98+
f.saveFileList("docProps/app.xml", output)
99+
return
100+
}
101+
102+
// GetAppProps provides a function to get document application properties.
103+
func (f *File) GetAppProps() (ret *AppProperties, err error) {
104+
var app = new(xlsxProperties)
105+
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("docProps/app.xml")))).
106+
Decode(app); err != nil && err != io.EOF {
107+
err = fmt.Errorf("xml decode error: %s", err)
108+
return
109+
}
110+
ret, err = &AppProperties{
111+
Application: app.Application,
112+
ScaleCrop: app.ScaleCrop,
113+
DocSecurity: app.DocSecurity,
114+
Company: app.Company,
115+
LinksUpToDate: app.LinksUpToDate,
116+
HyperlinksChanged: app.HyperlinksChanged,
117+
AppVersion: app.AppVersion,
118+
}, nil
119+
return
120+
}
121+
22122
// SetDocProps provides a function to set document core properties. The
23123
// properties that can be set are:
24124
//

docProps_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,51 @@ import (
2020

2121
var MacintoshCyrillicCharset = []byte{0x8F, 0xF0, 0xE8, 0xE2, 0xE5, 0xF2, 0x20, 0xEC, 0xE8, 0xF0}
2222

23+
func TestSetAppProps(t *testing.T) {
24+
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
25+
if !assert.NoError(t, err) {
26+
t.FailNow()
27+
}
28+
assert.NoError(t, f.SetAppProps(&AppProperties{
29+
Application: "Microsoft Excel",
30+
ScaleCrop: true,
31+
DocSecurity: 3,
32+
Company: "Company Name",
33+
LinksUpToDate: true,
34+
HyperlinksChanged: true,
35+
AppVersion: "16.0000",
36+
}))
37+
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetAppProps.xlsx")))
38+
f.Pkg.Store("docProps/app.xml", nil)
39+
assert.NoError(t, f.SetAppProps(&AppProperties{}))
40+
assert.NoError(t, f.Close())
41+
42+
// Test unsupported charset
43+
f = NewFile()
44+
f.Pkg.Store("docProps/app.xml", MacintoshCyrillicCharset)
45+
assert.EqualError(t, f.SetAppProps(&AppProperties{}), "xml decode error: XML syntax error on line 1: invalid UTF-8")
46+
}
47+
48+
func TestGetAppProps(t *testing.T) {
49+
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
50+
if !assert.NoError(t, err) {
51+
t.FailNow()
52+
}
53+
props, err := f.GetAppProps()
54+
assert.NoError(t, err)
55+
assert.Equal(t, props.Application, "Microsoft Macintosh Excel")
56+
f.Pkg.Store("docProps/app.xml", nil)
57+
_, err = f.GetAppProps()
58+
assert.NoError(t, err)
59+
assert.NoError(t, f.Close())
60+
61+
// Test unsupported charset
62+
f = NewFile()
63+
f.Pkg.Store("docProps/app.xml", MacintoshCyrillicCharset)
64+
_, err = f.GetAppProps()
65+
assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8")
66+
}
67+
2368
func TestSetDocProps(t *testing.T) {
2469
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
2570
if !assert.NoError(t, err) {

test/Book1.xlsx

-15 Bytes
Binary file not shown.

xmlApp.go

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,38 +13,50 @@ package excelize
1313

1414
import "encoding/xml"
1515

16+
// AppProperties directly maps the document application properties.
17+
type AppProperties struct {
18+
Application string
19+
ScaleCrop bool
20+
DocSecurity int
21+
Company string
22+
LinksUpToDate bool
23+
HyperlinksChanged bool
24+
AppVersion string
25+
}
26+
1627
// xlsxProperties specifies to an OOXML document properties such as the
1728
// template used, the number of pages and words, and the application name and
1829
// version.
1930
type xlsxProperties struct {
2031
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties Properties"`
21-
Template string
22-
Manager string
23-
Company string
24-
Pages int
25-
Words int
26-
Characters int
27-
PresentationFormat string
28-
Lines int
29-
Paragraphs int
30-
Slides int
31-
Notes int
32-
TotalTime int
33-
HiddenSlides int
34-
MMClips int
35-
ScaleCrop bool
32+
Vt string `xml:"xmlns:vt,attr"`
33+
Template string `xml:",omitempty"`
34+
Manager string `xml:",omitempty"`
35+
Company string `xml:",omitempty"`
36+
Pages int `xml:",omitempty"`
37+
Words int `xml:",omitempty"`
38+
Characters int `xml:",omitempty"`
39+
PresentationFormat string `xml:",omitempty"`
40+
Lines int `xml:",omitempty"`
41+
Paragraphs int `xml:",omitempty"`
42+
Slides int `xml:",omitempty"`
43+
Notes int `xml:",omitempty"`
44+
TotalTime int `xml:",omitempty"`
45+
HiddenSlides int `xml:",omitempty"`
46+
MMClips int `xml:",omitempty"`
47+
ScaleCrop bool `xml:",omitempty"`
3648
HeadingPairs *xlsxVectorVariant
3749
TitlesOfParts *xlsxVectorLpstr
38-
LinksUpToDate bool
39-
CharactersWithSpaces int
40-
SharedDoc bool
41-
HyperlinkBase string
50+
LinksUpToDate bool `xml:",omitempty"`
51+
CharactersWithSpaces int `xml:",omitempty"`
52+
SharedDoc bool `xml:",omitempty"`
53+
HyperlinkBase string `xml:",omitempty"`
4254
HLinks *xlsxVectorVariant
43-
HyperlinksChanged bool
55+
HyperlinksChanged bool `xml:",omitempty"`
4456
DigSig *xlsxDigSig
45-
Application string
46-
AppVersion string
47-
DocSecurity int
57+
Application string `xml:",omitempty"`
58+
AppVersion string `xml:",omitempty"`
59+
DocSecurity int `xml:",omitempty"`
4860
}
4961

5062
// xlsxVectorVariant specifies the set of hyperlinks that were in this

xmlDrawing.go

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,39 @@ import (
1919
// Source relationship and namespace list, associated prefixes and schema in which it was
2020
// introduced.
2121
var (
22-
SourceRelationship = xml.Attr{Name: xml.Name{Local: "r", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"}
23-
SourceRelationshipCompatibility = xml.Attr{Name: xml.Name{Local: "mc", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"}
24-
SourceRelationshipChart20070802 = xml.Attr{Name: xml.Name{Local: "c14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"}
25-
SourceRelationshipChart2014 = xml.Attr{Name: xml.Name{Local: "c16", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2014/chart"}
26-
SourceRelationshipChart201506 = xml.Attr{Name: xml.Name{Local: "c16r2", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2015/06/chart"}
27-
NameSpaceSpreadSheet = xml.Attr{Name: xml.Name{Local: "xmlns"}, Value: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
28-
NameSpaceSpreadSheetX14 = xml.Attr{Name: xml.Name{Local: "x14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"}
29-
NameSpaceDrawingML = xml.Attr{Name: xml.Name{Local: "a", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/main"}
30-
NameSpaceDrawingMLChart = xml.Attr{Name: xml.Name{Local: "c", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/chart"}
31-
NameSpaceDrawingMLSpreadSheet = xml.Attr{Name: xml.Name{Local: "xdr", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"}
32-
NameSpaceSpreadSheetX15 = xml.Attr{Name: xml.Name{Local: "x15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"}
33-
NameSpaceSpreadSheetExcel2006Main = xml.Attr{Name: xml.Name{Local: "xne", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/excel/2006/main"}
34-
NameSpaceMacExcel2008Main = xml.Attr{Name: xml.Name{Local: "mx", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/mac/excel/2008/main"}
22+
SourceRelationship = xml.Attr{Name: xml.Name{Local: "r", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"}
23+
SourceRelationshipCompatibility = xml.Attr{Name: xml.Name{Local: "mc", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"}
24+
SourceRelationshipChart20070802 = xml.Attr{Name: xml.Name{Local: "c14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"}
25+
SourceRelationshipChart2014 = xml.Attr{Name: xml.Name{Local: "c16", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2014/chart"}
26+
SourceRelationshipChart201506 = xml.Attr{Name: xml.Name{Local: "c16r2", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2015/06/chart"}
27+
NameSpaceSpreadSheet = xml.Attr{Name: xml.Name{Local: "xmlns"}, Value: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
28+
NameSpaceSpreadSheetX14 = xml.Attr{Name: xml.Name{Local: "x14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"}
29+
NameSpaceDrawingML = xml.Attr{Name: xml.Name{Local: "a", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/main"}
30+
NameSpaceDrawingMLChart = xml.Attr{Name: xml.Name{Local: "c", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/chart"}
31+
NameSpaceDrawingMLSpreadSheet = xml.Attr{Name: xml.Name{Local: "xdr", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"}
32+
NameSpaceSpreadSheetX15 = xml.Attr{Name: xml.Name{Local: "x15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"}
33+
NameSpaceSpreadSheetExcel2006Main = xml.Attr{Name: xml.Name{Local: "xne", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/excel/2006/main"}
34+
NameSpaceMacExcel2008Main = xml.Attr{Name: xml.Name{Local: "mx", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/mac/excel/2008/main"}
35+
NameSpaceDocumentPropertiesVariantTypes = xml.Attr{Name: xml.Name{Local: "vt", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"}
3536
)
3637

3738
// Source relationship and namespace.
3839
const (
39-
SourceRelationshipOfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
40-
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
41-
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
42-
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
43-
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
44-
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
45-
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
46-
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
47-
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
48-
SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
49-
SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"
50-
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
51-
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
52-
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
40+
SourceRelationshipOfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
41+
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
42+
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
43+
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
44+
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
45+
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
46+
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
47+
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
48+
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
49+
SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
50+
SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"
51+
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
52+
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
53+
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
54+
5355
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
5456
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
5557
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"

0 commit comments

Comments
 (0)