摘要
- RFC 3076 并不直接规范化一份未触碰的文件。字节流必须先由 XML 处理器转换成 XPath 节点集,换行、属性、CDATA 与已解析实体在此之前就已发生变化。
- 相同的规范化字节,是对特定数据模型、注释选项和算法的精确回执;它不能还原原始 XML,也不会自动保留 DTD、基础 URI 或应用语义。
稳定输出从链条中段开始
2001 年 3 月,RFC 3076 与 W3C 的 Canonical XML Version 1.0 Recommendation 面对一个真实难题:XML 允许多种物理写法表达许多应用眼中的同一信息。属性顺序可以不同,字符编码可以不同,空元素可用短写或成对标签,字符与实体引用也可以换成对应内容。数字签名或完整性比较若直接面对这些表面差异,就难以得到一致的摘要。
规范化方法把输出固定为 UTF-8,删除 XML 声明和文档类型声明,把空元素改写为起止标签,统一属性引号,按规定转义字符,移除多余命名空间声明,并按字典序排列命名空间与属性。是否保留注释是明确参数。一个良构的规范化结果再次经过同一方法时不会改变。
但规范的正式对象是 XPath 节点集。输入若是 XML 字节流,系统必须先解析,再得到节点。规范化器接手时,原文件已经被另一套规则加工过。
解析器已经决定了什么可以被排列
XML 处理器先统一换行与属性值,把 CDATA 段替换成字符内容,解析字符引用和已解析实体,还可能根据 DTD 加入默认属性。命名空间成为节点,相邻字符被合并成文本节点。这些不是最终序列化时才做的排版,而是构造规范化对象的前置步骤。
因此,两份源文件可以正确地汇聚到同一输出。一份直接写字符,另一份写数字引用;一份调用内部实体,另一份写实体替换文本;一份用空元素短写,另一份用完整起止标签。只要解析后的信息符合规则,它们就可以产生相同字节。这正是 Canonical XML 的价值。
代价是输出不再可逆。原始编码被 UTF-8 取代;XML 声明和 DTD 消失;实体与 CDATA 的边界不复存在;属性原顺序改为规定顺序。规范化结果能够回答“这个节点模型的确定性表示是什么”,却不能回答“最初是哪串字节、哪些外部资源和哪套解析策略构造了它”。
完整回执必须从规范化之前开始:收到的字节及哈希、获取 URI 与时间、声明编码、解析器版本与设置、是否验证、外部子集和实体策略、实际取回的每份依赖、有效基础 URI,以及解析器加入的默认属性。只保存最终哈希无法事后恢复这些事实。
字节相同,运行行为仍可能丢失
RFC 3076 的限制章节明确列出 XPath 模型无法保存的内容:基础 URI,特别是外部已解析实体替换文本的来源位置;notation 与外部未解析实体;以及 DTD 中声明的属性类型。
基础 URI 的问题最直观。外部实体可能包含相对 URI。解析器把实体内容嵌入主文档后,若没有保留原实体的位置,这串相对字符可能按新的基础位置解析。规范化字节仍然稳定,后续应用打开的资源却可能不同。RFC 建议在需要时正确使用 xml:base,或在规范化前把相对 URI 解析成绝对 URI。
DTD 还形成另一种不对称。默认属性可能已被加入节点集,因此会出现在输出中;但提供这个默认值的文档类型声明已经被删除。与此同时,ID、IDREF、枚举、NOTATION 等类型约束不会随规范化文件继续存在。后来的解析器看见字符值,却未必知道原先的类型契约。
notation 与未解析实体也可能把外部非 XML 数据绑定给应用。XPath 模型并不携带所有绑定。RFC 称这些情况“不常见”,并不等于依赖它们的系统可以放弃来源证据。
节点集不是默认包含一切的子树
对文档子集做规范化时,XPath 提供的是独立节点组成的集合。选中元素不等于自动选中它的属性、文字与后代。父节点在集合中,也不会让被排除的子节点出现在输出里。反过来,被省略的祖先仍可能贡献命名空间环境或可继承的 XML 属性。
RFC 因而把保持成员完整语义的责任交给节点集创建者。子集的规范化结果甚至可能不是良构 XML。它仍是算法定义的字节流,却不能仅凭“canonical”一词推断完整、自足或适合再次解析。
这与 RFC 3075 的问题不同。RFC 3075 关注签名究竟覆盖哪些 Reference 与变换结果;RFC 3076 关注签名或比较以前,解析器究竟构造了什么对象。即使签名验证完全正确,也会继承节点集的来源边界。
“规范化”不是所有语义的同义词
RFC 3076 没有把规范化形式定义成所有逻辑等价的“当且仅当”条件。某个应用可能忽略特定空白,也可能把 black 与 rgb(0,0,0) 视为同一颜色;别的 W3C 规范也可能增加等价规则。因此,两份规范化输出不同,仍可能在某个应用里含义相同。
方法也不执行通用的 Unicode 字符模型规范化。它刻意保留输入中的命名空间前缀,因为盲目改名可能破坏属性值或文本中嵌入的 XPath、QName 式字符串。RFC 提供的是可执行、可测试的有限比较,不是普遍语义引擎。
后来的修订再次暴露上下文边界
W3C 在 2006 年记录了 C14N 1.0 的子集问题:把相对 xml:base 简单复制到选中后代,可能丢失祖先路径,因而改变有效 URI。后来出现的 xml:id 也表明,标识符不应像普通 XML 命名空间属性那样被继承。
2008 年成为 Recommendation 的 Canonical XML 1.1 对此作出修订:不继承 xml:id,并对 xml:base 做专门路径合成。这是规范演进的证据,不是每个 C14N 1.0 部署都失败的证据。Exclusive XML Canonicalization 解决的是片段移入新上下文时的命名空间问题;RFC 3275 把 C14N 1.0 纳入 XML Signature 的必备方法。它们都没有把规范化哈希扩张为原文件、外部输入可信度或应用授权的证明。
历史记录应保存哪条链
应保存收到的字节、哈希与获取位置;媒体类型与编码;解析器身份、版本和设置;验证方式;实际使用的 DTD、目录、外部子集与实体;基础 URI;命名空间处理与默认属性;XPath 选择及得到的节点集;注释选项;规范化方法与版本;最终输出哈希。
随后还要记录比较或签名结果、应用自己的等价规则、采取的决定与可观察效果。Lu Heng 后来关于 running code 与现实层次的论述可作为披露后的分析镜头:能够重复生成的字节,比一个抽象标签更强;但执行层回执不会吞并来源、权威、含义与结果层。
来源
- RFC Editor:RFC 3076
- RFC 3076:Canonical XML Version 1.0
- IETF Datatracker:RFC 3076
- W3C Canonical XML Version 1.0 Recommendation
- XPath Version 1.0
- XML 1.0
- Known Issues with Canonical XML 1.0
- Canonical XML Version 1.1
- Exclusive XML Canonicalization Version 1.0
- RFC 3275:XML-Signature Syntax and Processing
- Lu Heng:《Running-Code Primacy》
- Lu Heng:《On Reality Layers, Symbolic Power, and Why Clarity Feels So Hostile》
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
