Help us shape the future of Go! Take the 2026 Go Developer Survey

ofdxml

package
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

README

OFD XML 读写

ofdxml 面向 OFD 包内的 XML,支持顺序生成,也支持读取已有 XML、修改节点树并写回。

读取后修改

doc, err := ofdxml.Parse(data)
if err != nil {
	return err
}

// 节点树使用 etree API。按命名空间 URI 区分 OFD 元素和同名扩展元素。
for element := range doc.Root().FindElementsSeq("./Fonts/Font") {
	if element.Tag == "Font" && element.NamespaceURI() == ofdxml.Namespace {
		element.CreateAttr("FontName", "新字体名称")
	}
}

output, err := ofdxml.Marshal(doc)
if err != nil {
	return err
}
// output 可独立长期持有。

Parse 返回 *etree.Document,可使用 CreateAttr、SetText、InsertChild、 RemoveChild、Copy 等方法编辑。跨文档复制或移动子树时,需要补齐原先从祖先 继承的命名空间声明;节点的顺序及 OFD 资源引用由调用方维护。

Marshal 保留原有名称和命名空间声明,保留节点顺序、文本空白、注释和处理指令, 不缩进或修改输入树。CDATA 读取为普通文本,写回统一使用文本转义;即使外部 etree 树带有 CDATA 标记,也按普通文本写出。XML 声明统一为 UTF-8;实体的写法、 引号等形式可能变化。文本中的回车以字符引用写出,以保证重新读取后的文字相同。 编辑后出现多个根元素、根外文本、非法名称或命名空间、非法注释/处理指令、 非法 XML 字符时返回错误。WriteElement 同样报告这些错误及底层流式写入错误。 顺序生成用的 Writer.Text/Attr 继续按其约定替换非法字符;树写回拒绝非法 字符,避免编辑内容被静默替换。

读取结果不借用输入切片,写回结果不借用树或池中的缓冲区。节点树的并发编辑需要 调用方同步。

性能路径

UTF-8 XML 1.0 使用已有的 tdewolff/parse/v2/xml lexer 直接构建 etree 树, 不调用 etree 的解析器,也没有读取回退。同一文档内复用元素和属性名称,名称 只校验一次。XML 声明的单双引号、空白、standalone 以及 CRLF、制表符和属性 换行均使用同一条读取路径。

属性值从原始输入读取,避免 lexer 原地替换属性空白影响结果。按 XML 1.0 §2.11、§3.3.3 归一化:字面 CR/CRLF 转换为 LF,属性中的字面制表符和换行转换 为空格,CRLF 只产生一个空格;字符引用产生的 CR、LF 和制表符按原值保留。 注释和处理指令中的字面换行同样归一化。注意 encoding/xml 本身没有完整实现 这些规则,对照测试会补齐这部分归一化,并使用独立 XML 解析器复核。

读取范围是 OFD XML 所需的元素、属性、文本、预定义实体和数字字符引用,并保留 注释和处理指令。CDATA 内容作为文本读取,其中的 & 等内容保持字面值, 不作为实体再次解码。DOCTYPE、自定义实体及非 UTF-8 编码返回错误。 节点树只负责 XML 读取和编辑,不进行 OFD 模型或 XSD 校验;GB/T 33190—2016 §7.1 的 OFD 命名空间及各类节点结构由上层模型、校验器和业务操作维护。

写回复用 Writer 的缓冲区、转义和数值输出能力,直接写前缀和本地名,避免拼接 临时名称。标准 ofd 前缀的 Marshal 路径递归复用声明;扩展前缀及归一化写回 按源树解析命名空间。大型输出直接移交超出池容量上限的缓冲区。

已有 MarshalDocument 和 WriteElement 用于将 OFD 元素转换为 ofd: 前缀的 写入场景,归一化时按元素作用域补齐声明。对于 ofd 已绑定外部 URI 的非规范 输入,保留该绑定及当前 OFD 元素的原名称,避免改变扩展元素、属性或 QName 值 的含义;子作用域重新正确声明 ofd 后可继续归一化。读取后编辑优先使用 Parse / Marshal。

验证

go test ./internal/ofdxml -count=1
go test ./internal/ofdxml -run '^$' -bench 'BenchmarkXML' -benchmem
go test ./internal/ofdxml -run '^$' -fuzz FuzzParseMatchesEtree -fuzztime=10s

BenchmarkXMLEdit 比较包含中文、实体和属性的页面 XML 在读取、修改一个对象 ID、 写回整个文档时的耗时和分配,同时覆盖 CRLF 格式化、属性换行及不同声明写法; BenchmarkXMLMarshal 单独比较树写回成本。两者使用内存数据,不包含 ZIP 解压 或文件读写。

Documentation

Overview

Package ofdxml 提供 OFD XML 顺序写入及读取、修改、写回支持。

