はい、2つの方法があります。1 つは単純で (人間の直感とドキュメントに依存します)、もう 1 つはより表現力豊かです (ただし、必然的にもう少し複雑になります)。
簡単な方法は、'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 を使用した検証など) は、主に使用される要素名に基づいています。2 つの異なる種類の行に異なる内容を含める場合は、それらに 2 つの異なる名前を付けます。したがって、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>
bar-table と bar-row についても同様です。
ただし、場合によっては、'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"/>
table と row の型は単純です。
<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 の行に必要な 2 つのセル タイプだけです。そして、パターンを締めくくるために、要素 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>
あなたが説明する状況は、抽象要素と置換グループが設計されたユースケースの 1 つです。ここで使用できるその他のテクニック (詳細は説明しません) には、次のようなものがあります。
- 宣言されたサブタイプ、xsi:type の使用 (foo-table および bar-table を制限または type table の拡張として宣言し、
<table xsi:type="tns:foo-table">...</table>
またはを使用<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 の機能でもあります)。
他にも方法があるかもしれません。