CORE

描述符系统

声明式 XML 映射 — 描述符类型、构建器 API 和运行时函数

@office-open/core 的描述符系统提供 TypeScript Options 对象与 XML 之间的声明式双向映射。同一个描述符同时驱动序列化(Options → XML 字符串)和解析(Element → Options)。

描述符类型

ElementDescriptor

声明式属性/子元素映射,通过 DescriptorBuilder 构建:

import { element, stringify, parse } from "@office-open/core";

const spacingDesc = element<SpacingOptions>("w:spacing")
  .attr("before", "w:before")
  .attr("after", "w:after")
  .build();

CustomDescriptor

用于复杂逻辑的自定义描述符,提供 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 Partial<MyOptions>;
  },
};

DescriptorBuilder API

element() 函数创建一个流式构建器,支持链式调用:

const desc = element<MyOptions>("w:p")
  .attr("alignment", "w:val")
  .child("spacing", "w:spacing", spacingDesc)
  .children("runs", "w:r", runDesc)
  .text("text")
  .build();

构建器方法

方法说明
.attr(key, xmlName, opts?)属性映射
.child(key, tag, desc)单个子元素映射
.children(key, tag, desc)重复子元素映射(数组)
.union(key, variants)多选一子元素映射
.text(key)文本内容映射
.custom(spec)自定义内容处理器
.build()构建不可变的描述符

attr 选项

.attr("size", "w:sz", {
  default: 10,                              // 等于默认值时省略
  encode: (v: number) => String(v * 2),     // JS 值 → XML 字符串
  decode: (raw: string) => Number(raw) / 2, // XML 字符串 → JS 值
})

运行时函数

stringify()

将 Options 对象序列化为 XML 字符串:

import { stringify } from "@office-open/core";

const xml = stringify(spacingDesc, { before: 240, after: 120 }, ctx);
// <w:spacing w:before="240" w:after="120"/>

当可选元素应被省略时返回 undefined

parse()

将 XML Element 解析为 Options 对象:

import { parse } from "@office-open/core";

const opts = parse(spacingDesc, element, ctx);
// { before: 240, after: 120 }

上下文

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;
}

双向一致性

同一个描述符同时驱动序列化和解析,无需中间表示:

import { stringify, parse, element } from "@office-open/core";

const desc = element<FontOptions>("w:rPr")
  .attr("bold", "w:b", { encode: boolEncode, decode: boolDecode })
  .attr("size", "w:sz")
  .build();

// 序列化
const xml = stringify(desc, { bold: true, size: 24 }, ctx);

// 解析
const parsed = parse(desc, element, ctx);
// parsed.bold === true, parsed.size === 24

序列化过程直接生成 XML 字符串,不创建中间对象树,以减少内存分配。

何时直接使用

通常不需要直接调用 stringify()parse()。各格式包的顶层函数会自动处理:

  • generateDocument() / generatePresentation() / generateWorkbook() — 内部调用 stringify
  • parseDocument() / parsePresentation() / parseWorkbook() — 内部调用 parse

在以下场景直接使用描述符运行时:

  • 构建自定义 OOXML 部件的描述符
  • 调试序列化/解析结果
  • 实现格式包的部件模块

OOXML 辅助函数

描述符内部使用的编码/解码辅助函数:

函数说明
boolEncode将布尔值编码为 XML 属性值
boolDecode将 XML 属性值解码为布尔值
enumEncode将枚举值编码为 XML 字符串
enumDecode将 XML 字符串解码为枚举值
Copyright © 2026