xs:unique未生效主因是selector未匹配到同级候选元素或field值为空;scope默认限于所在元素子树,跨范围需上移声明;xs:key要求字段必填非空,xs:unique则忽略缺失字段。

xs:unique 为什么没生效?检查 scope 和 XPath 范围
常见现象是 XML 文档里明显重复的值,但验证时没报错。根本原因通常是 xs:unique 的 selector 匹配不到目标元素,或 field 提取的值为空/重复前缀不一致。
-
selector必须指向一组**同级候选元素**(比如所有book),不能写成//book—— 绝对路径在多数处理器中不被支持,应使用相对路径如book -
field的 XPath 必须返回**原子值**;若写成@id但属性不存在,该元素会被静默忽略,不参与唯一性检查 - 作用域(scope)默认是
xs:unique所在元素的子树;如果想跨多个section检查全局唯一,得把xs:unique放到它们共同的父元素下
xs:unique 和 xs:key 的区别在哪?别混用场景
xs:key 要求每个 field 值**必须存在且非空**,而 xs:unique 允许字段缺失(对应元素直接被排除出检查集)。实际选型看业务约束:
- 要强制每个
product必须有sku且全局不重复 → 用xs:key - 只希望「提供了
email的用户」之间不重复,但允许部分用户没填 → 用xs:unique - 两者都支持复合键(多个
xs:field),但顺序敏感:<field xpath="first"></field><field xpath="last"></field>和反过来是两个不同约束
验证失败时只报“duplicate key”?定位具体哪一行
错误信息里通常只有 cvc-identity-constraint.4.1 这类编号,不指明位置。调试靠两步:
- 用支持详细报告的工具,比如
xmllint --schema schema.xsd doc.xml,比 JDK 自带 Xerces 更早暴露冲突值 - 临时把
xs:unique改成xs:key并加一个必填字段(如@dummy),触发更明确的缺失提示,反推原字段为何为空 - 注意命名空间:如果 XML 有默认命名空间,
selector中的元素名必须加前缀,且要在xs:unique所在的xs:schema中声明该前缀
性能隐患:大量元素 + 复杂 field 表达式
每个匹配 selector 的元素,都会执行全部 xs:field 的 XPath 求值。当文档含上万 item、且 field 是 ancestor::section/@name 这类向上遍历表达式时,验证可能卡住。
- 优先用直系属性或子元素:
@id或id/text(),避免 // 或 ancestor:: - 不要在
field里调用函数(如normalize-space(@id)),XSD 1.0 不支持,多数处理器直接忽略或报错 - 如果唯一性逻辑复杂(如忽略大小写、截断长度),别硬塞进 XSD —— 放到解析后代码里校验更可控










