跳到正文

ADR-0038:XML 主题快照与静态样式名称 ​

背景 ​

Java 编写入口已经可以集中复用完整正文、六级标题、便利表格和命名样式。XML 编译器仍需重复声明文字属性,且没有选择命名段落/行内完整值的语法。直接复用 Java Builder 的 setter 实现会改变 XML 原有正文与格格式独立配置的范围;扩大共用属性集合还会无意放开标题或字段的 style。

现有 XML 编译时构造完整模型原型,再由 DocumentTemplate 绑定数据。条件两支、循环原型、动态行及静态内表已在编译阶段遍历,适合一次解析静态样式名称,不需要运行期主题树、另一套绑定器或布局重写。

决策 ​

只增加公开配置 XmlTemplate.Builder.theme(DocumentTheme),同步保存不可变主题及其已解析正文/格格式。主题提供六级完整标题格式、完整表格式和两类命名映射;编译器 build 固定快照,编译后的模型原型不保存名称或待解析主题引用。

调用 theme 替换整组默认值,后续 bodyFormat 只影响顶层正文/列表,cellFormat 只影响表格格及内表格。二者保持旧独立范围,不互相重置,也不重设标题、表格式或命名值。主题的隐式格格式在传入时已经解析;后续 XML 正文变化不会再次派生它。

无主题时使用旧默认值,配置默认主题与旧语法的完整模型和输出应等价。现有页设置、资源白名单、源/绑定预算、执行上下文及借用 Reader 所有权保持。

p 与 span 的完整样式选择 ​

仅 p 和已有合法位置的 span 增加 style 属性。p 可位于顶层或原子块格;span 保留原有段落、标题、列表、行内格和 link 内的位置。heading、bullet、numbered、cell、table、rows、link、字段和根元素不接受 style。

p 没有名称时继续使用上下文格式:顶层为当前正文,格内从实际格派生零段间距。存在名称时查询主题的段落映射,完整替换基底,再应用现有 XML 属性。命名格式的缩进、间距、断行和分页策略完整保留,格内选择不自动清零间距。原子块格仍禁止 pageBreakBefore 和 keepWithNext;命名格式包含这些策略时继续由既有语义校验明确拒绝,不自动清除。

XML 显式 size 缺少 line-height 时,继续采用 size × 1.5;没有 size 时保留基底的固定行距。该旧规则与 Java 完整格式回调不同,不能为了同名 API 而修改。显式零间距、false keep-together 等值优先。

span 没有名称时保持旧黑色、所在段/格字号、默认角色、零基线偏移和无装饰。存在名称时从主题的完整 InlineStyle 起,再由 role、color、size、underline、strike 逐项覆盖。显式空 role、黑色和 false 装饰均有效;基线偏移没有 XML 覆盖属性,完整保留命名值并交由固定行框校验。

完整命名字号不会随父段变化,同级普通文字、图片和字段不接收 span 名称。仅显式 XML role 字面量执行旧标识符语法;主题中的完整角色名直接保留,例如连字符角色可由 Java 引擎注册。编译器不持有字体,未知角色、缺字和行框不足继续在既有布局入口失败或诊断。

span 使用独立属性白名单,不修改字段共用的原 INLINE_STYLE_ATTRIBUTES。不放开嵌套 span、字段主题、link 主题或新的块格节点。

标题、表格与原子拒绝 ​

标题取主题对应 1~6 级的完整格式,再由 XML 属性覆盖;未修改的整段保持及与下一块保持策略保留。默认主题的各级格式与旧 Heading.defaultFormat 相同。正文 setter 不影响标题。

静态 table 和动态 rows 从完整主题 TableFormat 起,仅以已有 row-split 属性覆盖 allowRowSplit。主题 padding 和块间距保留,不新增 XML padding 或 spacing 属性。内表重新取编译器主题表格式,不继承外表的局部 row-split。

主题开启拆行时,含块格的父表和任意内表仍执行旧编译拒绝;调用方需要在相应 table 上明确写 row-split="false"。不自动关闭拆行,不扩大原子内表能力。两层深度、完整网格、动态行纵向合并和块格重复表头的拒绝保持。

静态名称、诊断与预算 ​

名称由 DocumentTheme 查询验证,区分大小写,允许 [A-Za-z_][A-Za-z_0-9-]{0,63},不误用 XML 资源/角色较窄的语法。两类映射分别查找,不回退或跨图搜索。

style 包含 ${ 时立即报 INVALID_EXPRESSION;空白、非法或未知名称报 INVALID_VALUE。查询异常转成既有 TemplateException,只含 code 和元素的一基行列,不泄漏名称、正文或主题值,不新增异常类型或枚举值。

现有编译遍历验证 then/else、each、rows 和静态内表的全部名称,运行期未选分支和零次循环也不能绕过。绑定只复制已解析格式,继续执行数据替换、ID 重定位及字段/外链契约。

名称属性受 XML 输入总长度限制,主题映射受每类 128 项上限约束。源元素、深度、解码文字、绑定展开和同步取消/超时继续沿用既有预算与检查点,不引入全局缓存、远程资源或隐式 I/O。

验证与范围 ​

行为验证须覆盖默认主题兼容,独立正文/格 setter 及 theme 顺序,编译器/原型快照,命名完整段落和运行的属性覆盖,六级标题分页,根表/动态表/内表格式及拆行冲突。非法、未知、插值名称须在全部分支编译拒绝,保留叶位置与脱敏消息;其他节点的 style 仍按未知属性拒绝。

独立小样对两套主题下同一 XML 核对实际字号、颜色、行距、内边距、来源和全部新页,验证标准 DOCX 及静态 SVG 的既有子集。图文链接和最终字段另按交互边界验收,不能要求静态后端丢弃交互。公共签名同时验证隔离调用方;旧 XML、块格和字段/链接样例回归,不自动刷新视觉基线。

本批不新增模块、依赖或外部资源,不实现 CSS、XML 内样式定义、主题继承、动态名称、可编辑字段样式、表头专用主题或递归续排。GAP-04 仍为部分支持。