是的,有两种方法。一种很简单(并且依赖于一些人类的直觉和文档),另一种更具表现力(但也不可避免地会更复杂一些。)
简单的方法是将名称 'table' 和 'row' 替换为指示我们正在谈论的表的名称:
<table-foo>
<row-foo>
<fooid>28</fooid>
<fooname>something</fooname>
</row-foo>
...
</table-foo>
<table-bar>
<row-bar>
<barid>19</barid>
<barcounter>93</barcounter>
</row-bar>
...
</table-bar>
XSD 验证(如使用 DTD 和 Relax NG 的验证)主要基于所使用的元素名称。如果您希望两种不同类型的行包含不同的内容,请给它们两个不同的名称。所以 foo-table 及其后代可以这样声明:
<xs:element name="table-foo" substitutionGroup="tns:table">
<xs:complexType>
<xs:sequence>
<xs:element ref="tns:row-foo"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="row-foo" substitutionGroup="tns:row">
<xs:complexType>
<xs:sequence>
<xs:element ref="tns:fooid"/>
<xs:element ref="tns:fooname"/>
</xs:sequence>
</xs:complexType>
同样适用于吧台和吧台。
然而,有时,我们绝对必须或真的想要捕捉到“row-foo”和“row-bar”都有一些重要的共同点这一事实。它们都是一些抽象本体中的“行”,这对我们来说可能很重要。在这种情况下,您可以使用抽象元素来捕捉规律。
例如,下面是表格、行和单元格的简单抽象:
<xs:element name="table"
abstract="true"
type="tns:table"/>
<xs:element name="row"
abstract="true"
type="tns:row"/>
<xs:element name="cell"
abstract="true"
type="xs:anySimpleType"/>
表和行的类型很简单:
<xs:complexType name="table">
<xs:sequence>
<xs:element ref="tns:row" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="row">
<xs:sequence>
<xs:element ref="tns:cell" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
现在,table-foo 等的声明变得稍微复杂一些,因为对于每个声明,我们必须建立与我们刚刚定义的抽象的关系。元素 foo-table 是表抽象的实例化,其类型是抽象表类型的限制:
<xs:element name="table-foo"
substitutionGroup="tns:table">
<xs:complexType>
<xs:complexContent>
<xs:restriction base="tns:table">
<xs:sequence>
<xs:element ref="tns:row-foo"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:element>
元素 foo-row 也是类似的:我们通过使用substitutionGroup 属性指定它是一个“行”,并且我们通过从抽象行类型的限制导出它的复杂类型:
<xs:element name="row-foo" substitutionGroup="tns:row">
<xs:complexType>
<xs:complexContent>
<xs:restriction base="tns:row">
<xs:sequence>
<xs:element ref="tns:fooid"/>
<xs:element ref="tns:fooname"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:element>
请注意,我们不允许在此处出现任意单元格,仅允许表 foo 中的行出现我们想要的两种单元格类型。为了结束这个模式,我们声明元素 fooid 和 fooname 是单元格,使用(再次)substitutionGroup。
<xs:element name="fooid" type="xs:integer"
substitutionGroup="tns:cell"/>
<xs:element name="fooname" type="xs:string"
substitutionGroup="tns:cell"/>
相同的模式可用于为表格栏声明一组不同的合法单元格:
<xs:element name="barid" type="xs:positiveInteger"
substitutionGroup="tns:cell"/>
<xs:element name="barcounter" type="xs:double"
substitutionGroup="tns:cell"/>
<xs:element name="table-bar" substitutionGroup="tns:table">
<xs:complexType>
<xs:complexContent>
<xs:restriction base="tns:table">
<xs:sequence>
<xs:element ref="tns:row-bar"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="row-bar" substitutionGroup="tns:row">
<xs:complexType>
<xs:complexContent>
<xs:restriction base="tns:row">
<xs:sequence>
<xs:element ref="tns:barid"/>
<xs:element ref="tns:barcounter"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:element>
您描述的情况是为其设计抽象元素和替换组的用例之一。这里也可以使用的其他技术(但我不会详细说明)包括:
- 声明子类型,使用 xsi:type(声明 foo-table 和 bar-table 作为类型 table 的限制或扩展,使用
<table xsi:type="tns:foo-table">...</table>
or<table xsi:type="tns:bar-table">...</table>
来指导验证)
- 断言(声明 foo-table 和 bar-table 类型,通过添加关于孙子的断言来扩展通用表类型——这是 XSD 1.1 1.0 中不可用的特性)。
- 条件类型分配(声明
table
如果有则获得一种类型,如果有则name="foo"
获得不同的类型name="bar"
——也是 1.0 中不可用的 XSD 1.1 功能)。
可能还有其他方法可以做到这一点。