如何限制XML Schema通配符类型使其包含指定属性组?
XML Schema:为任意子元素强制添加通用属性组
问题描述
需要定义一组对象,每个对象可以是任意特定类型、拥有自身所需属性,但必须共同包含一个通用属性组。
无效的尝试方案
方案1:属性组应用于父元素
将通用属性组添加到<objects>父元素上,导致属性属于父元素而非每个子对象,不符合需求:
<xs:element name="objects"> <xs:complexType> <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <xs:attributeGroup ref="object-attributes"/> </xs:complexType> </xs:element>
方案2:为<xs:any>添加属性组
试图直接给<xs:any>通配符嵌套属性组,但XML Schema规范不允许<xs:any>包含注释以外的子元素,因此该写法无效:
<xs:element name="objects"> <xs:complexType> <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax"> <xs:attributeGroup ref="object-attributes"/> </xs:any> </xs:sequence> </xs:complexType> </xs:element>
可行解决方案
方案1:抽象基类型+替换组(XSD 1.0兼容)
通过定义抽象基类型封装通用属性组,再让所有具体元素类型扩展该基类型,最后通过替换组实现任意子元素的兼容:
- 定义通用属性组和抽象基类型
<!-- 通用属性组定义 --> <xs:attributeGroup name="object-attributes"> <xs:attribute name="id" type="xs:string" use="required"/> <xs:attribute name="type" type="xs:string" use="required"/> </xs:attributeGroup> <!-- 抽象基类型,包含通用属性组 --> <xs:complexType name="BaseObjectType" abstract="true"> <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <xs:attributeGroup ref="object-attributes"/> </xs:complexType>
- 定义具体元素类型(扩展抽象基类型)
<!-- 示例:用户对象类型 --> <xs:complexType name="UserObjectType"> <xs:complexContent> <xs:extension base="BaseObjectType"> <xs:sequence> <xs:element name="username" type="xs:string"/> <xs:element name="email" type="xs:string"/> </xs:sequence> <!-- 该类型特有的属性 --> <xs:attribute name="isActive" type="xs:boolean"/> </xs:extension> </xs:complexContent> </xs:complexType> <!-- 绑定到具体元素,加入替换组 --> <xs:element name="object" type="BaseObjectType" abstract="true"/> <xs:element name="user" type="UserObjectType" substitutionGroup="object"/> <xs:element name="product" type="ProductObjectType" substitutionGroup="object"/>
- 定义
<objects>容器元素
<xs:element name="objects"> <xs:complexType> <xs:sequence> <xs:element ref="object" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element>
这种方式下,<objects>中可以放入<user>、<product>等任意属于object替换组的元素,每个元素都会自动包含通用属性组。
方案2:XSD 1.1断言(灵活无预定义)
如果使用XSD 1.1,可以通过断言直接约束每个子元素必须包含通用属性组,无需预先定义所有元素类型:
<xs:element name="objects"> <xs:complexType> <xs:sequence> <xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax"/> </xs:sequence> <!-- 断言检查每个子元素都包含通用属性(根据实际属性调整) --> <xs:assert test="every $elem in * satisfies $elem/@id and $elem/@type"/> </xs:complexType> </xs:element>
该方式更灵活,但需要解析器支持XSD 1.1规范。
内容的提问来源于stack exchange,提问作者uspectaculum
相关产品推荐
相关产品推荐

