This closes #1095, support to set and get document application properties

This commit is contained in:
xuri 2021-12-26 14:55:53 +08:00
parent 089cd365a3
commit 6b1e592cbc
No known key found for this signature in database
GPG Key ID: BA5E5BB1C948EDF7
8 changed files with 212 additions and 52 deletions

View File

@ -23,7 +23,7 @@ Excelize is a library written in pure Go providing a set of functions that allow
go get github.com/xuri/excelize
```
- If your packages are managed using [Go Modules](https://blog.golang.org/using-go-modules), please install with following command.
- If your packages are managed using [Go Modules](https://go.dev/blog/using-go-modules), please install with following command.
```bash
go get github.com/xuri/excelize/v2

View File

@ -23,7 +23,7 @@ Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基
go get github.com/xuri/excelize
```
- 如果您使用 [Go Modules](https://blog.golang.org/using-go-modules) 管理软件包,请使用下面的命令来安装最新版本。
- 如果您使用 [Go Modules](https://go.dev/blog/using-go-modules) 管理软件包,请使用下面的命令来安装最新版本。
```bash
go get github.com/xuri/excelize/v2

View File

@ -626,6 +626,7 @@ type formulaFuncs struct {
// WEIBULL
// WEIBULL.DIST
// XIRR
// XLOOKUP
// XNPV
// XOR
// YEAR

View File

@ -19,6 +19,106 @@ import (
"reflect"
)
// SetAppProps provides a function to set document application properties. The
// properties that can be set are:
//
// Property | Description
// -------------------+--------------------------------------------------------------------------
// Application | The name of the application that created this document.
// |
// ScaleCrop | Indicates the display mode of the document thumbnail. Set this element
// | to TRUE to enable scaling of the document thumbnail to the display. Set
// | this element to FALSE to enable cropping of the document thumbnail to
// | show only sections that will fit the display.
// |
// DocSecurity | Security level of a document as a numeric value. Document security is
// | defined as:
// | 1 - Document is password protected.
// | 2 - Document is recommended to be opened as read-only.
// | 3 - Document is enforced to be opened as read-only.
// | 4 - Document is locked for annotation.
// |
// Company | The name of a company associated with the document.
// |
// LinksUpToDate | Indicates whether hyperlinks in a document are up-to-date. Set this
// | element to TRUE to indicate that hyperlinks are updated. Set this
// | element to FALSE to indicate that hyperlinks are outdated.
// |
// HyperlinksChanged | Specifies that one or more hyperlinks in this part were updated
// | exclusively in this part by a producer. The next producer to open this
// | document shall update the hyperlink relationships with the new
// | hyperlinks specified in this part.
// |
// AppVersion | Specifies the version of the application which produced this document.
// | The content of this element shall be of the form XX.YYYY where X and Y
// | represent numerical values, or the document shall be considered
// | non-conformant.
//
// For example:
//
// err := f.SetAppProps(&excelize.AppProperties{
// Application: "Microsoft Excel",
// ScaleCrop: true,
// DocSecurity: 3,
// Company: "Company Name",
// LinksUpToDate: true,
// HyperlinksChanged: true,
// AppVersion: "16.0000",
// })
//
func (f *File) SetAppProps(appProperties *AppProperties) (err error) {
var (
app *xlsxProperties
fields []string
output []byte
immutable, mutable reflect.Value
field string
)
app = new(xlsxProperties)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("docProps/app.xml")))).
Decode(app); err != nil && err != io.EOF {
err = fmt.Errorf("xml decode error: %s", err)
return
}
fields = []string{"Application", "ScaleCrop", "DocSecurity", "Company", "LinksUpToDate", "HyperlinksChanged", "AppVersion"}
immutable, mutable = reflect.ValueOf(*appProperties), reflect.ValueOf(app).Elem()
for _, field = range fields {
immutableField := immutable.FieldByName(field)
switch immutableField.Kind() {
case reflect.Bool:
mutable.FieldByName(field).SetBool(immutableField.Bool())
case reflect.Int:
mutable.FieldByName(field).SetInt(immutableField.Int())
default:
mutable.FieldByName(field).SetString(immutableField.String())
}
}
app.Vt = NameSpaceDocumentPropertiesVariantTypes.Value
output, err = xml.Marshal(app)
f.saveFileList("docProps/app.xml", output)
return
}
// GetAppProps provides a function to get document application properties.
func (f *File) GetAppProps() (ret *AppProperties, err error) {
var app = new(xlsxProperties)
if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML("docProps/app.xml")))).
Decode(app); err != nil && err != io.EOF {
err = fmt.Errorf("xml decode error: %s", err)
return
}
ret, err = &AppProperties{
Application: app.Application,
ScaleCrop: app.ScaleCrop,
DocSecurity: app.DocSecurity,
Company: app.Company,
LinksUpToDate: app.LinksUpToDate,
HyperlinksChanged: app.HyperlinksChanged,
AppVersion: app.AppVersion,
}, nil
return
}
// SetDocProps provides a function to set document core properties. The
// properties that can be set are:
//

