xs:union 的 membertypes 只能引用已声明的简单类型名或内联 xs:simpletype,禁止表达式、复杂类型、未声明别名、嵌套 union;校验按 membertypes 从左到右匹配首个成功类型,不回溯。

xs:union 的 memberTypes 里能写哪些东西
只能写已定义的简单类型名,或者用 xs:simpleType 内联定义——不能写表达式、不能写复杂类型、不能写未声明的别名。
常见错误是直接塞一个正则模式进去,比如 memberTypes="xs:string xs:integer" 看似合理,但若 xs:integer 没在当前 Schema 中显式引入(比如没通过 xmlns:xs="http://www.w3.org/2001/XMLSchema" 声明,或被覆盖了命名空间),解析器就报错:src-resolve: Cannot resolve the name 'xs:integer' to a(n) 'simpleType definition'。
- 必须确保所有类型名都已在作用域内声明,且命名空间前缀绑定正确
- 多个类型用空格分隔,不是逗号,也不是 XML 属性列表语法
- 如果要用自定义类型,得先用
xs:simpleType定义好再引用,不能边定义边用
为什么 xs:union 不支持嵌套 union 或递归引用
因为 XSD 1.0 规范明确禁止 xs:union 的 memberTypes 引用另一个 xs:union —— 解析器会拒绝,典型报错:cos-st-restricts: The type defined by union cannot be used as a memberType in another union。
这不是实现差异,是规范硬性限制。想模拟“多层联合”,只能平铺展开:把底层 union 的所有成员类型逐一拎出来,列在顶层 union 的 memberTypes 里。
- 例如:A = union of B and C,B = union of string/int,C = decimal → 那么 A 必须写成
memberTypes="xs:string xs:integer xs:decimal" - 试图写
memberTypes="my:B my:C"会失败,即使 my:B 和 my:C 本身是合法 union - XSD 1.1 放宽了部分限制,但主流工具链(如 Xerces、libxml2、.NET XmlSchemaSet)默认仍按 1.0 处理
用 xs:union 时,值校验到底怎么走
校验顺序是“从左到右尝试匹配第一个成功类型”,不回溯,也不取最精确匹配。这意味着顺序很重要,尤其当类型有包含关系时(比如 xs:string 和自定义的 pattern 类型)。
例如:一个 union 定义为 memberTypes="xs:string my:email",而 my:email 是基于 xs:string 加 pattern 限制的。此时输入 "foo@bar.com" 会先匹配 xs:string 成功,根本不会进 my:email 的 pattern 校验——结果就是非法邮箱也能过。
- 要把更具体的类型放在前面,比如
memberTypes="my:email xs:string" - union 本身不提供“联合语义”的值约束,它只是“任一匹配即通过”
- 没有机制让多个成员类型共同参与一次校验(比如既要满足 email 格式,又要长度
替代方案比死磕 xs:union 更实际的场景
当你发现要反复调整 memberTypes 顺序、要平铺嵌套 union、还要手动保证类型互斥时,大概率该换思路了。
真正需要“多种格式接受但语义一致”的字段(比如 ID 字段接受 UUID、数字 ID、短码),用 xs:string + 应用层解析更可控;需要强约束又有多态需求的,XSD 1.1 的 xs:assert 或直接切到 JSON Schema 更合适。
- XML 工具链对 union 的支持参差不齐:JAXB 可能忽略部分成员,Python xmlschema 库对空格分隔解析敏感
- 调试困难:校验失败时,多数解析器只报“not valid against union”,不告诉你卡在哪一个 memberType
- union 的 type derivation 规则复杂,和
xs:restriction/xs:extension混用极易出隐性冲突
union 是个窄口子工具,用对地方省事,用歪了反而把 schema 变成黑盒。真正难的是判断“这里到底需不需要 union”。










