あなたの問題には解決策がありますが、きれいではありません。理由は次のとおりです。
非決定論的コンテンツ モデルの違反
W3C XML Schema の本質に触れました。あなたが求めているもの — 可変順序と可変未知要素 — は、XSD の最も困難でありながら最も基本的な原則であるNon-Ambiguityのルール、またはより正式にはUnique Particle Attribution Constraintに違反しています。
コンテンツ モデルは、検証中に [..] シーケンス内の各アイテムが、そのアイテムのコンテンツや属性を調べることなく、シーケンスの残りのアイテムに関する情報なしで一意に決定できるように形成する必要があります。
通常の英語では、XML が検証され、XSD プロセッサが遭遇し<SurName>
た場合、最初に が続くかどうかをチェックせずに検証できる必要があります<GivenName>
。あなたのシナリオでは、これは不可能です。この規則は、有限ステート マシンによる実装を許可するために存在します。これにより、実装がかなり簡単で高速になります。
これは最も議論の多い問題の 1 つであり、SGML と DTD (コンテンツ モデルは決定論的である必要があります) および XML の遺産であり、デフォルトで、要素の順序が重要であると定義されています(したがって、反対のことを試みて順序を変更します)。重要ではない、難しい)。
Marc_s が既に示唆しているように、Relax_NG は、非決定論的なコンテンツ モデルを可能にする代替手段です。しかし、W3C XML スキーマに行き詰まっている場合はどうすればよいでしょうか?
機能しない半有効なソリューション
あなたはすでにそれxs:all
が非常に制限的であることにお気づきでしょう。理由は簡単です。同じ非決定論的なルールが適用され、1 より大きい とシーケンスが許可されないのはそのためxs:any
ですmin/maxOccurs
。
choice
また、 、 、のあらゆる種類の組み合わせsequence
を試したことがあるかもしれませんany
。このような無効な状況が発生したときに Microsoft XSD プロセッサがスローするエラーは次のとおりです。
エラー: 要素 ' http://example.com/Chad:SurName 'の複数の定義により、コンテンツ モデルがあいまいになります。コンテンツ モデルは、要素情報アイテム シーケンスの検証中に、シーケンス内の各アイテムを順番に検証しようとする直接的、間接的、または暗示的に含まれる粒子が、コンテンツまたは属性を調べることなく一意に決定できるように形成する必要があります。そのアイテム、およびシーケンスの残りのアイテムに関する情報なし。
O'Reilly の XML Schema (そうです、この本には欠点があります) では、これが見事に説明されています。さらに、本の一部はオンラインで入手できます。Unique Particle Attribution Ruleに関するセクション 7.4.1.3を読むことを強くお勧めします。その説明と例は、私が得ることができるよりもはるかに明確です。
1 つの実用的なソリューション
ほとんどの場合、非決定論的設計から決定論的設計に移行することが可能です。これは通常は見栄えがよくありませんが、W3C XML スキーマに固執する必要がある場合や、厳密ではない規則を XML に絶対に許可する必要がある場合の解決策です。あなたの状況の悪夢は、1 つのこと (2 つの事前定義された要素) を強制したいと同時に、それを非常に緩くしたいことです (順序は関係なく、前と後の間で何でも構いません)。適切なアドバイスをするのではなく、解決策に直接導くだけだとすると、次のようになります。
<xs:element name="User">
<xs:complexType>
<xs:sequence>
<xs:any minOccurs="0" processContents="lax" namespace="##other" />
<xs:choice>
<xs:sequence>
<xs:element name="GivenName" />
<xs:any minOccurs="0" processContents="lax" namespace="##other" />
<xs:element name="SurName" />
</xs:sequence>
<xs:sequence>
<xs:element name="SurName" />
<xs:any minOccurs="0" processContents="lax" namespace="##other" />
<xs:element name="GivenName" />
</xs:sequence>
</xs:choice>
<xs:any minOccurs="0" processContents="lax" namespace="##any" />
</xs:sequence>
<xs:attribute name="ID" type="xs:unsignedByte" use="required" />
</xs:complexType>
</xs:element>
上記のコードは実際に機能します。しかし、いくつかの注意点があります。1 つ目は、名前空間としてxs:any
withです。最後のものを除いて、 を##other
使用することはできません。これは、代わりに要素 like を使用することを許可し、 の定義があいまいになることを意味します。##any
GivenName
User
2 つ目の注意点は、このトリックを 2 つまたは 3 つ以上で使用する場合は、すべての組み合わせを書き留める必要があるということです。メンテナンスの悪夢。そのため、次のことを思いつきます。
提案された解決策、バリアブル コンテンツ コンテナーのバリアント
定義を変更してください。これには、読者やユーザーにとってより明確であるという利点があります。また、メンテナンスが容易になるというメリットもあります。一連のソリューション全体が XFront hereで説明されています。これは、Oleg の投稿から既に見たかもしれない読みにくいリンクです。すばらしい読み物ですが、ほとんどの場合、可変コンテンツ コンテナー内に 2 つの要素という最小要件があることを考慮していません。
あなたの状況 (想像以上に頻繁に起こる) に対する現在のベスト プラクティス アプローチは、データを必須フィールドと非必須フィールドに分割することです。要素を追加する<Required>
か、反対のことを行い、要素を追加します(またはそれをProperties、またはOptionalData<ExtendedInfo>
と呼びます)。これは次のようになります。
<xs:element name="User2">
<xs:complexType>
<xs:sequence>
<xs:element name="GivenName" />
<xs:element name="SurName" />
<xs:element name="ExtendedInfo" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="lax" namespace="##any" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
現時点では理想的とは言えないかもしれませんが、少し成長させてください。固定要素の順序付けられたセットを持つことは、それほど大したことではありません。W3C XML スキーマのこの明らかな欠陥について不満を言うのはあなただけではありませんが、前述したように、それを使用する必要がある場合は、その制限を受け入れるか、開発の負担を受け入れる必要があります。より高い所有コストでこれらの制限を回避します。
代替ソリューション
これはもうご存知だと思いますが、属性の順序はデフォルトでは未定です。すべてのコンテンツが単純なタイプである場合は、代わりに属性をより豊富に使用することを選択できます。
最後に一言
どのようなアプローチをとっても、データの多くの検証可能性が失われます。多くの場合、コンテンツ プロバイダーがコンテンツ タイプを追加できるようにする方が適切ですが、それが確認できる場合に限られます。lax
これは、からstrict
processing に切り替え、型自体をより厳密にすることで実行できます。しかし、厳しすぎるのもよくありません。適切なバランスは、直面しているユースケースを判断する能力と、特定の実装戦略のトレードオフと比較検討する能力に依存します。