View File

@ -20,6 +20,51 @@ import (
var MacintoshCyrillicCharset = []byte{0x8F, 0xF0, 0xE8, 0xE2, 0xE5, 0xF2, 0x20, 0xEC, 0xE8, 0xF0}
func TestSetAppProps(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
assert.NoError(t, f.SetAppProps(&AppProperties{
Application: "Microsoft Excel",
ScaleCrop: true,
DocSecurity: 3,
Company: "Company Name",
LinksUpToDate: true,
HyperlinksChanged: true,
AppVersion: "16.0000",
}))
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestSetAppProps.xlsx")))
f.Pkg.Store("docProps/app.xml", nil)
assert.NoError(t, f.SetAppProps(&AppProperties{}))
assert.NoError(t, f.Close())
// Test unsupported charset
f = NewFile()
f.Pkg.Store("docProps/app.xml", MacintoshCyrillicCharset)
assert.EqualError(t, f.SetAppProps(&AppProperties{}), "xml decode error: XML syntax error on line 1: invalid UTF-8")
}
func TestGetAppProps(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
props, err := f.GetAppProps()
assert.NoError(t, err)
assert.Equal(t, props.Application, "Microsoft Macintosh Excel")
f.Pkg.Store("docProps/app.xml", nil)
_, err = f.GetAppProps()
assert.NoError(t, err)
assert.NoError(t, f.Close())
// Test unsupported charset
f = NewFile()
f.Pkg.Store("docProps/app.xml", MacintoshCyrillicCharset)
_, err = f.GetAppProps()
assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8")
}
func TestSetDocProps(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) {

Binary file not shown.

View File

@ -13,38 +13,50 @@ package excelize
import "encoding/xml"
// AppProperties directly maps the document application properties.
type AppProperties struct {
Application string
ScaleCrop bool
DocSecurity int
Company string
LinksUpToDate bool
HyperlinksChanged bool
AppVersion string
}
// xlsxProperties specifies to an OOXML document properties such as the
// template used, the number of pages and words, and the application name and
// version.
type xlsxProperties struct {
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties Properties"`
Template string
Manager string
Company string
Pages int
Words int
Characters int
PresentationFormat string
Lines int
Paragraphs int
Slides int
Notes int
TotalTime int
HiddenSlides int
MMClips int
ScaleCrop bool
Vt string `xml:"xmlns:vt,attr"`
Template string `xml:",omitempty"`
Manager string `xml:",omitempty"`
Company string `xml:",omitempty"`
Pages int `xml:",omitempty"`
Words int `xml:",omitempty"`
Characters int `xml:",omitempty"`
PresentationFormat string `xml:",omitempty"`
Lines int `xml:",omitempty"`
Paragraphs int `xml:",omitempty"`
Slides int `xml:",omitempty"`
Notes int `xml:",omitempty"`
TotalTime int `xml:",omitempty"`
HiddenSlides int `xml:",omitempty"`
MMClips int `xml:",omitempty"`
ScaleCrop bool `xml:",omitempty"`
HeadingPairs *xlsxVectorVariant
TitlesOfParts *xlsxVectorLpstr
LinksUpToDate bool
CharactersWithSpaces int
SharedDoc bool
HyperlinkBase string
LinksUpToDate bool `xml:",omitempty"`
CharactersWithSpaces int `xml:",omitempty"`
SharedDoc bool `xml:",omitempty"`
HyperlinkBase string `xml:",omitempty"`
HLinks *xlsxVectorVariant
HyperlinksChanged bool
HyperlinksChanged bool `xml:",omitempty"`
DigSig *xlsxDigSig
Application string
AppVersion string
DocSecurity int
Application string `xml:",omitempty"`
AppVersion string `xml:",omitempty"`
DocSecurity int `xml:",omitempty"`
}
// xlsxVectorVariant specifies the set of hyperlinks that were in this

View File

@ -32,6 +32,7 @@ var (
NameSpaceSpreadSheetX15 = xml.Attr{Name: xml.Name{Local: "x15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"}
NameSpaceSpreadSheetExcel2006Main = xml.Attr{Name: xml.Name{Local: "xne", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/excel/2006/main"}
NameSpaceMacExcel2008Main = xml.Attr{Name: xml.Name{Local: "mx", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/mac/excel/2008/main"}
NameSpaceDocumentPropertiesVariantTypes = xml.Attr{Name: xml.Name{Local: "vt", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"}
)
// Source relationship and namespace.
@ -50,6 +51,7 @@ const (
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"