0

我正在尝试为一些基于 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 中。有没有办法定义这个?

4

1 回答 1

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-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 功能)。

可能还有其他方法可以做到这一点。

于 2013-08-19T17:30:43.917 回答