Index

Constants

View Source
const Namespace = spec.Namespace

Namespace 是 OFD 命名空间 URI。

Variables

This section is empty.

Functions

func AppendFloat

func AppendFloat(dst []byte, value float64) []byte

AppendFloat 追加不使用科学计数法的 OFD 数值,四舍五入到四位小数, 去除末尾多余的零并归一化负零。非有限值按 creator 的既有约定写为零。

func Marshal

func Marshal(doc *etree.Document) ([]byte, error)

Marshal 写出修改后的 XML 树,保留原有元素名、命名空间声明和节点顺序。 不缩进、不裁剪文本,不修改输入树;输出字节独立于树与写入器缓冲区。 CDATA 和普通文本统一转义写出。 XML 声明统一为 UTF-8。与 MarshalDocument 不同,此函数不统一 OFD 前缀, 不需要逐节点查找命名空间,适合读取后修改的快速写回。

func MarshalDocument

func MarshalDocument(doc *etree.Document) ([]byte, error)

MarshalDocument 写出已解析的 XML 树,保留扩展命名空间及节点顺序。 OFD 元素按 GB/T 33190—2016 §7.1 使用 ofd 前缀,扩展元素使用原名称。 对 ofd 已绑定外部命名空间的非规范输入,保留该作用域内 OFD 元素的原名称, 避免改变扩展元素、属性或 QName 值的命名空间含义。 此函数不修改输入树;返回的字节独立于写入器缓冲区。

func Parse

func Parse(data []byte) (*etree.Document, error)

Parse 读取 OFD 包中的 UTF-8 XML 1.0 文档,返回可用 etree API 修改的树。 直接通过 lexer 构树,不调用 etree 的解析器。保留文本空白、扩展命名空间、 注释和处理指令;CDATA 作为普通文本读取。按 XML 1.0 归一化字面换行和属性空白, 保留字符引用值。 支持预定义实体和数字引用,不接受 DOCTYPE 或自定义实体。 树不依赖输入切片的生命周期。跨文档移动子树须由调用方补齐命名空间声明。

func Put

func Put(w *Writer)

Put 将不再使用的 Writer 归还池中以复用缓冲区。归还后不得再访问 Bytes 返回的切片;Done 的返回值独立于写入器,可安全使用。

func WriteElement

func WriteElement(w *Writer, element *etree.Element) error

WriteElement 将元素及其子节点追加到 w,适用于嵌入既有 XML 片段。 调用方应在元素上补齐不能从输出父节点继承的命名空间声明。

Types

type Writer

type Writer struct {
	// contains filtered or unexported fields
}

Writer 将 OFD XML 顺序写入内存或分块写入目标,自动添加 ofd 前缀和根命名空间声明。 OFD 元素名必须是合法的 XML 本地名,扩展元素可通过 StartQualified 写入。 属性必须在内容之前写入,内容之后的属性调用会被忽略。 一个 Writer 不能被多个 goroutine 同时使用。

func New

func New() *Writer

New 从复用池获取 OFD XML 写入器。用完后应调用 Put 归还缓冲区; 若需要长期持有输出,使用 Done。

func (*Writer) Attr

func (w *Writer) Attr(name, value string)

Attr 是 Attribute 的简写,OFD 普通属性不添加前缀。

func (*Writer) AttrBox

func (w *Writer) AttrBox(name string, x, y, width, height float64)

AttrBox 写入由空格分隔的四个 OFD 矩形数值。

func (*Writer) AttrFloat

func (w *Writer) AttrFloat(name string, value float64)

AttrFloat 写入最多保留四位小数的 OFD 数值属性。

func (*Writer) AttrFloatList

func (w *Writer) AttrFloatList(name string, values []float64)

AttrFloatList 写入由空格分隔的 OFD 数值列表。

func (*Writer) AttrInt

func (w *Writer) AttrInt(name string, value int)

AttrInt 写入十进制有符号整数属性,不生成临时字符串。

func (*Writer) AttrIntList

func (w *Writer) AttrIntList(name string, values []int)

AttrIntList 写入由空格分隔的十进制整数列表。

func (*Writer) AttrUint

func (w *Writer) AttrUint(name string, value uint64)

AttrUint 写入十进制无符号整数属性,不生成临时字符串。

func (*Writer) Attribute

func (w *Writer) Attribute(name, value string)

Attribute 在当前尚未闭合的开始标签上写入属性。

func (*Writer) Bytes

func (w *Writer) Bytes() []byte

Bytes 关闭剩余元素并直接返回缓冲区,不复制字节。 返回值只在下一次写入或 Reset 前有效;需要长期保留时应自行复制。 仅适用于内存模式,分块模式使用 Finish。

func (*Writer) Directive

func (w *Writer) Directive(value string)

