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 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 ```bash
go get github.com/xuri/excelize/v2 go get github.com/xuri/excelize/v2

View File

@ -23,7 +23,7 @@ Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基
go get github.com/xuri/excelize 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 ```bash
go get github.com/xuri/excelize/v2 go get github.com/xuri/excelize/v2

View File

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

View File

@ -19,6 +19,106 @@ import (
"reflect" "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 // SetDocProps provides a function to set document core properties. The
// properties that can be set are: // 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} 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) { func TestSetDocProps(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "Book1.xlsx")) f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
if !assert.NoError(t, err) { if !assert.NoError(t, err) {

Binary file not shown.

View File

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

View File

@ -19,37 +19,39 @@ import (
// Source relationship and namespace list, associated prefixes and schema in which it was // Source relationship and namespace list, associated prefixes and schema in which it was
// introduced. // introduced.
var ( var (
SourceRelationship = xml.Attr{Name: xml.Name{Local: "r", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"} SourceRelationship = xml.Attr{Name: xml.Name{Local: "r", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/relationships"}
SourceRelationshipCompatibility = xml.Attr{Name: xml.Name{Local: "mc", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"} SourceRelationshipCompatibility = xml.Attr{Name: xml.Name{Local: "mc", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/markup-compatibility/2006"}
SourceRelationshipChart20070802 = xml.Attr{Name: xml.Name{Local: "c14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"} SourceRelationshipChart20070802 = xml.Attr{Name: xml.Name{Local: "c14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2007/8/2/chart"}
SourceRelationshipChart2014 = xml.Attr{Name: xml.Name{Local: "c16", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2014/chart"} SourceRelationshipChart2014 = xml.Attr{Name: xml.Name{Local: "c16", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2014/chart"}
SourceRelationshipChart201506 = xml.Attr{Name: xml.Name{Local: "c16r2", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2015/06/chart"} SourceRelationshipChart201506 = xml.Attr{Name: xml.Name{Local: "c16r2", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/drawing/2015/06/chart"}
NameSpaceSpreadSheet = xml.Attr{Name: xml.Name{Local: "xmlns"}, Value: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"} NameSpaceSpreadSheet = xml.Attr{Name: xml.Name{Local: "xmlns"}, Value: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
NameSpaceSpreadSheetX14 = xml.Attr{Name: xml.Name{Local: "x14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"} NameSpaceSpreadSheetX14 = xml.Attr{Name: xml.Name{Local: "x14", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"}
NameSpaceDrawingML = xml.Attr{Name: xml.Name{Local: "a", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/main"} NameSpaceDrawingML = xml.Attr{Name: xml.Name{Local: "a", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/main"}
NameSpaceDrawingMLChart = xml.Attr{Name: xml.Name{Local: "c", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/chart"} NameSpaceDrawingMLChart = xml.Attr{Name: xml.Name{Local: "c", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/chart"}
NameSpaceDrawingMLSpreadSheet = xml.Attr{Name: xml.Name{Local: "xdr", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"} NameSpaceDrawingMLSpreadSheet = xml.Attr{Name: xml.Name{Local: "xdr", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"}
NameSpaceSpreadSheetX15 = xml.Attr{Name: xml.Name{Local: "x15", Space: "xmlns"}, Value: "http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"} 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"} 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"} 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. // Source relationship and namespace.
const ( const (
SourceRelationshipOfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" SourceRelationshipOfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart" SourceRelationshipChart = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"
SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" SourceRelationshipComments = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" SourceRelationshipImage = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table" SourceRelationshipTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"
SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing" SourceRelationshipDrawingML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"
SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" SourceRelationshipDrawingVML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing"
SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" SourceRelationshipHyperLink = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" SourceRelationshipWorkSheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet" SourceRelationshipChartsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"
SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet" SourceRelationshipDialogsheet = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"
SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable" SourceRelationshipPivotTable = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable"
SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition" SourceRelationshipPivotCache = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition"
SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" SourceRelationshipSharedStrings = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject" SourceRelationshipVBAProject = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
NameSpaceXML = "http://www.w3.org/XML/1998/namespace" NameSpaceXML = "http://www.w3.org/XML/1998/namespace"
NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance" NameSpaceXMLSchemaInstance = "http://www.w3.org/2001/XMLSchema-instance"