Files
ofdgo/ofdgo_meta.go
T
2026-10-25 20:39:50 +08:00

220 lines
6.6 KiB
Go

// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ofdgo
import (
"encoding/xml"
"fmt"
)
// ofdCreator 标识本库生成的文档
const ofdCreator = "xiaoqidun/ofdgo"
// OFD OFD入口结构
// 代表OFD文档的根节点
type OFD struct {
XMLName xml.Name `xml:"OFD"`
Version string `xml:"Version,attr"`
DocType string `xml:"DocType,attr"`
DocBody []DocBody `xml:"DocBody"`
}
// DocBody 文档体信息
// 包含文档元数据和根节点路径
type DocBody struct {
DocInfo DocInfo `xml:"DocInfo"`
DocRoot string `xml:"DocRoot"`
Signatures string `xml:"Signatures"`
versioned bool
}
// DocInfo 文档元数据
type DocInfo struct {
DocID string `xml:"DocID"`
Title string `xml:"Title"`
Author string `xml:"Author"`
Subject string `xml:"Subject"`
Abstract string `xml:"Abstract"`
CreationDate string `xml:"CreationDate"`
ModDate string `xml:"ModDate"`
DocUsage string `xml:"DocUsage"`
Cover string `xml:"Cover"`
Keywords Keywords `xml:"Keywords,omitempty"`
Creator string `xml:"Creator"`
CreatorVersion string `xml:"CreatorVersion"`
CustomDatas *CustomDatas `xml:"CustomDatas"`
}
// Keywords 保存有序关键词,保留重复及空文本,空集合不生成XML节点
type Keywords []string
// CustomDatas 自定义数据集合
type CustomDatas struct {
CustomData []CustomData `xml:"CustomData"`
}
// CustomData 自定义数据项
type CustomData struct {
Name string `xml:"Name,attr"`
Value string `xml:",chardata"`
sourceIndex int
}
// UnmarshalXML 读取主入口,区分标准文档条目与扩展中的同名节点
// 入参: decoder XML解码器, start 起始节点
// 返回: error 解析错误
func (ofd *OFD) UnmarshalXML(decoder *xml.Decoder, start xml.StartElement) error {
if start.Name.Local != "OFD" {
return fmt.Errorf("expected OFD root, got %s", start.Name.Local)
}
*ofd = OFD{XMLName: start.Name, Version: attrValue(start, "Version"), DocType: attrValue(start, "DocType")}
return decodeOFDChildren(decoder, start, func(d *xml.Decoder, node xml.StartElement) error {
if node.Name.Local != "DocBody" {
return d.Skip()
}
var body DocBody
if err := d.DecodeElement(&body, &node); err != nil {
return err
}
ofd.DocBody = append(ofd.DocBody, body)
return nil
})
}
// UnmarshalXML 读取文档入口并记录版本列表是否存在,版本描述在选择时读取
// 入参: decoder XML解码器, start 起始节点
// 返回: error 解析错误
func (body *DocBody) UnmarshalXML(decoder *xml.Decoder, start xml.StartElement) error {
*body = DocBody{}
return decodeOFDChildren(decoder, start, func(d *xml.Decoder, node xml.StartElement) error {
switch node.Name.Local {
case "DocInfo":
return d.DecodeElement(&body.DocInfo, &node)
case "DocRoot":
return d.DecodeElement(&body.DocRoot, &node)
case "Signatures":
return d.DecodeElement(&body.Signatures, &node)
case "Versions":
body.versioned = true
}
return d.Skip()
})
}
// UnmarshalXML 读取文档元数据,不将外部同名字段作为OFD信息
// 入参: d XML解码器, start 起始节点
// 返回: error 解析错误
func (info *DocInfo) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
*info = DocInfo{}
return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error {
var target any
switch node.Name.Local {
case "DocID":
target = &info.DocID
case "Title":
target = &info.Title
case "Author":
target = &info.Author
case "Subject":
target = &info.Subject
case "Abstract":
target = &info.Abstract
case "CreationDate":
target = &info.CreationDate
case "ModDate":
target = &info.ModDate
case "DocUsage":
target = &info.DocUsage
case "Cover":
target = &info.Cover
case "Keywords":
target = &info.Keywords
case "Creator":
target = &info.Creator
case "CreatorVersion":
target = &info.CreatorVersion
case "CustomDatas":
target = &info.CustomDatas
default:
return d.Skip()
}
return d.DecodeElement(target, &node)
})
}
// UnmarshalXML 按原顺序读取标准关键词,跳过外部扩展条目
// 入参: d XML解码器, start 起始节点
// 返回: error 解析错误
func (keywords *Keywords) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
*keywords = nil
return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error {
if node.Name.Local != "Keyword" {
return d.Skip()
}
var value string
if err := d.DecodeElement(&value, &node); err != nil {
return err
}
*keywords = append(*keywords, value)
return nil
})
}
// MarshalXML 编码非空关键词集合,子节点沿用集合的命名空间
// 入参: e XML编码器, start 起始节点
// 返回: error 编码错误
func (keywords Keywords) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if len(keywords) == 0 {
return nil
}
if err := e.EncodeToken(start); err != nil {
return err
}
for _, value := range keywords {
child := xml.StartElement{Name: xml.Name{Space: start.Name.Space, Local: "Keyword"}}
if err := e.EncodeElement(value, child); err != nil {
return err
}
}
return e.EncodeToken(start.End())
}
// UnmarshalXML 按原顺序读取OFD自定义字段,跳过外部扩展条目
// 入参: d XML解码器, start 起始节点
// 返回: error 解析错误
func (data *CustomDatas) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
*data = CustomDatas{}
return decodeOFDChildren(d, start, func(d *xml.Decoder, node xml.StartElement) error {
if node.Name.Local != "CustomData" {
return d.Skip()
}
return d.DecodeElement(&data.CustomData, &node)
})
}
// UnmarshalXML 读取自定义字段的名称和文本,忽略带命名空间的属性
// 入参: d XML解码器, start 起始节点
// 返回: error 解析错误
func (data *CustomData) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type customData CustomData
var value customData
start = ofdXMLStart(start)
if err := d.DecodeElement(&value, &start); err != nil {
return err
}
*data = CustomData(value)
return nil
}