我正在尝试为某些基于xml的数据库交换定义一个模式,如下所示:
<table name="foo">
<row>
<fooid>15</fooid>
<fooname>some entry</fooname>
</row>
<row>
<fooid>28</fooid>
<fooname>something else</fooname>
</row>
</table>
<table name="bar">
<row>
<barid>19</barid>
<barcounter>93</barcounter>
</row>
</table>
所以我有几个这样的表,在这些表中应该只有这些表中存在的字段。例如,barid不应出现在表foo中。 有没有办法来定义它?
答案 0 :(得分:2)
是的,有两种方法。一个是简单的(并且依赖于一些人的直觉和文档),另一个更具表现力(但也不可避免地更复杂。)
简单的方法是将名称'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表是表抽象的实例,其类型是抽象表类型的限制:
<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>
您描述的情况是设计抽象元素和替换组的用例之一。其他可以在这里使用的技术(但我不会详细说明)包括:
<table xsi:type="tns:foo-table">...</table>
或<table xsi:type="tns:bar-table">...</table>
来指导验证)table
如果有name="foo"
则获得一种类型,如果有name="bar"
则获得不同类型 - 也是1.0中不可用的XSD 1.1功能。 也可能有其他方法可以做到。