すべてのアナリストとプログラマーの生活の中で、XMLスキームを設計するためのテンプレート(パターン)の存在と彼の人生の変化について学ぶ日が来ます。 たとえば、私にとって、デザインの美しさの実現はこの知識から始まりました。
今日は、XSDのデザインパターンとは何か、それぞれの利点と欠点、そして私たちの仕事にエデンの園を選んだ理由についてお話したいと思います。
たとえば、次のXMLドキュメントをデータソースとして使用します。
<?xml version="1.0" encoding="UTF-8"?> <Customer> <CustomerId>100</CustomerId> <FirstName></FirstName> <LastName></LastName> <Address> <StreetAddress> 2</StreetAddress> <City></City> <Zip>115088</Zip> </Address> </Customer>
そして、XML文書の同じ構造をさまざまな方法で記述する方法を見てみましょう。
テンプレートへの分割の基礎は、XSD内でグローバル要素および/またはデータ型を定義する原則です。
マトリョーシカ(ロシアの人形)
テンプレートの本質は、スキームがそれが記述するXMLドキュメントのミラーであることです:複雑な要素が他の複雑な要素を内部に含み、さらにそれらが単純な要素を含む場合、XSDのそのような要素の説明は互いに埋め込まれます。 テンプレートの名前は、世界的に有名な人形マトリョーシカに敬意を表しており、テンプレートの子が親にカプセル化される方法に似ています。
Matryoshkaテンプレートを使用してソースファイルの構造を説明する図は、次のようになります。
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/Customer" xmlns:tns="http://www.example.org/Customer" elementFormDefault="qualified"> <xsd:element name="Customer"> <xsd:complexType> <xsd:sequence> <xsd:element name="CustomerId" type="xsd:int" /> <xsd:element name="FirstName" type="xsd:string" /> <xsd:element name="LastName" type="xsd:string" /> <xsd:element name="Address"> <xsd:complexType> <xsd:sequence> <xsd:element name="StreetAddress" type="xsd:string"/> <xsd:element name="City" type="xsd:string"/> <xsd:element name="Zip" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
テンプレート機能:
- コンテンツの不透明度。 XSDコンテンツは、他のスキームに対しても、同じスキームの他の部分に対しても不透明です。 その結果、XSD内のどのタイプまたは要素も再利用できません。
- 隠されたエリア。 ローカル要素が定義されているスキームの領域(この例では「City」と「Zip」)は、ルート要素(「Address」)内にローカライズされています。 その結果、スキームでelementFormDefault = "unqualified"を設定すると、ローカル要素の名前空間( "City"および "Zip")はスキーム内で非表示になります。
- 独立。 この設計では、回路の各コンポーネントは自律的です(つまり、他のコンポーネントと相互接続されていません)。 したがって、個々のコンポーネントの変更による影響は限定的です。 たとえば、住所に「FlatNumber」要素を追加しても、スキームの他の要素には影響しません。
- コンパクト。 この設計のおかげで、すべての意味関連のデータが回路内で自律的なコンポーネントに結合されます。 コンポーネントはコンパクトです。
サラミ(サラミスライス)
テンプレートの本質は、記述されたXMLドキュメントが複合要素に分割され、それぞれがXSDでグローバルとして記述されていることです。 次に、記述された要素が接続されます。
Salamiテンプレートを使用したソースファイルの構造を説明する図は、次のようになります。
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/Customer" xmlns:tns="http://www.example.org/Customer" elementFormDefault="qualified"> <xsd:element name="CustomerId" type="xsd:int" /> <xsd:element name="FirstName" type="xsd:string" /> <xsd:element name="LastName" type="xsd:string" /> <xsd:element name="StreetAddress" type="xsd:string"/> <xsd:element name="City" type="xsd:string"/> <xsd:element name="Zip" type="xsd:string"/> <xsd:element name="Customer"> <xsd:complexType> <xsd:sequence> <xsd:element ref="tns:CustomerId" /> <xsd:element ref="tns:FirstName" /> <xsd:element ref="tns:LastName" /> <xsd:element name="Address"> <xsd:complexType> <xsd:sequence> <xsd:element ref="tns:StreetAddress" /> <xsd:element ref="tns:City" /> <xsd:element ref="tns:Zip" /> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
テンプレート機能:
- コンテンツの透明性。 すべての要素は、このXSDの他のコンポーネントと同様に、他のスキームを見ることができます。
- グローバリティ。 スキーマのすべての要素はグローバルに宣言されているため、スキーマ名前空間のelementFormDefaultの値に関係なく、属性のセット全体がXMLドキュメントに表示されます(何かが空の場合があります)。
- 相互依存。 この設計では、複雑な要素は回路の他の部分を参照します。つまり、それらに依存します。 そのため、個々のコンポーネントを変更すると、回路全体が大幅に変更される可能性があります。
- コンパクト。 この設計のおかげで、意味で接続されたすべてのデータは、回路内で自律的なコンポーネントに結合されます。つまり、コンポーネントはコンパクトです。
ベネチアンブラインド
テンプレートの本質は、記述されたXML文書が複合型に分割され、それぞれがXSDでグローバルとして記述されていることです。 次に、回路を接続するグローバルタイプに対応するルート要素が宣言されます。
Venetian Blindsテンプレートを使用したソースファイルの構造を説明する図は、次のようになります。
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/Customer" xmlns:tns="http://www.example.org/Customer" elementFormDefault="qualified"> <xsd:complexType name="AddressType"> <xsd:sequence> <xsd:element name="StreetAddress" type="xsd:string"/> <xsd:element name="City" type="xsd:string"/> <xsd:element name="Zip" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="CustomerType"> <xsd:sequence> <xsd:element name="CustomerId" type="xsd:int" /> <xsd:element name="FirstName" type="xsd:string" /> <xsd:element name="LastName" type="xsd:string" /> <xsd:element name="Address" type="tns:AddressType" /> </xsd:sequence> </xsd:complexType> <xsd:element name="Customer" type="tns:CustomerType" /> </xsd:schema>
テンプレート機能:
- コンテンツの透明性。 データ型は他のスキーマから見ることができ、このXSDのコンポーネントからも見ることができます。
- 最大の名前の非表示。 要素宣言はローカルであるため、テンプレートは名前を隠す可能性が最大限にあります。
- 空の属性の非表示を簡単に制御できます。 名前空間が非表示の場合、ドキュメントに空の属性を表示するかどうかは、単一のelementFormDefaultスイッチによって制御されます。
- 相互依存。 この設計では、複雑なデータ型はスキーマの他の部分を参照します。つまり、それらに依存します。 そのため、個々のコンポーネントを変更すると、回路全体が大幅に変更される可能性があります。
- コンパクト。 この設計のおかげで、意味で接続されたすべてのデータは、回路内で自律的なコンポーネントに結合されます。つまり、コンポーネントはコンパクトです。
エデンの園(エデンの園)
エデンの園は、各要素と複合データ型をグローバルとして定義するため、優れています。 これにより、同じXSD内、または他のXSDから、さらにはWSDLからでも型または要素を参照できます。 これは、型と要素の両方のセマンティクスを完全に制御する唯一の方法です。
Garden of Edenテンプレートを使用してソースファイルの構造を説明する図は、次のようになります。
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/Customer" xmlns:tns="http://www.example.org/Customer" elementFormDefault="qualified"> <xsd:element name="CustomerId" type="xsd:int"/> <xsd:element name="FirstName" type="xsd:string"/> <xsd:element name="LastName" type="xsd:string"/> <xsd:element name="StreetAddress" type="xsd:string"/> <xsd:element name="City" type="xsd:string"/> <xsd:element name="Zip" type="xsd:string"/> <xsd:element name="Address" type="tns:AddressType"/> <xsd:element name="Customer" type="tns:CustomerType"/> <xsd:complexType name="AddressType"> <xsd:sequence> <xsd:element ref="tns:StreetAddress"/> <xsd:element ref="tns:City"/> <xsd:element ref="tns:Zip"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="CustomerType"> <xsd:sequence> <xsd:element ref="tns:CustomerId"/> <xsd:element ref="tns:FirstName"/> <xsd:element ref="tns:LastName"/> <xsd:element ref="tns:Address"/> </xsd:sequence> </xsd:complexType> </xsd:schema>
テンプレート機能:
- コンテンツの最大透明度。 タイプとデータ要素の両方は、このXSDのコンポーネントだけでなく、他のスキームからも見ることができます。
- 名前の最大限の開示。 ローカルで定義されるものはないため、名前の可視性は最大になります。
- 相互依存。 この設計では、複雑なデータ型と要素は回路の他の部分を参照します。つまり、それらに依存します。 そのため、個々のコンポーネントを変更すると、回路全体が大幅に変更される可能性があります。
- かさばる。 関連データは、タイプと要素の定義によって「塗り付けられます」。 そのようなスキームを「読む」ことはより困難です。
テンプレートの選択
テンプレートを選択する際には、いくつかの基準を考慮することが重要です。
- 可能な限り回路部品の再利用;
- 回路を操作するのは簡単です。
- 回路コンポーネントが相互依存または独立している必要があります。
多くの場合、設計テンプレートを選択するとき、回路コンポーネントを再利用する機能とコンポーネント間の関係の深さとのバランスを見つける必要があります。 図は、これら2つの側面のコンテキストでの各テンプレートの可能性を示しています。
一方、コンポーネントの再利用が適切にサポートされているスキームは、コンポーネント間に強い関係があります。 必要に応じて、そのようなスキームで何かを変更する場合、スキームの開発者は、多くの関連する要素やタイプを変更する必要があるという事実に遭遇する可能性があります。 そのようなスキームは、その後管理が困難です。
一般に、次のテンプレート選択ルールを導出できます。
- 回路のコンポーネントを再利用する必要がない場合、開発者によるXSDの使いやすさがより重要であり、コンポーネントの名前を厳密に制御する必要がない場合は、「入れ子人形」を選択します。
- コンポーネントの再利用が開発者の利便性よりも重要であり、データ要素の名前をシステム全体で制御する必要がある場合は、「Salami」を選択します。
- 前の段落に加えて、データ型の名前を制御し、データ型を再利用できるようにすることが重要な場合は、「Garden of Eden」を選択します。
- 「ベネチアンブラインド」は、コンポーネントを再利用することが重要である場合、およびローカル名を決定する自由(またはスキーム内でコンポーネントを非表示にする機能)に適しています。
プロジェクトで私たちにとって最も重要なことは、スキームのタイプと要素の再利用、そして何よりも名前の完全な意味制御です。 テンプレートの選択は明白でした-Garden of Eden。
少し叙情的な余談。 私の記憶にあるXMLスキーマ設計パターンの最も興味深いアプリケーションは、これまでも聴衆の催眠術でもありました。 タイトルのアナリストの1人は、このテーマに関するストーリーを通して自分の手で主導権を握るのが大好きです。 5分後にタイムアウトになり、視聴者の視線は暗くなり、視聴者は自分自身のどこかに行きます。 「エデンの庭」では、多数の意識がオフになっています。
結論として、テンプレートミックスも可能であることを付け加えたいと思います。
ソースとリソース:
XMLスキーマ仕様
スキーマスコープ:入門書およびベストプラクティス
XMLスキーマでのデザインパターンの紹介