编写XSD断言:确保<instruction>满足stroke子元素或祖先含stroke的XOR约束
解决方案:XSD 1.1断言实现的异或约束
核心逻辑
每个<instruction>必须满足严格异或:要么自身包含<stroke>子元素,要么任意层级的祖先元素(包括根<program>)包含<stroke>,两者不能同时满足,也不能都不满足。
正确的XSD断言写法
在<instruction>的complexType定义中添加断言,注意必须使用XSD 1.1(XSD 1.0不支持断言):
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> <xs:element name="program"> <xs:complexType> <xs:sequence> <xs:element name="stroke" type="xs:string" minOccurs="0"/> <xs:element name="instruction" type="instructionType" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:complexType name="instructionType"> <xs:sequence> <xs:element name="stroke" type="xs:string" minOccurs="0"/> <xs:element name="instruction" type="instructionType" minOccurs="0" maxOccurs="unbounded"/> <!-- 可添加其他子元素定义 --> </xs:sequence> <!-- 核心断言 --> <xs:assert test="(exists(stroke) xor exists(ancestor::*[exists(stroke)]))"/> </xs:complexType> </xs:schema>
断言表达式详解
exists(stroke):检查当前<instruction>是否直接包含<stroke>子元素ancestor::*[exists(stroke)]:匹配所有祖先元素(从父元素到根<program>)中包含<stroke>的节点,用ancestor::*而非ancestor::instruction,确保能检测到根元素<program>中的<stroke>xor:严格实现异或逻辑,确保两个条件恰好满足一个
常见问题修复
- 根下
<instruction>检测异常:之前的错误大概率是用了ancestor::instruction,导致忽略了根<program>,换成ancestor::*即可解决。 - 祖先元素检测失效:确保XPath中是
exists(ancestor::*[exists(stroke)]),而非错误的路径(比如遗漏exists(stroke)判断祖先是否包含子元素)。
验证示例
有效XML
<program> <stroke>root-level stroke</stroke> <instruction> <!-- 自身无stroke,但祖先program有,符合约束 --> <instruction> <stroke>child stroke</stroke> <!-- 自身有stroke,符合约束 --> </instruction> </instruction> </program>
无效XML(会触发断言失败)
<program> <instruction> <!-- 自身无stroke,祖先program也无stroke,违反约束 --> <instruction> <!-- 自身无stroke,父instruction也无,祖先program也无,违反约束 --> </instruction> </instruction> </program>
注意事项
- 必须使用支持XSD 1.1的处理器(比如Saxon-HE 9.5+、Apache Xerces2 2.12+),否则断言会被忽略。
- 若需求是“或”而非严格异或(允许自身和祖先同时有stroke),只需把
xor换成or,并添加not(not(exists(stroke)) and not(exists(ancestor::*[exists(stroke)])))确保至少满足一个条件。
内容的提问来源于stack exchange,提问作者bartneck
相关产品推荐
相关产品推荐