Directive 写入已校验的 XML 指令内容,例如 DOCTYPE 定义。 value 不含外围的 <! 和 >;调用方负责保证内容符合 XML 语法。

func (*Writer) Done

func (w *Writer) Done() []byte

Done 关闭剩余元素并把 Writer 归还池中,调用后不得再使用该 Writer。 小缓冲区复制输出后复用,超过池容量上限的缓冲区直接移交给调用方。 返回的切片可安全长期持有;仅需立即写入时,改用 Bytes 避免复制。

func (*Writer) Element

func (w *Writer) Element(name, value string)

Element 写入只包含文本的 OFD 元素。

func (*Writer) ElementBox

func (w *Writer) ElementBox(name string, x, y, width, height float64)

ElementBox 写入只包含矩形数值的元素。

func (*Writer) ElementFloat

func (w *Writer) ElementFloat(name string, value float64)

ElementFloat 写入只包含 OFD 数值的元素。

func (*Writer) ElementFloatList

func (w *Writer) ElementFloatList(name string, values []float64)

ElementFloatList 写入只包含 OFD 数值列表的元素。

func (*Writer) ElementInt

func (w *Writer) ElementInt(name string, value int)

ElementInt 写入只包含有符号整数的 OFD 元素。

func (*Writer) ElementIntList

func (w *Writer) ElementIntList(name string, values []int)

ElementIntList 写入只包含整数列表的元素。

func (*Writer) ElementUint

func (w *Writer) ElementUint(name string, value uint64)

ElementUint 写入只包含无符号整数的 OFD 元素。

func (*Writer) End

func (w *Writer) End()

End 是 EndElement 的简写。

func (*Writer) EndElement

func (w *Writer) EndElement()

EndElement 关闭最近打开的元素,无内容的元素输出为自闭合标签。

func (*Writer) Err

func (w *Writer) Err() error

Err 返回分块输出遇到的第一个错误。错误后不再调用底层写入器。

func (*Writer) Finish

func (w *Writer) Finish() error

Finish 关闭剩余元素并写出最后一块,返回第一次写入错误或 io.ErrShortWrite。

func (*Writer) Raw

func (w *Writer) Raw(data []byte)

Raw 原样追加已校验的 XML 片段,不进行转义。 调用方必须按当前命名空间上下文校验片段,保证标签配对,且不含 XML 声明和 DOCTYPE。

func (*Writer) Reset

func (w *Writer) Reset()

Reset 清空文档并重新写入 XML 声明,复用已分配的缓冲区。

func (*Writer) ResetTo

func (w *Writer) ResetTo(dst io.Writer)

ResetTo 开始分块输出文档;写入过程中自动冲刷缓冲区,以 Finish 收尾并获取错误。 dst 为 nil 时等同于 Reset。分块模式不使用 Bytes、Done 或 WriteTo 获取完整文档。

func (*Writer) Start

func (w *Writer) Start(name string)

Start 是 StartElement 的简写。

func (*Writer) StartElement

func (w *Writer) StartElement(name string)

StartElement 开始一个 OFD 元素,根元素自动声明 OFD 命名空间。

func (*Writer) StartQualified

func (w *Writer) StartQualified(name string)

StartQualified 开始一个使用指定 XML 名称的扩展元素,不自动添加前缀。 name 必须是合法的 XML 名称,例如 ext:Value 或 Value;调用方负责用 Attr 声明所需的命名空间。嵌套的 OFD 元素仍可通过 Start 写入。

func (*Writer) Text

func (w *Writer) Text(value string)

Text 写入自动转义的文本,并将非法 XML 字符替换为 U+FFFD。

func (*Writer) TextBox

func (w *Writer) TextBox(x, y, width, height float64)

TextBox 写入由空格分隔的四个 OFD 矩形数值文本。

func (*Writer) TextFloat

func (w *Writer) TextFloat(value float64)

TextFloat 写入最多保留四位小数的 OFD 数值文本。

func (*Writer) TextFloatList

func (w *Writer) TextFloatList(values []float64)

TextFloatList 写入由空格分隔的 OFD 数值列表文本。

func (*Writer) TextInt

func (w *Writer) TextInt(value int)

TextInt 写入十进制有符号整数文本,不生成临时字符串。

func (*Writer) TextIntList

func (w *Writer) TextIntList(values []int)

TextIntList 写入由空格分隔的十进制整数列表文本。

func (*Writer) TextUint

func (w *Writer) TextUint(value uint64)

TextUint 写入十进制无符号整数文本,不生成临时字符串。

func (*Writer) WriteTo

func (w *Writer) WriteTo(dst io.Writer) (int64, error)

WriteTo 将已缓存在内存中的完整 XML 写入 dst,并报告底层写入错误或短写入。 需要在生成过程中控制缓冲区大小时,使用 ResetTo 和 Finish。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL