描述符系统
@office-open/core 的描述符系统提供 TypeScript Options 对象与 XML 之间的声明式双向映射。同一个描述符同时驱动序列化(Options → XML 字符串)和解析(Element → Options)。
描述符类型
每个描述符都是 CustomDescriptor<T>,手写 stringify() 和 parse() 方法(无声明式属性/子元素构建器):
import type { CustomDescriptor } from "@office-open/core";
const myDesc: CustomDescriptor<MyOptions> = {
kind: "custom",
stringify(value, ctx) {
return `<w:my val="${value.name}"/>`;
},
parse(el, ctx) {
return { name: el.attributes?.["w:val"] } as MyOptions;
},
};
高级用法: 当描述符的序列化输入类型与解析输出不同时(例如累加器式输入 vs. 结构化解析结果),需显式声明两者:
CustomDescriptor<TInput, Ctx, TOutput>。TOutput默认为TInput,因此常见的单参数形式CustomDescriptor<T>等价于CustomDescriptor<T, WriteContext, T>。
运行时函数
stringify()
将 Options 对象序列化为 XML 字符串:
import { stringify } from "@office-open/core";
const xml = stringify(myDesc, { name: "x" }, ctx);
// <w:my val="x"/>
当可选元素应被省略时返回 undefined。
parse()
将 XML Element 解析为 Options 对象:
import { parse } from "@office-open/core";
const opts = parse(myDesc, element, ctx);
上下文
WriteContext
序列化过程中传递的上下文对象:
interface WriteContext {
addRelationship(type: string, target: string, mode?: string): string;
addMedia(data: Uint8Array, type: string): string;
}
ReadContext
解析过程中传递的上下文对象:
interface ReadContext {
resolveRelationship(rId: string): string | undefined;
getPart(path: string): XmlElement | undefined;
getRaw(path: string): Uint8Array | undefined;
}
双向一致性
同一个描述符同时驱动序列化和解析,无需中间表示:
// 序列化
const xml = stringify(myDesc, { bold: true, size: 24 }, ctx);
// 解析
const parsed = parse(myDesc, element, ctx);
序列化过程直接生成 XML 字符串,不创建中间对象树,以减少内存分配。
何时直接使用
通常不需要直接调用 stringify() 和 parse()。各格式包的顶层函数会自动处理:
generateDocument()/generatePresentation()/generateWorkbook()— 内部调用 stringifyparseDocument()/parsePresentation()/parseWorkbook()— 内部调用 parse
在以下场景直接使用描述符运行时:
- 构建自定义 OOXML 部件的描述符
- 调试序列化/解析结果
- 实现格式包的部件模块
XSD 值映射
当 XSD 类型使用缩写时(例如 ST_TextAlignType 用 "ctr" 表示 center),双向映射定义在 @office-open/core(util/mappings.ts)中。每个映射通过 bidi() 一次性构建,提供 .to()(用户值 → XSD 值)和 .from()(XSD 值 → 用户值),同一个映射同时服务于序列化和解析:
import { xsdTextAlign } from "@office-open/core";
// 序列化(Options → XML)
attrs.push(`algn="${xsdTextAlign.to(options.alignment)}"`); // "center" → "ctr"
// 解析(XML → Options)
result.alignment = xsdTextAlign.from(String(el.attributes["algn"])); // "ctr" → "center"
当 XSD 已使用完整英文单词时(例如 "start"、"center"),无需映射——值直接原样写入和读取。
命名约定
| 约定 | 示例 |
|---|---|
描述符名称:<part>Desc | spacingDesc、settingsDesc、slideDesc |
Options 接口:<Part>Options | WorkbookOptions、DocumentOptions |
辅助函数:stringify*() / parse*() | stringifyWorksheet()、parseWorkbook() |