2010年 9月 17日 - 読者からのコメントを基に、リスト 3、11、12、13 のコードが著者によって更新されました。
スキーマは、強力な XML Schema Definition Language (XSD、また W3C Schema と呼ばれることもあります) を使って他の XML データのモデリングと妥当性検証を行うための、整形式の XML 文書です。スキーマのパーティクル (要素、型、属性、その他の構成体) の定義方法に応じて、それらのパーティクルに対し、グローバルで公開型のスコープ、またはローカルで非公開型のスコープが関連付けられます。スキーマのスコープをどう設計するかにより、スキーマの進化、再利用性、他の技術との相互運用性に大きく影響します。
スキーマを使い始めたばかりの読者であれ、現在のソリューションからより多くを得たい読者であれ、スキーマのスコープを十分に理解することが成功への鍵です。この記事ではまず、さまざまなスキーマ・パーティクルに対してグローバル・スコープまたはローカル・スコープを定義する方法と、スコープがスキーマ・パーティクルの動作にどう影響するかを説明します。次に、スキーマ設計の基本パターンと、プロジェクトの要求に合わせてスコープ設計を行う上での考慮事項とベスト・プラクティスについて説明します。
スキーマにとって最上位レベルのコンテナー要素は schema です。schema 要素の直接の子要素はグローバルに定義されます (つまり、それらの子要素はグローバルなスコープを持ちます)。グローバル要素はルート・ノードとして使用することができ、またそれらのグローバル要素をスキーマの別の部分から参照することができます。一旦要素を定義すれば、スキーマのどこからでもその要素を再利用することができます。
リスト 1 に示すスキーマの例は、postalCode という 1 つのグローバル要素を持つ単純なデータ・モデルを示しています。
リスト 1. 1 つのグローバル要素を持つスキーマ
<xs:schema> <xs:element name='postalCode' type='xs:string'/> </xs:schema> |
リスト 1 のスキーマを使用すると、下記のデータ・インスタンスを適切に妥当性検証することができます。
<postalCode>14534</postalCode> |
このデータ・インスタンスでは、postalCode がルート要素、つまりこのデータ・インスタンスの最上位レベルのコンテナーです。関連付けられたスキーマの最上位レベルで定義された要素のみが、データ・インスタンスのルート要素になることができます。リスト 1 のスキーマでは 1 つの要素しか定義していないため、データ・インスタンスのルート要素となれるのが postalCode のみであることは容易に理解することができます。
リスト 2 に示すスキーマの例では、2 つの要素をルート・レベルで定義しています。
リスト 2. ルート要素が 2 つ考えられるスキーマ
<xs:schema> <xs:element name='postalCode' type='xs:string'/> <xs:element name='zipCode' type='xs:string'/> </xs:schema> |
リスト 2 のスキーマでモデリングされたインスタンスでは、postalCode または zipCode がルート要素となることができます。
ローカルで要素を定義すると、それらの要素がスキーマの他の部分から見えないようにすることができます。ローカル要素のコンテキストは現在の場所に限定されているため、その要素をスキーマの他の部分から参照することはできません。リスト 3 の例では、zipCode 要素の定義はグローバルではありません。zipCode 要素は address 要素のサブ要素として、complexType という要素定義の中で定義されています。
リスト 3. ローカルな子要素を持つ 1 つのグローバル要素
<xs:schema>
<xs:element name='address'>
<xs:complexType>
<xs:sequence>
<xs:element name='street' type='xs:string'/>
<xs:element name='city' type='xs:string'/>
<xs:element name='state' type='xs:string'/>
<xs:element name='zipCode' type='xs:string'/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
|
zipCode 要素の定義は address 要素の宣言の中で行われているため、ローカル定義であり、スコープは address 要素の中にしかありません。文書インスタンスを有効なものにするためには、zipCode 要素は address 要素の中になければなりません (リスト 4)。
リスト 4. リスト 3 のスキーマに対する有効なデータ・インスタンス
<address> <!-- street, city and state hidden for example purposes --> <zipCode>14534</zipCode> </address> |
リスト 4 では address 要素がルート要素です。zipCode 要素はスキーマ・モジュールのルート・レベルでグローバルに定義されているわけではないため、インスタンスのルート要素になることはできません。ローカルで定義された要素は、それらの要素が定義されている要素定義のコンテキストの中でしか使用することができません。
グローバルに定義された要素はすべて、ルート要素として機能するだけではありません。必要な場合には任意のローカル・スコープで、グローバルに定義された要素を参照したり、使用したりすることができます。リスト 5 の例では、グローバルに定義された zipCode 要素が、address 要素の定義の中で、ローカル・スコープのコンテキストで使われています。
リスト 5. ローカル・スコープでグローバル要素を参照する
<xs:schema>
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name='street' type='xs:string'/>
<xs:element name='city' type='xs:string'/>
<xs:element ref='zipCode'/> <!-- reference to globally defined element -->
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- Globally defined element that is referenced in element above -->
<xs:element name='zipCode' type='xs:string'/>
</xs:schema>
|
これを見ると、要素宣言をグローバルに公開することでモジュール化や再利用が可能になることがわかります。このスキーマの他の部分や、このスキーマをインポートする親スキーマの中で、zipCode 要素を参照することができます。
属性定義の場合も動作は同じです。例えばリスト 6 では、グローバルに定義された state 属性が、address 要素の中でローカル・スコープのコンテキストで参照されています。
リスト 6. ローカル・スコープでグローバル属性を参照する
<xs:schema> <xs:element name='address'> <xs:complexType> <!--[.. elements removed for readability..]--> <xs:attribute ref="state"/> <!-- referencing globally defined attribute --> </xs:complexType> </xs:element> <xs:attribute name="state" type="xs:string"/> <!--globally defined attribute --> </xs:schema> |
要素と属性をグローバルにもローカルにも定義できるのと同様に、型も定義することができます。これまで示した例では、address 要素の定義に対してローカルに定義された型を使用していました。この要素の型定義をローカルではなくグローバルな定義にするためには、この要素の型定義に一意の名前を付け、ルート schema ノードの下に配置します (リスト 7)。
リスト 7. グローバルな型をローカル・スコープで参照する
<xs:schema>
<xs:element name='address' type="address.type"/>
<xs:complexType name="address.type">
<xs:sequence>
<xs:element name='street' type='xs:string'/>
<xs:element name='city' type='xs:string'/>
<xs:element name='state' type='xs:string'/>
<xs:element name='zipCode' type='xs:string'/>
</xs:sequence>
</xs:complexType>
</xs:schema>
|
これで、この要素の型定義は address.type という一意の名前を持つグローバルな定義になります。ある要素にこの型を指定するためには、この要素の型属性 (type="") にこのグローバルな型の名前を指定することで、この型を参照するようにします。グローバルな型定義は xs:extension 要素を使って拡張することも、あるいは xs:restriction 要素を使って制限することもできます。
スキーマ・パーティクルの定義をローカル・スコープにすべきかグローバル・スコープにすべきかの判断は、必ずしも容易ではありません。使用ケース、名前空間の要件、またスキーマの進化の程度により、どちらがベストかは異なります。一般的に、スキーマの設計は以下の 4 つの基本的なパターンに分類することができます。
- 「ロシア人形 (Russian Doll)」パターン
- 「サラミ・スライス (Salami Slice)」パターン
- 「ベネチアン・ブラインド (Venetian Blinds)」パターン
- 「エデンの園 (Garden of Eden)」パターン
これらのパターンを理解し、プロジェクトにとって最適のソリューションを判断することが重要です。
このパターンは、ロシアの有名なマトリョーシカ人形に似ていることから、この名前が付けられました (マトリョーシカは木の人形で、中に小さな人形が入っており、さらにその中にも人形・・・という構造になっています)。ロシア人形パターンでは、すべてのサブ要素をローカルで定義します。従って、各要素とその型は、まさにロシア人形のように、その親によってカプセル化されています。
リスト 8 の例 (ある家電のヘルプ文書を単純化して表現したもの) は、このパターンを示しています。
リスト 8. ロシア人形スタイルのスキーマ
<xs:schema>
<xs:element name="HelpDoc">
<xs:complexType>
<xs:sequence>
<xs:element name="Section">
<xs:complexType>
<xs:sequence>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Body" type="xs:string"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:/complexType>
</xs:element>
</xs:schema>
|
このスキーマに関連付けられたインスタンスはリスト 9 のようになります。
リスト 9. ロシア人形のスキーマ・モデルに当てはまるインスタンス
<HelpDoc> <Section name="operation_instructions"> <Title>Operating your appliance.</Title> <Body>First, open the packaging and check to see...</Body> </Section> </HelpDoc> |
リスト 8 では、すべてのサブ要素、属性、型がローカルに定義されていることがわかります。唯一、グローバルな要素は、ルートの HelpDoc です。この構文は簡潔であり、読みやすいと思う人がいるかもしれません。ロシア人形スタイルのスキーマでは、そのスキーマのコンポーネントを他の型や要素、スキーマに対して公開しないため、極めて独立性が高く (つまり要素は他の要素にグローバルに依存しておらず)、焦点が絞られている (自己完結している 1 つの親の中に関連する要素がグループ化されている) と考えることもできます。
このパターンは、他のシステムとほとんどやり取りをせず、コンポーネントを再利用しない、という想定のスキーマの典型的なものです。この方式でスキーマを定義すると、構造を自己完結したものに保つことや、名前空間を隠すこと、そして他のシステムからの影響を防ぐことができます。
サラミ・スライス・パターンでは、コンテンツ・モデルの公開に向けて一歩踏み出します。このパターンでは、ローカルに定義された要素をすべて、グローバルな定義へと変更します。リスト 10 は、リスト 8 のロシア人形スタイルの例をサラミ・スライス・パターンに合うように変更したものです。
リスト 10. サラミ・スライス・パターン
<xs:schema>
<xs:element name="Body" type="xs:string"/>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Section">
<xs:complexType>
<xs:sequence>
<xs:element ref="Title"/>
<xs:element ref="Body"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="HelpDocs">
<xs:complexType>
<xs:sequence>
<xs:element ref="Section"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
|
サラミ・スライス・パターンでは、すべての要素を公開します。そのため、そのスキーマの他の部分でそれらの要素を参照したり再利用したりすることができ、またそれらの要素を他のスキーマからも見えるようにすることができます。この方式の主なメリットは、要素が非常に再利用しやすくなることです。ただしそれは、すべての名前空間がグローバルに公開され、要素間の結合が増すということも意味します。リスト 10 で、Section 要素は Title 要素と Body 要素にグローバルに結合されています。Title 要素と Body 要素を少しでも変更すると、結果的に Section の定義に影響することになります。
「ベネチアン・ブラインド (Venetian Blinds)」パターン
ベネチアン・ブラインド・パターンでは、すべての要素をグローバルに定義する代わりに、すべての型をグローバルに定義することから始めます (リスト 11)。
リスト 11. ベネチアン・ブラインド・パターン
<xs:schema>
<xs:complexType name="section.type">
<xs:sequence>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Body" type="xs:string"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
<xs:complexType name="helpdocs.type">
<xs:sequence>
<xs:element name="Section" type="section.type"/>
</xs:sequence>
</xs:complexType>
<xs:element name="HelpDocs" type="helpdocs.type"/>
</xs:schema>
|
ベネチアン・ブラインド・スタイルでは、グローバルな型定義を使って再利用性を高めます。すべてのサブ要素はローカルに定義されているため、名前空間を隠せるという別のメリットがあります。この方式では、構造の定義を公開して再利用を促進する一方、名前空間を隠すか公開するかを elementFormDefault 属性を使って切り替えることができます。つまり両方の良いところを利用することができます。
エデンの園設計パターンでは、要素の宣言と型の宣言の両方をグローバルにし、極限までグローバル化を進めます。リスト 12 はエデンの園スタイルのスキーマを示しています。
リスト 12. エデンの園パターン
<xs:schema>
<xs:attribute name="name" type="xs:string"/>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Body" type="xs:string"/>
<xs:element name="Section" type="section.type"/>
<xs:element name="HelpDocs" type="helpdocs.type"/>
<xs:complexType name="section.type">
<xs:sequence>
<xs:element ref="Title"/>
<xs:element ref="Body"/>
</xs:sequence>
<xs:attribute ref="name"/>
</xs:complexType>
<xs:complexType name="helpdocs.type">
<xs:sequence>
<xs:element ref="Section"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
|
あらゆる要素、属性、型をグローバルにすることで、スキーマ内でもスキーマ間でも最大限に再利用を図るシナリオを実現することができます。ただし名前空間は強制的に公開されることになります。構造を完全に公開することで、非常に強く結合されているけれどもアジャイルなスキーマになります。また、さまざまな要素が相互に依存しているため、スキーマを大幅に変更してもそれがすぐに全体に適用されます。
スキーマを設計する場合には、コンポーネントを再利用できるように公開するかどうか、名前空間を隠して名前空間の公開を制限すべきか、結合 (あるいは、さまざまなグローバル要素や型の相互依存) を減らすべきか、といった要素間のバランスを取ることがよくあります。図 1 は 4 つのスキーマ・パターンそれぞれの再利用のしやすさをまとめたものであり、結合 (Coupling) レベルと公開 (Exposure) レベルの両面から、それぞれの相対的な位置づけを示しています。
図 1. パターンの違いによる公開レベルと結合レベル
スキーマのコンポーネントが再利用しやすくなれば、今後の開発に要する時間を短縮することができ、大幅な変更も容易になります。ただしそうすると、さまざまな要素や型が必要以上に結合されたシナリオになる可能性もあります。スキーマ同士が強く結合されると、要素や型が相互依存するようになり、今後、変更や追加を扱うのが難しくなります。不用意に結合すると、他のシステムはインターフェースが変わらないことを前提にしているため、スキーマを進化させにくくなります。何を、どの程度公開するかに注意することが重要です。いったん 1 つの方式を選択すると、取り消しは困難です。
とはいえ、今後の成功を確実にするための方法はあります。まず、スコープを以下のように適切に設計します。
- スキーマの再利用は重要ではなく、スキーマのサイズを最小限にすることが重要な場合には、ロシア人形スタイルを使用します。ロシア人形スタイルは簡潔であり、名前空間を隠すためには最も効果的だからです。
- 要素の置き換えが設計上重要な場合、あるいは要素を他のスキーマからも見えるようにする必要がある場合には、サラミ・スライスまたはエデンの園スタイルを使用します。
- 最大限に再利用したい場合で、可能な限り名前空間を隠せるようにしたい場合には、ベネチアン・ブラインド・スタイルを使用します。そして
elementFormDefaultを使用し、名前空間を公開するのか、あるいは隠すのかを切り替えます。
また、異なるパターンを混在させることを恐れる必要はありません。特定のスキーマの中で複数のスキーマ設計パターンを使用すると、非常に効果的な場合があります。構造のうち、プライベートにして隠しておきたい部分には、ロシア人形スタイルを使用します。同時に、サラミ・スライス、またはエデンの園の設計スタイルを使って一部の要素をグローバルに公開する必要があるかもしれません。例えばリスト 13 は、非常に公開度の高いエデンの園スタイルを、非公開型ロシア人形スタイルのセクションと一緒に使用しています。
リスト 13. パターンを混在させる
<xs:schema>
<!-- Garden of Eden style component -->
<xs:element name="Title" type="xs:string"/>
<xs:element name="Body" type="xs:string"/>
<xs:element name="Section" type="section.type"/>
<xs:element name="HelpDocs" type="helpdocs.type"/>
<xs:complexType name="section.type">
<xs:sequence>
<xs:element ref="Title"/>
<xs:element ref="Body"/>
</xs:sequence>
<xs:attribute name="name"/>
</xs:complexType>
<xs:complexType name="helpdocs.type">
<xs:sequence>
<xs:element ref="Section"/>
<!-- Russian doll style component -->
<xs:element name="Credits">
<xs:complexType>
<xs:sequence>
<xs:element name="Author" type="xs:string"/>
<xs:element name="Year" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
|
このシナリオでは、HelpDocs 要素、Section 要素、Title 要素 Body 要素を他のスキーマで使用できるように公開する必要があるかもしれません。ただし、Credits 要素を隠し、他のスキーマ定義に結合されないようにする必要があります。
再利用の必要性が高くない場合には、このようにしてスキーマを作成するのは非常に理にかなっています。要素をグローバルにすることで公開度を上げるのは容易ですが、公開したものを後で非公開にするのは非常に困難です。この例の場合には、将来の設計で公開度を上げる必要に迫られた場合にも、容易に公開度を上げることができます。
どのようなスキーマ・プロジェクトであれ、そのプロジェクトを開始する前に、設計の選択肢と目標とを整合させる必要があります。スキーマのスコープの使い方を理解することで、スキーマやコンテンツの管理プロセスを効率化することができます。最終的に、そうすることで皆さんはスキーマのライフサイクル管理をうまく行えるようになり、また皆さんのスキーマが他のシステムと効率的にやり取りできるようになります。
学ぶために
- 「現実世界でのXML Schema」(Paul Golick と Richard Mader の共著、developerWorks、2002年1月) を読み、XML を使う上で幅広く活用できる 17 項目のプラクティスについて学んでください。
- 「XMLスキーマの使用法の基本: エレメントの定義 」(Ashvin Radiya と Vibha Dixit の共著、developerWorks、2000年8月) を読み、スキーマの柔軟性について知り、また XML 文書の最も基本的なビルディング・ブロック (つまり要素) を XML Schema システムの中で定義する方法を学んでください。
- 「Tip: When to use local and global declarations」(Benoît Marchal 著、developerWorks、2003年9月) を読んでください。このヒントでは、要素をグローバルに宣言する方法とローカルに宣言する方法について、どんな場合にどちらを使うべきかを含めて解説しています。
- W3C の XML Schema 入門サイトを訪れ、XML スキーマに対する W3C 勧告について調べてください。
- developerWorks の XML ゾーンには、XML の領域でのスキルを磨くためのリソースが豊富に用意されています。
- My developerWorks で developerWorks のエクスペリエンスをパーソナライズしてください。
- XML および関連技術において IBM 認定技術者になる方法については、IBM XML certification を参照してください。
- developerWorks の XML ゾーンを XML の技術ライブラリーとして利用してください。広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、IBM Redbooks などが用意されています。また、XML に関する他のヒント記事も読んでください。
- developerWorks の Technical events and webcasts で最新情報を入手してください。
- 今すぐ Twitter に参加して developerWorks のツイートをフォローしてください。
- developerWorks podcasts では、ソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
製品や技術を入手するために
- IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。
議論するために
- XML zone discussion forums に参加してください。これらのフォーラムでは XML を中心に議論が行われています。
- developerWorks blogs から developerWorks のコミュニティーに加わってください。

Casey Jordan は構造化データとスマート・データのエバンジェリストであり、Jorsek の共同設立者でもあります。Jorsek は、さまざまな組織におけるデータのデプロイメント、ストレージ、そして人同士の協力の質を高めるためのソフトウェアとサービスを提供する企業です。彼はコンテンツ管理と Web サービスに 10 年を超える経験があり、ネイティブ XML データベース、XQuery、XSLT、XML Schema、DITA などの XML 技術と企業のコンテンツ戦略とを整合させるための支援を行っています。

Dale Waldt はこれまで 25 年以上にわたり、政府や企業、非営利団体などでの XML アプリケーション、コンポジションおよびパブリッシング・ソリューション、複合 Web サイトの設計、開発を主導してきました。この 10 年間は、Web およびコンテンツ技術、そしてオープン標準の採用を専門としたコンサルタント、インストラクター、業界アナリストとして活躍しています。開発チームと協力して、プロセスの最適化やスキーマの設計に取り組むことや、データおよびアプリケーションの設計・開発リーダーを務めること、そしてソフトウェアおよびサービスの評価、XML、XSLT および関連技術での開発者トレーニングに従事することもよくあります。