mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 16:44:23 +08:00
220 lines
6.6 KiB
Go
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
|
|
}
|