如何在XSD中定义同名且属性/内容类型不同的TestField元素?
解决方案
问题分析
你的核心问题有两个:
- 未配置
<xs:element>的maxOccurs="unbounded",导致解析器不允许多个同名<TestField>元素。 <TestField>的内容类型随Name属性值变化(decimal/boolean/string),单一的simpleContent扩展无法满足多类型匹配需求,需要用XSD 1.1的条件类型赋值实现。
完整XSD代码(XSD 1.1版本)
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> <!-- 定义SomeApp根元素 --> <xs:element name="SomeApp"> <xs:complexType> <xs:sequence> <xs:element name="Org" type="xs:string"/> <xs:element name="Name" type="xs:string"/> <xs:element name="Version" type="xs:decimal"/> <xs:element name="Source" type="xs:integer"/> <xs:element name="UniversalID" type="xs:string"/> <!-- 允许多个TestField元素,设置maxOccurs="unbounded" --> <xs:element name="TestField" maxOccurs="unbounded"> <xs:complexType> <xs:simpleContent> <!-- 条件类型赋值:根据Name属性值匹配对应的内容类型 --> <xs:extension base="xs:anySimpleType"> <xs:attribute name="Name" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="Price"/> <xs:enumeration value="Level"/> <xs:enumeration value="new"/> <xs:enumeration value="Description"/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:assert test=" (@Name = 'Price' or @Name = 'Level') and . castable as xs:decimal or @Name = 'new' and . castable as xs:boolean or @Name = 'Description' and . castable as xs:string "/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
关键说明
- 允许多个TestField:通过给
<xs:element name="TestField">添加maxOccurs="unbounded",让解析器接受任意数量的同名元素。 - 条件类型匹配:
- 使用XSD 1.1的
<xs:assert>约束,根据Name属性的值验证内容是否符合对应类型:- 当
Name="Price"或Name="Level"时,内容必须可转换为xs:decimal; - 当
Name="new"时,内容必须可转换为xs:boolean; - 当
Name="Description"时,内容必须可转换为xs:string。
- 当
- 开头的
vc:minVersion="1.1"声明确保XSD处理器使用1.1版本解析,因为条件类型赋值是1.1新增特性。
- 使用XSD 1.1的
替代方案(XSD 1.0兼容)
如果无法使用XSD 1.1,可以将<TestField>的内容类型定义为xs:string,然后在业务逻辑中自行校验类型匹配:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="SomeApp"> <xs:complexType> <xs:sequence> <xs:element name="Org" type="xs:string"/> <xs:element name="Name" type="xs:string"/> <xs:element name="Version" type="xs:decimal"/> <xs:element name="Source" type="xs:integer"/> <xs:element name="UniversalID" type="xs:string"/> <xs:element name="TestField" maxOccurs="unbounded"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="Name" use="required"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:enumeration value="Price"/> <xs:enumeration value="Level"/> <xs:enumeration value="new"/> <xs:enumeration value="Description"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
这种方式能通过XSD 1.0验证,但无法在Schema层面强制内容类型与Name属性的对应关系,需要后续业务代码补充校验。
内容的提问来源于stack exchange,提问作者Uinta_Ranger
相关产品推荐
相关产品推荐

