写点什么

Go-Excelize API 源码阅读(二十一)——SetAppProps(appProperties *AppProperties)

作者:Regan Yue
  • 2022-10-15
    湖北
  • 本文字数:3884 字

    阅读完需:约 1 分钟

Go-Excelize API 源码阅读(二十一)——SetAppProps(appProperties *AppProperties)

一、Go-Excelize 简介

Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的电子表格文档。支持 XLAM / XLSM / XLSX / XLTM / XLTX 等多种文档格式,高度兼容带有样式、图片(表)、透视表、切片器等复杂组件的文档,并提供流式读写 API,用于处理包含大规模数据的工作簿。可应用于各类报表平台、云计算、边缘计算等系统。使用本类库要求使用的 Go 语言为 1.15 或更高版本。

二、 SetAppProps(appProperties *AppProperties)

func (f *File) SetAppProps(appProperties *AppProperties) error
复制代码


设置工作簿的应用程序属性。可以设置的属性包括:


//     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.//                       | 指定文档缩略图的显示方式。设置为 true 指定将文档缩略图缩放显示,设置为 false 指定将文档缩略图剪裁显示//     DocSecurity       | Security level of a document as a numeric value. Document security is//                       | defined as:以数值表示的文档安全级别。文档安全定义为://                       | 1 - Document is password protected.1 - 文档受密码保护//                       | 2 - Document is recommended to be opened as read-only.2 - 文档受密码保护//                       | 3 - Document is enforced to be opened as read-only.3 - 强制以只读方式打开文档//                       | 4 - Document is locked for annotation.4 - 文档批注被锁定//                       |//     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.//                       | 设置文档中的超链接是否是最新的。设置为 true 表示超链接已更新,设置为 false 表示超链接已过时//     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.//                       | 指定生成此文档的应用程序的版本。值应为 XX.YYYY 格式,其中 X 和 Y 代表数值,否则文件将不符合标准
复制代码


例如:


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(defaultXMLPathDocPropsApp)))).    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(defaultXMLPathDocPropsApp, output)  return}
复制代码


来看第一部分:


  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(defaultXMLPathDocPropsApp)))).    Decode(app); err != nil && err != io.EOF {    err = fmt.Errorf("xml decode error: %s", err)    return  }
复制代码


先使用 var 一次定义要使用的所有变量,然后使用 new 分配一块内存,返回这块内存的地址就赋给了 app。


  if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(defaultXMLPathDocPropsApp)))).    Decode(app); err != nil && err != io.EOF {    err = fmt.Errorf("xml decode error: %s", err)    return  }
复制代码


然后读取 xml 文件:defaultXMLPathDocPropsApp



Decode 的工作方式与 Unmarshal 类似,不同之处在于它读取解码器流来查找开始元素。下面是它们的源码:


func Unmarshal(data []byte, v any) error {  return NewDecoder(bytes.NewReader(data)).Decode(v)}
func (d *Decoder) Decode(v any) error { return d.DecodeElement(v, nil)}
func (d *Decoder) DecodeElement(v any, start *StartElement) error { val := reflect.ValueOf(v) if val.Kind() != reflect.Pointer { return errors.New("non-pointer passed to Unmarshal") } return d.unmarshal(val.Elem(), start, 0)}
复制代码


接下来建立了一个字段数组:


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(defaultXMLPathDocPropsApp, output)
复制代码


然后再将


NameSpaceDocumentPropertiesVariantTypes = xml.Attr{Name: xml.Name{Local: "vt", Space: "xmlns"}, Value: "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"}
复制代码


的值赋给 app.Vt。


再使用 xml.Marshal(app),进行 xml 编码。


// saveFileList provides a function to update given file content in file list// of spreadsheet.func (f *File) saveFileList(name string, content []byte) {  f.Pkg.Store(name, append([]byte(xml.Header), content...))}
复制代码


再使用 saveFileList 更新电子表格文件列表中给定文件内容。

三、结语

这里是老岳,这是 Go 语言相关源码的解读第二十二篇,我会不断努力,给大家带来更多类似的文章,恳请大家不吝赐教。

发布于: 刚刚阅读数: 5
用户头像

Regan Yue

关注

还未添加个人签名 2020-08-12 加入

对Go、Python、网络安全、区块链感兴趣. · 华为云云享专家 · 掘金资讯创作者

评论

发布
暂无评论
Go-Excelize API源码阅读(二十一)——SetAppProps(appProperties *AppProperties)_Go_Regan Yue_InfoQ写作社区