ADR-0028:严格 Markdown 模板
- 状态:采纳。
- 日期:2026-10-16。
- 关联:能力缺口表、Markdown API、ADR-0025。
问题
XML 模板已将结构从 Java 中分离。简单报告仍需要大量标签;调用方希望直接看出标题、段落与列表结构。引入通用 Markdown/HTML 渲染器会扩大依赖与协议范围,并可能丢失现有语义、字体策略和输出诊断。
决策
在既有 export4j-adapter-template 新增 MarkdownTemplate,单向依赖模型及 JDK。编译返回原有 DocumentTemplate,数据展开、布局及后端保持原职责。该子集不增加依赖。
采用明确拒绝未知语义的严格子集:顶格 ATX 标题、空行段落、软换行、单行一级无序项、非嵌套星号强调、ASCII 点路径变量、显式资源图像。普通段落和列表沿用配置的 ParagraphFormat,标题沿用 Heading 默认格式;强调只选择真实字体角色。编译器既不扫描系统字体,也不合成粗斜字形。
图片采用 ,资源和 point 尺寸由 Java Builder 白名单登记。仅正文允许图像,alt 支持文字与变量。URL、路径、动态资源名、图片标题及模板内尺寸拒绝。没有任何外联、include、脚本、代码执行或文件读取入口。
没有宽松模式。HTML、实体、链接、代码、表格、引用、有序/任务/嵌套列表、Setext 标题、硬换行、下划线强调和删除线等明确拒绝。条目后无空行的普通行具有列表续行歧义,因此拒绝。保留标点有显式转义集合,不能通过转义美元符或花括号绕过表达式校验。数据内容只插入一次,不重新解析为 Markdown 或模板。
不扩展 Markdown 指令系统;条件、循环、动态表格行、字段和分页继续使用 XML 或 Java API。由此避免为两种文本入口复制绑定行为、循环目标规则或执行语言。
预算与来源
源预算分别限制 UTF-16 长度、物理行数、块数和实际内联内容数,段落图像另遵守模型的 1,024 上限。解析使用有界线性扫描,不依赖递归正则或递归语法栈。借用 Reader 最多读取输入限额加 1 个 UTF-16 单元,始终保留调用方所有权。编译与绑定均传播同步执行上下文;模型、模板和布局仍驻留内存。
MarkdownTemplateException 与既有 XML 专用 TemplateException 分离。它提供稳定错误码、一基行列和零基 UTF-16 offset,位置指向未归一化源码;CRLF、补充平面字符及转义不改变原始诊断坐标。消息不回显源文本、值或资源路径,不提供部分结果。
绑定保持既有 BindingException 和预算,不新增 Markdown 行列映射。绑定后的模型校验仍可能抛出原有 IllegalArgumentException,例如图像 alt 超长或含控制字符。图像位置和文字运行由现有语义模型重新计算,不能用编译前索引定位展开后的正文。
影响
简单报告可以用更接近成品结构的模板编写;复杂需求仍通过 XML 或 Java 表达。严格边界可能要求为普通标点加转义,但不会把不支持的语义静默降成文字。后续扩展须先定义模型映射、拒绝规则、工作预算和独立输出验收,不能将该子集标记为完整 Markdown/HTML 支持。
源码和行为测试采用 Apache-2.0,没有新增第三方运行依赖、字体或图片素材。该入口需纳入现有模块构建、本地 bundle、隔离调用方及新输出页面的独立验证。