如何在 XSD Schema 中标记和管理元素、属性及枚举值的弃用?
可以用 xs:annotation/xs:appinfo 保存结构化的弃用信息,用 xs:documentation 写迁移说明,再通过 XSLT 或 Schematron 检查实际使用情况。这种做法适用于元素、属性和枚举值,无需改变 XSD 的标准语法。
XSD 提供了 xs:schema/@version 属性,但没有规定版本号的格式、比较方式或兼容性规则。弃用版本、计划移除版本和相应的告警行为,仍需由项目自行约定。
弃用标记与校验约束有什么区别?
XSD 1.0 和 XSD 1.1 都没有通用的 deprecated 标记,也没有标准化的“使用后给出弃用警告”机制。
弃用过渡期内,通常应保留原来的声明或枚举值,让旧文档继续通过 XSD 校验。自定义注解记录弃用状态,单独运行的检查规则报告使用情况。
到正式移除的版本时,再修改相应的结构约束。只把注解中的状态改成“已移除”,普通 XSD 校验器仍会接受这些内容。
在 XSD 中记录弃用信息
建议为生命周期元数据分配独立的命名空间,并统一字段含义。例如:
| 字段 | 项目约定的含义 |
|---|---|
dep:deprecated | 被注解的声明或枚举值已经弃用 |
since | 首次弃用的规范版本 |
removeIn | 计划从哪个规范版本开始不再接受 |
xs:documentation | 替代方案、迁移方法和其他说明 |
这些字段的弃用含义由项目自行约定,XSD 没有为它们定义内置的弃用语义。尚未确定移除版本时,可以省略 removeIn,避免写入尚未承诺的时间表。
以下示例假设规范当前版本为 2.4.0,部分内容自 2.3.0 起弃用,计划在 3.0.0 中移除。版本号和业务名称仅用于演示。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:o="urn:example:orders"
xmlns:dep="urn:example:schema-lifecycle"
targetNamespace="urn:example:orders"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
version="2.4.0">
<xs:simpleType name="StatusType">
<xs:restriction base="xs:string">
<xs:enumeration value="active"/>
<xs:enumeration value="legacy">
<xs:annotation>
<xs:documentation xml:lang="zh-CN">
此状态值已弃用,迁移方式见规范发布说明。
</xs:documentation>
<xs:appinfo>
<dep:deprecated since="2.3.0" removeIn="3.0.0"/>
</xs:appinfo>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:element name="order">
<xs:complexType>
<xs:sequence>
<xs:element name="code" type="xs:string" minOccurs="0"/>
<xs:element name="legacyCode"
type="xs:string"
minOccurs="0">
<xs:annotation>
<xs:documentation xml:lang="zh-CN">
请迁移到同一命名空间下的 code 元素。
</xs:documentation>
<xs:appinfo>
<dep:deprecated since="2.3.0" removeIn="3.0.0"/>
</xs:appinfo>
</xs:annotation>
</xs:element>
</xs:sequence>
<xs:attribute name="mode" type="xs:string"/>
<xs:attribute name="legacyMode" type="xs:string">
<xs:annotation>
<xs:documentation xml:lang="zh-CN">
请迁移到 mode 属性。
</xs:documentation>
<xs:appinfo>
<dep:deprecated since="2.3.0" removeIn="3.0.0"/>
</xs:appinfo>
</xs:annotation>
</xs:attribute>
<xs:attribute name="status" type="o:StatusType"/>
</xs:complexType>
</xs:element>
</xs:schema>
xs:element、xs:attribute 和 xs:enumeration 都允许包含 xs:annotation,可以采用同一套元数据结构。注解的位置必须符合各自的内容模型,示例中都放在声明内容的开头。
xs:documentation 供人阅读,程序应读取 xs:appinfo 中的明确字段,避免从说明文字中猜测版本号或弃用状态。
用 Schematron 检查 XML 中的使用情况
注解保存在 XSD 文件里,待校验的 XML 实例不会自动携带这些信息。要报告实例中的弃用用法,需要编写或生成对应的检查规则。
上面的示例可以配合以下独立的 Schematron 文件使用:
<?xml version="1.0" encoding="UTF-8"?>
<sch:schema
xmlns:sch="http://purl.oclc.org/dsdl/schematron"
queryBinding="xslt">
<sch:ns prefix="o" uri="urn:example:orders"/>
<sch:pattern id="deprecated-features">
<sch:rule context="o:order/o:legacyCode">
<sch:report test="true()" role="warning">
legacyCode 自 2.3.0 起弃用,计划于 3.0.0 移除;
请迁移到 code。
</sch:report>
</sch:rule>
<sch:rule context="o:order">
<sch:report test="@legacyMode" role="warning">
legacyMode 自 2.3.0 起弃用,计划于 3.0.0 移除;
请迁移到 mode。
</sch:report>
<sch:report test="@status = 'legacy'" role="warning">
status 的 legacy 值自 2.3.0 起弃用,
计划于 3.0.0 移除。
</sch:report>
</sch:rule>
</sch:pattern>
</sch:schema>
这里使用 sch:report,在条件成立时报告。role="warning" 标记严重程度,但是否显示为警告、是否影响构建退出状态,还要在所用处理器或外层脚本中配置,仅设置这个属性并不够。
示例中的元素属于 urn:example:orders,属性没有命名空间,因此规则分别使用 o:legacyCode、@legacyMode 和 @status。
部署时应执行两个步骤:
- 运行 XSD 校验,检查结构和数据类型。
- 运行 Schematron 校验,报告仍然合法的弃用用法。
即使把 Schematron 内容嵌入 xs:appinfo,也需要支持该约定的工具提取并执行。普通 XSD 校验器不会自动运行它。
用 XSLT 提取注解或生成规则
XSLT 可以读取 XSD 中的弃用元数据,生成弃用清单、迁移文档或 Schematron 规则。绑定 xs 和 dep 命名空间后,可以用以下 XPath 选择带弃用标记的节点:
//xs:*[
self::xs:element
or self::xs:attribute
or self::xs:enumeration
][xs:annotation/xs:appinfo/dep:deprecated]
再分别读取注解中的弃用版本和计划移除版本:
xs:annotation/xs:appinfo/dep:deprecated/@since
xs:annotation/xs:appinfo/dep:deprecated/@removeIn
提取 XSD 注解比较直接,自动生成实例检测规则则需要分析声明的使用位置。
例如,同名的局部元素可能出现在不同类型中,一个枚举类型也可能被多个元素和属性共用。对于大型规范,生成器必须处理 xs:include、xs:import、ref、类型引用及相关派生关系,不能只拿 @name 拼出一个 //名称 表达式。
如果暂时没有完整的 Schema 分析工具,可以先以 XSD 注解为元数据来源,人工维护少量 Schematron 规则,并在发布检查中核对两者是否一致。
怎样管理整份规范的版本?
可以用 xs:schema/@version 标识 Schema 文档的版本,同时建立发布规则:
- 规定版本格式,以及哪些修改属于兼容性变更。
- 为每次发布保存不可变的 XSD 文件、依赖文件和对应的检查规则。
- 如果规范由多个 XSD 组成,使用发布清单统一记录入口文件及各依赖的确切版本;入口文件的
version不会自动管理其他文件。 - 通过应用配置、目录解析机制或明确的实例版本字段,选择相应的规范版本。
是否修改 targetNamespace,应根据兼容性策略决定,无需每次发布都修改。命名空间的变化会改变元素、属性或类型的 QName。如果保留同一命名空间发布多个版本,就需要明确应用加载哪一套 Schema。
xsi:schemaLocation 提供的是 Schema 位置提示,处理器可以采用其他配置,因此不能仅靠它选择版本。
比较版本号时,不要使用普通字符串排序,也不要把 2.10 当作小数。若采用语义化版本,应使用对应的解析和比较规则。
到移除版本时还要做什么?
正式发布移除版本时,应同步删除或调整声明、枚举约束和相关引用,并更新检测规则与迁移说明。对于封闭的内容模型,已移除的用法通常会直接触发 XSD 校验错误;如果存在 xs:any 或 xs:anyAttribute 等通配符,还要检查它们是否仍允许旧内容通过。
旧版本的规范和规则应继续保留,让历史文档能够按原来的契约校验。规模较大的规范还可以为弃用元数据编写独立的校验规则,检查必填字段、版本格式,以及移除版本是否晚于弃用版本,减少人工维护造成的不一致。
备注:内容仅供参考。
