XML スキーマは DTD よりもはるかに強力なものです。XML スキーマの能力を例示するために、最初の 3 つのリストでは、エレメントの各種の表現方法を簡単に比較します。リスト 1 は XML 文書の抜粋です。リスト 2 はこれら 2 つのエレメントの DTD 構文による宣言であり、リスト 3 はそれに対応する XML スキーマ構文です。リスト 3 の構文は XML の構文と同じであることに注目できます。スキーマを見ることによって、妥当性検査パーサーは、エレメントInvoiceNo
が正の整数であり、エレメントProductID が A ~ Z の 1 文字に 6 桁の数字が続いたものであることを検査することができます。対照的に、DTD を参照する妥当性検査パーサーは、これらのエレメントがストリングで表現されていることを検査できるにすぎません。
リスト 1: XML 文書の一部
<InvoiceNo>123456789</InvoiceNo>
<ProductID>J123456</ProductID>
|
リスト 2: リスト 1 のエレメントを記述した DTD
<!ELEMENT InvoiceNo (#PCDATA)>
<!ELEMENT ProductID (#PCDATA)>
|
リスト 3: リスト 1 のエレメントを記述した XML スキーマ
<element name='InvoiceNo' type='positive-integer'/>
<element name='ProductID' type='ProductCode'/>
<simpleType name='ProductCode' base='string'>
<pattern value='[A-Z]{1}d{6}'/>
</simpleType>
|
様々な人と協力して仕事を行う世界では、ある人が他のグループから受け取った文書を処理することがあり、他のグループでは自分とは別の方法でデータ・エレメントを表現することを望むことがあります。さらに、一つの文書の中で、別のグループが作成したエレメントで同じ名前を持つものを区別して参照する必要があるかもしれません。では、同じ名前の別々の定義をどのように区別することができるでしょうか? XML スキーマでは、ネームスペースを使ってそれらの定義を区別します。
一つの XML スキーマでは、エレメント、タイプ、属性、属性グループの名前など、一連の新しい名前を定義します。それらの定義と宣言はスキーマ内に記述されます。リスト 3 ではInvoiceNo、ProductID、およびProductCode として名前を定義しています。
一つのスキーマ内で定義された名前は、そのターゲット・ネームスペース に属していると言います。ネームスペース自体は、固定の名前を持ちます。この名前は任意に決めることができます。ネームスペースの名前は URL 構文に従います。たとえば、リスト 3 に抜粋されたスキーマのネームスペースの名前は、http://www.SampleStore.com/Account と設定することができます。
ネームスペースの構文は、誤解しやすいものかもしれません。ネームスペース名はhttp:// で始まりますが、その URL にあるスキーマ定義を含むファイルを指すものではありません。実際、URLhttp://www.SampleStore.com/Account は、どのファイルを指すものでもなく、ネームスペースに割り当てられた名前を表しているだけです。
スキーマ内の定義と宣言は、他のネームスペースに属する名前を指していることもあります。この記事では、それらのネームスペースをソース・ネームスペース と呼びます。つまりそれぞれのスキーマには、1 つのターゲット・ネームスペースと、おそらく多くのソース・ネームスペースがあることになり、スキーマ内のすべての名前は何らかのネームスペースに属します。ネームスペースの名前はかなり長くなることがありますが、XML スキーマ文書内のxmlns 宣言の構文によって短縮形を指定します。これからリスト 4 に示されたスキーマ例にネームスペースを追加してゆくことによって、これらの概念を示すことにします。
リスト 4: ターゲットおよびソース・ネームスペース
<!--XML Schema fragment in file schema1.xsd-->
<xsd:schema targetNamespace='http://www.SampleStore.com/Account'
xmlns:xsd='http://www.w3.org/1999/XMLSchema'
xmlns:ACC= 'http://www.SampleStore.com/Account'>
<xsd:element name='InvoiceNo' type='xsd:positive-integer'/>
<xsd:element name='ProductID' type='ACC:ProductCode'/>
<xsd:simpleType name='ProductCode' base='xsd:string'>
<xsd:pattern value='[A-Z]{1}d{6}'/>
</xsd:simpleType>
|
リスト 4 の XML スキーマでは、targetNamespace の名前はhttp://www.SampleStore.com/Account であり、これにはInvoiceNo、ProductID、およびProductCode という名前が含まれています。schema、element、simpleType、pattern、string、およびpositive-integer という名前は、ソース・ネームスペースのhttp://www.w3.org/1999/XMLSchema に属しています。このネームスペースには、xmlns 宣言によってxsd という短縮系が与えられています。別名として割り当てるxsd については、特に決まりはありません。どんな名前でも選択できます。便宜上、またこの記事の残りの部分を簡単にするため、ネームスペースhttp://www.w3.org/1999/XMLSchema を指すものとしてxsd を使用し、一部のコードではxsd の修飾も省きます。この例では、targetNamespace が、ソース・ネームスペースの 1 つにもなっていますが、これは、ProductCode という名前が、他の名前の定義に使用されているからです。
図 1: リスト 4 のネームスペース
リスト 4 のスキーマ (一部) では、ソース・スキーマ・ファイルのロケーションを指定する必要はありません。"スキーマのスキーマ" であるhttp://www.w3.org/1999/XMLSchema については、そのロケーションはよく知られているので、指定する必要はありません。ソース・ネームスペースのhttp://www.SampleStore.com/Account については、それが今まさにこのファイルで定義しようとしているターゲット・ネームスペースにもなっているので、ロケーションを指定する必要はありません。スキーマのロケーションの指定方法とデフォルトのネームスペースの使用法についてさらによく理解するため、リスト 5 の例の拡張部分を考慮しましょう。
リスト 5: 複数のソース・ネームスペース、ネームスペースのインポート
<!--XML Schema fragment in file schema1.xsd-->
<schema targetNamespace='http://www.SampleStore.com/Account'
xmlns='http://www.w3.org/1999/XMLSchema'
xmlns:ACC= 'http://www.SampleStore.com/Account'
xmlns:PART= 'http://www.PartnerStore.com/PartsCatalog'>
<import namespace='http://www.PartnerStore.com/PartsCatalog'
schemaLocation='http://www.ProductStandards.org/repository/alpha.xsd'/>
<element name='InvoiceNo' type='positive-integer'/>
<element name='ProductID' type='ACC:ProductCode'/>
<simpleType name='ProductCode' base='string'>
<pattern value='[A-Z]{1}d{6}'/>
</simpleType>
<element name='stickyGlue' type='PART:SuperGlueType'/>
|
リスト 5 には、さらにもう 1 つのネームスペースへの参照が加わっています。それはhttp://www.PartnerStore.com/PartsCatalog です。このネームスペースは、targetNamespace とも、標準ネームスペースとも異なります。結果として、それはimport 宣言エレメントを使用してインポートしなければならず、そのschemaLocation 属性は、スキーマを含むファイルのロケーションを指定します。デフォルトのネームスペースはhttp://www.w3.org/1999/XMLSchema であり、そのxmlns 宣言には短縮形の名前がありません。これによってschema やelement といった修飾なしの名前はすべて、デフォルトのネームスペースであるhttp://www.w3.org/1999/XMLSchema に属すことになります。スキーマで 1 つのネームスペースからの名前を複数参照している場合、それをデフォルトのネームスペースとして指定する方が便利です。
XML インスタンス文書で、複数のスキーマで定義された複数のネームスペースに属するエレメントの名前を参照することがあります。ネームスペースの名前を参照し、その名前の短縮形を宣言するためには、xmlns 宣言を使用します。XML スキーマ・インスタンスのネームスペースに属するschemaLocation 属性を使用して、ファイルのロケーションを指定します。この属性は、前述の例のxsd ネームスペースの 同じ名前の属性schemaLocation とは異なることに注意してください。
リスト 6: 複数のスキーマの複数のネームスペース名の使用
<?xml version="1.0"?>
<ACC:rootElement xmlns:ACC='http://www.SampleStore.com/Account'
xmlns:PART='http://www.PartnerStore.com/PartsCatalog'
xmlns:xsi='http://www.w3.org/1999/XMLSchema-instance'
xsi:schemaLocation='http://www.PartnerStore.com/PartsCatalog
http://www.ProductStandards.org/repository/alpha.xsd
http://www.SampleStore.com/Account
http://www.SampleStore.com/repository/schema1.xsd'>
<ACC:InvoiceNo>123456789</ACC:InvoiceNo>
|
図 2: リスト 5 および 6 のネームスペース
エレメントを定義するということは、その名前と内容モデルを定義することです。XML スキーマでは、エレメントの内容モデルはそのタイプ別に定義されます。それで、XML 文書内のインスタンス・エレメントは、そのスキーマで定義されているタイプに一致した値だけをとることができます。
タイプは単純か複合のいずれかです。単純タイプは、その値にエレメントや属性を含めることはできません。複合タイプでは、他のエレメント内の組み込みエレメントの効果を出したり、属性をエレメントに関連付けることができます。この記事の中のここまでの例は、ユーザーの定義した単純タイプです (ProductCode を参照)。XML スキーマ仕様には、事前に定義された単純タイプも含まれています (単純タイプの囲みを参照してください)。派生的単純タイプ は、基本タイプに値が限定されます。たとえば、派生的単純タイプであるProductCode の値は、基本タイプstring の値のサブセットになります。
属性や他のエレメントを含まないエレメントは、事前に定義された単純タイプまたはユーザー定義の単純タイプとして定義することができます。この例としては、string、integer、decimal、time、ProductCode などがあります。
リスト 7: エレメント用のいくつかの単純タイプ
<element name='age' type='integer'/>
<element name='price' type='decimal'/> |
さて、リスト 7 の単純エレメントprice に、属性currency を追加することは可能でしょうか。実はそれはできません。単純タイプのエレメントは属性を持つことができないのです。属性を追加したいなら、price を複合タイプとして定義しなければなりません。リスト 8 の例では、いわゆる無名タイプ と呼ばれるものを定義しました。この場合、複合タイプには明示的な名前が与えられていません。言い換えると、complexType エレメントのname 属性は定義されないということです。
リスト 8: 複合エレメント・タイプ
<element name='price'>
<complexType base='decimal' derivedBy='extension'>
<attribute name='currency' type='string'/>
</complexType>
</element>
<!-- In XML instance document, we can write: <price currency='US'>45.50</price> -->
|
他のエレメントを組み込んでいるエレメントは必ず複合タイプになる
XML 文書では、エレメントの下位に他のエレメントを含むことができます。この要件は DTD では直接的に表現されます。XML スキーマでは、代わりに type 属性を持つエレメントを定義し、その type 属性が他のエレメントや属性の宣言を指すようにすることができます。簡単な例として、表 1 をご覧ください。
| XML 文書 |
<Book>
|
| DTD |
<!ELEMENT Book (Title, Author)>
|
| XML スキーマ |
<element name='Book' type='BookType'/>
|
表 1 の XML コードは DTD と XML スキーマの両方に従っていますが、それらの間には大きな違いがあります。DTD ではすべてのエレメントがグローバルですが、表中の XML スキーマでは、Title とAuthor がローカルに定義されています。それらは、エレメントBook の中でのみ出現可能です。DTD の宣言の作用を XML スキーマで厳密に再現しようとすれば、リスト 9に示されているように、エレメントTitle とAuthor がグローバルな有効範囲を持つ必要があります。エレメントelement のref 属性により、すでに宣言されているエレメントを参照することが可能になります。
リスト 9: グローバルな単純タイプで定義された複合タイプ
<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book' type='BookType'/>
<complexType name='BookType'>
<element ref='Title'/>
<element ref='Author'/>
</complexType>
|
表 1 とリスト 9 の例では、BookType はグローバルであり、他のエレメントを宣言するために使用することができます。対称的に、リスト 10 では、このタイプはエレメントBook の定義に対してローカルなものとし、またそのタイプは無名です。表 1 の XML 文書は、表 1、リスト 9、およびリスト 10 の 3 つのスキーマすべてに一致していることに注目できます。
リスト 10:
BookType をローカル・タイプとして隠す
<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book'>
<complexType>
<element ref='Title'/>
<element ref='Author'/>
</complexType>
</element>
|
XML スキーマは、エレメントの内容モデルの制約を表現するために、DTD より優れた柔軟性を持っています。最も簡単なレベルでは、DTD の場合と同様に、属性をエレメント宣言に関連付けることができ、与えられたエレメントのセットから、1 回だけ (1)、0 回以上 (*)、または 1 回以上 (+)、エレメントの順序列がその中で出現できることを示すことができます。XML スキーマでは、さらに制約を表現する付加的な方法があります。たとえば、エレメントelement のminOccurs およびmaxOccurs 属性を使用したり、choice、group、およびall エレメントを使用することができます。
リスト 11: エレメント・タイプでの制約の表現
<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book'>
<complexType>
<element ref='Title' minOccurs='0'/>
<element ref='Author' maxOccurs='2'/>
</complexType>
</element>
|
リスト 11 では、
Book の中でのTitle の出現はオプションとなります (DTD の '?' と同じ)。しかし、リスト 11 ではさらに、エレメントBook の中で Author が少なくとも 1 回、そして 2 回を超えずに出現することを規定しています。minOccurs とmaxOccurs のデフォルト値は、element に対して 1 です。エレメントchoice は、そのエレメントの子要素が 1 つだけ、インスタンスの中で出現させる宣言です。別のエレメントall は、グループ内のすべての子要素が 1 回または 0 回、任意の順序で出現するという制約を表現する宣言です。リスト 12 は、Book の中でTitle とAuthor の両方が順序を問わず出現してもよく、どちらも出現しなくてもよいという制約を表現しています。このような制約を DTD で表現するのは困難です。
リスト 12: エレメントにすべてのタイプを定義する必要性を示す
<xsd:element name='Title' type='string'/>
<xsd:element name='Author' type='string'/>
<xsd:element name='Book'>
<xsd:complexType>
<xsd:all>
<xsd:element ref='Tile'/>
<xsd:element ref='Author'/>
</xsd:all>
</xsd:complexType>
</xsd:element>
|
ここまでで、XML スキーマでエレメントを定義するために必要な基礎的な概念を網羅し、簡単な例をとおしてその能力の一端を垣間見ました。さらに多くの強力なメカニズムが利用できます。
- XML スキーマには、タイプ継承に対する高度なサポートがあり、以前に定義された構造の再利用が可能です。いわゆるファセット を使用することにより、別のタイプの値のサブセットを表す新しいタイプを派生させることができます。たとえば、列挙、範囲指定、またはパターン・マッチングによって、サブセットを定義することができます。この記事の例では、
ProductCodeタイプはpatternファセットを使って定義されたものです。サブタイプにより、基本タイプにエレメント宣言や属性宣言をさらに追加することもできます。 - サブタイプをすべて定義できるのか、また特定の文書中でサブタイプを置換できるのかを、いくつかのメカニズムによって制御することができます。たとえば、
InvoiceType(送り状番号のタイプ) にはサブタイプができないことを表現できます。これはつまり、だれも新しいバージョンのInvoiceTypeを定義できないということです。さらに、特定の文脈において、ProductCodeタイプのサブタイプはいずれも置換できないことを表現できます。 - サブタイプは別として、等価性タイプを定義することができます。これは、あるタイプの値を別のタイプで置き換えることができるというものです。
- エレメントまたはタイプを抽象型として宣言することにより、XML スキーマはその置換を強制するためのメカニズムを提供します。
- 便宜上、属性およびエレメントのグループを定義して名前を付けることができます。グループを引き続き参照することで、再利用が可能になります。
- XML スキーマでは、スキーマに注釈を付けるための 3 つのエレメントを提供しています。それは、
appInfo、documentation、そしてannotationです。これらは、スキーマを読む人のため (documentation) と アプリケーションのため (appInfo) に用意されています。 - 子エレメントの特定の属性に基づく固有性制約を表現することができます。
W3C サイトの資料を通し (参考文献を参照)、また広範な情報を得るため dW の XML ゾーンを調べることにより、XML スキーマについて理解を深めてください。これまでに XML スキーマ仕様は、Candidate Recommendation に至るところまで承認が進んでおり、いっそう多くの人がそれを利用するようになることは間違いありません。
- XSV への無償のWeb 形式アクセス。XSV は University of Edinburgh/W3C (アルファ) による XML スキーマ検証プログラムです。
- Apache プロジェクトによる、無償でダウンロードできるXML スキーマ検証プログラム。
- Oracle による、無償でダウンロードできるXML スキーマ検証プログラム。これは 2000 年 2 月バージョンの XML スキーマに基づいています。
-
http://www.ibm.com/alphaworks による、無償でダウンロードできるツール。
- 2 部から成る XML スキーマの現行の W3C 仕様書。XML Schema Part 1: Structures およびXML Schema Part 2: Datatypes
Ashvin Radiya 氏は、 AvantSoft, Inc. の創設者であり、社長です。CTO として、最新の Java プログラミングおよび関連テクノロジーに関する AvantSoft トレーニング・コースの開発と普及に率先してきました。また、Fortune 100 の企業との戦略的提携を築き、その管理に携わっています。Ashvin 氏は、産業界、大学関係、そして専門分野についての幅広い経験を有しています。彼は オースチンの IBM において、先進的な CORBA ベースの分散型オブジェクト指向プロダクトの仕事に携わりました。モバイル・コマース、XML、Java、JavaBeans、Enterprise JavaBeans コンポーネント、InfoBus、セキュリティー、CORBA、および分散型オブジェクト指向プログラミングの分野で、高度な知識と専門技術を有しています。Ashvin 氏はシラキュース大学より、コンピューター・サイエンスの博士号を授与されました。Ashvin Radiya 氏の連絡先は、ashvin@avantsoft.com です。
Vibha Dixit 氏は、AvantSoft, Inc. において、ビジネス開発マネージャーおよび科学技術者としてかぎとなる役割を果たしています。彼女はビジネス計画、戦略的提携の管理、新規顧客の獲得、販売およびマーケティングの責任者です。また、モバイル・コマース、XML、および Java テクノロジーの分野における AvantSoft 社のテクノロジー目標と方向性の定義付けにも積極的に関与しています。Vibha 氏は、ビジネス管理におけるユニークな経験を持ち、コンピューター・テクノロジーにおいても強力な実務経験を有しています。AvantSoft 社に加わる以前は、IBM サンタ・テレサ研究所で分散トランザクション型オブジェクト・ミドルウェアの仕事に携わっていました。オハイオ・スーパーコンピューター・センターでは、マルチ・コンピューター用のオペレーティング・システムの設計と開発に参加しました。Vibha 氏はオハイオ州立大学より、コンピューター・サイエンスの博士号を授与されました。さらに、南部メソジスト大学で上級経営管理学修士課程を修了しています。Vibha Dixit 氏の連絡先は、vibha@avantsoft.com です。