XMLマスターポイントレッスン ~ ベーシック編 ~
第7回 XML Schemaのデータ型(後編)
インフォテリア認定教育センター 衣笠成一 KINUGASA, Seiichi
「XML Schema」も今回で最後の解説です。前回は、XML Schemaにおけるユーザー定義のデータ型である「単純型」の制限と拡張について解説しました。今回は、もう1つのユーザー定義のデータ型である「複合型」の拡張と制限について解説していきます。前回同様、ベーシックV2試験のセクション4「XML Schema」を攻略する上で必須の知識となりますので、しっかりと学習しておきましょう。
前回の復習
前回は、XML Schemaのデータ型にはあらかじめ定義された組み込み単純型があり、これらを拡張/制限したりしてユーザーが独自に新しい型を作ることができることを説明しました。XML Schemaのデータ型は、ユーザーが独自に定義できる「単純型」と「複合型」の2種類に分類できます。
単純型とは、XML 1.0で表現したときに文字列値のみを持つ型のことで、要素宣言や属性宣言で使用できます。XML Schema Part2では、組み込み単純型が用意されています。また、組み込み単純型に制限を設定して独自の単純型を作ることもできます。
一方の複合型とは、XML 1.0で表現したときに子要素や属性などの構造を持つ型のことで、要素宣言で使用できます。あらかじめ用意されている複合型はありませんので、ユーザーが独自に定義することになります。
●単純型の例
<xs:element name="所属" type="xs:string" />
この中で、「xs:string」と記述されている部分がXML Schemaの組み込み単純型です。ここでは、「名前が“所属”の要素は、データ型が文字列である」ことを定義しています。
●複合型の例
<xs:complexType name="EmployeeType">
<xs:sequence maxOccurs="unbounded">
<xs:element ref="名前" />
<xs:element ref="所属" />
</xs:sequence>
</xs:complexType>
<xs:element name="名前" type="xs:string" />
<xs:element name="所属" type="xs:string" />
この場合、complexType要素のname属性で型の名前「EmployeeType」を指定し、子要素にモデルグループ(子要素の出現順序を指定するもの)を指定しています。
この単純型や複合型を制限/拡張することで新しい型を作成(再利用)します。型の再利用方法については表にまとめておきましたので、はじめに確認しておいてください。
表:型の再利用の方法
基底型 | 再利用 | 新しい型 | 用途 |
単純型 | 制限(restriction) | 単純型(simpleType) | データ型に制限を加える |
---|---|---|---|
拡張(extension) | 複合型(complexType) | 単純型に属性を持たせる | |
複合型 | 制限(restriction) | 複合型(complexType) | 型の再利用 |
拡張(extension) | 複合型(complexType) | 型の再利用 |
複合型の拡張
複合型の拡張は、JavaやC++などのオブジェクト指向言語の継承機能とよく似ています。ベースとなる複合型のデータ型に、新たに要素宣言や属性宣言を追加できます。ただし、追加される要素はベースとなるデータ型の最後に追加され、また複合型を拡張した場合、そのデータ型は複合型となります。
前回同様、言葉だけではなかなか分かりにくいと思いますので、どのように複合型の拡張を定義するのかを次のような例で考えてみましょう。
- [1] 文字列型の名前要素と所属要素を持ち、出現順序は名前要素、所属要素となる複合型のEmpType型を作成する
- [2] EmpType 型をベースにして文字列型の電話要素、int型で必須の社員番号属性を追加した拡張型(ExtEmpType)を作成する
[1] の場合の定義方法
複合型を定義するには「complexType要素」を使用し、name属性に「EmpType」を指定します。
<xs:complexType name="EmpType">
:
</xs:complexType>
次に、子要素の出現順序を定義します。名前要素、所属要素の順番で出現させるには「sequence要素」を使用します。子要素の宣言は「element要素」のref属性を指定して、別の場所で宣言する要素宣言を参照するように定義します。
<xs:sequence>
<xs:element ref="名前" />
<xs:element ref="所属" />
</xs:sequence>
そして、最後に要素宣言を行ないます。
<xs:element name="名前" type="xs:string" />
<xs:element name="所属" type="xs:string" />
最終的なEmpType型はLIST1のようになります。
LIST1:EmpType 型の例
<xs:complexType name="EmpType">
<xs:sequence>
<xs:element ref="名前" />
<xs:element ref="所属" />
</xs:sequence>
</xs:complexType>
<xs:element name="名前" type="xs:string" />
<xs:element name="所属" type="xs:string" />
[2] の場合の定義方法
EmpType型という複合型をベースに電話要素と社員番号属性を追加しますので、複合型の拡張となります。
まず、complexType 要素を使用して、ExtEmpTypeをname属性で指定します。
<xs:complexType name="ExtEmpType">
:
</xs:complexType>
次に、complexType要素の子要素の内容が複合型であることを定義するために、「complexContent要素」を指定します。
<xs:complexContent>
:
</xs:complexContent>
続いて、拡張を表わす「extension要素」を記述し、base属性でベースになるデータ型を指定します。この例では、base属性に「EmpType」を指定します。
<xs:extension base="EmpType">
:
</xs:extension>
最後に、追加する電話要素と社員番号属性を定義します。属性を定義する場合、sequence要素やchoice要素などの子要素の定義(モデルグループ)の後に記述しなければなりません。
<xs:extension base="EmpType">
<xs:sequence>
<xs:element ref="電話" />
</xs:sequence>
<xs:attribute name="社員番号" type="xs:int" use="required" />
</xs:extension>
:
<xs:element name="電話" type="xs:string" />
最終的なExtEmpType型は図1のようになります。なお、ExtEmpType型の社員要素の宣言は次のとおりです。
<xs:element name="社員" type="ExtEmpType" />
複合型の拡張では、追加した宣言は最後に出現します。したがって、社員要素の子要素は名前要素、所属要素、電話要素の順番に記述しなければなりません。この定義における妥当なXML文書と妥当でないXML文書の例を図2に示します。
図2:XML文書の例(複合型の拡張)
●妥当なXML文書
〈名前〉岡村まさし〈/名前〉
〈所属〉設計部〈/所属〉
〈電話〉03-1452-4567〈/電話〉
〈/社員〉
●妥当でないXML文書
(名前、所属、電話要素の順番に記述されていない)
〈名前〉田中愛子〈/名前〉
〈電話〉03-6459-9864〈/電話〉
〈所属〉営業部〈/所属〉
〈/社員〉
●妥当でないXML文書
(社員番号属性がない)
〈名前〉香川たかし〈/名前〉
〈所属〉人事部〈/所属〉
〈電話〉07-5432-9876〈/電話〉
〈/社員〉
複合型の制限
複合型は、次のような制限を加えることで新しいデータ型を作成できます。複合型を制限した場合、そのデータ型は複合型となります。
- 要素の出現回数を変更(制限)する
- 要素や属性で使用されている単純型の値の範囲を狭める
- 属性の出現制約を変更(制限)する
こちらも、次のような例で見てみましょう。
[1] 次の複合型のUserType型を作成する
- 文字列型の名前要素、電話要素、メール要素がこの順番で出現する
- 各要素の出現回数は名前要素、メール要素が1回、電話要素が1回から3回までとする
- date型の更新日属性を持ち、省略可能とする
[2] UserType型から次の制約をかけたSimpleUserType型を作成する
- 電話要素の出現回数は1回のみとする
- 更新日属性の記述を必須入力とする
[1] の場合の定義方法
前述の複合型の定義と同様に、complexType要素とsequence要素を使用してUserType型を作成します。出現回数は、element要素の「minOccurs属性」と「maxOccurs属性」で指定します。この2つの属性のデフォルト値は1ですので、出現回数が1回の場合は省略できますが、この例では電話要素の出現回数が1回から3回までとなっているためmaxOccurs属性に「3」を記述します。完成したUserType型はLIST2のようになります。
LIST2:UserType型の例
<xs:complexType name="UserType">
<xs:sequence>
<xs:element ref="名前" />
<xs:element ref="電話" maxOccurs="3"/>
<xs:element ref="メール" />
</xs:sequence>
<xs:attribute name="更新日" type="xs:date" use="optional" />
</xs:complexType>
<xs:element name="名前" type="xs:string" />
<xs:element name="電話" type="xs:string" />
<xs:element name="メール" type="xs:string" />
[2] UserType型から制約をかけたSimpleUserType 型の作成
[1]の例では、UserType型という複合型に電話要素の出現回数の制限と更新日属性の出現制約の変更を行ないます。
まず、complexType 要素を使用して、SimpleUserTypeをname属性で指定します。
<xs:complexType name="SimpleUserType">
:
</xs:complexType>
次に、complexType要素の子要素の内容が複合型であることを定義するためにcomplexContent要素を指定します。
<xs:complexContent>
:
</xs:complexContent>
続いて、制限を表わす「restriction要素」を記述し、base属性でベースになるデータ型を指定します。
<xs:restriction base="UserType">
:
</xs:restriction>
最後に、ベースとなるデータ型の内容に記述した定義をすべて記述し、制限をかける内容を次のように記述します。
- 要素の出現回数を制限する場合、maxOccurs、minOccurs属性で出現回数を制限する
- 属性の記述を必須入力に変更する場合、use属性の値を「required(必須)」に変更する完成したSimpleUserType型は図3のようになります。
なお、SimpleUserType型のユーザー情報要素の宣言は次のとおりです。
<xs:element name="ユーザー情報" type="SimpleUserType" />
この結果、この定義における妥当なXML文書と妥当でないXML文書の例は図4のようになります。
図4:XML文書の例(複合型の制限)
●妥当なXML文書
〈名前〉山本一郎〈/名前〉
〈電話〉03-1452-4567〈/電話〉
〈メール〉yama@abc.gr.jp〈/メール〉
〈/ユーザー情報〉
●妥当でないXML文書
(電話要素が複数記述されている)
〈名前〉武田昭彦〈/名前〉
〈電話〉03-1452-4567〈/電話〉
〈電話〉06-5412-7654〈/電話〉
〈メール〉takeda@abc.gr.jp〈/メール〉
〈/ユーザー情報〉
●妥当でないXML文書
(更新日属性が記述されていない)
〈名前〉青木美夏〈/名前〉
〈電話〉03-9976-9876〈/電話〉
〈メール〉mika@abc.gr.jp〈/メール〉
〈/ユーザー情報〉
実際に型を再利用する方法
前回から2回にわたって、単純型と複合型の再利用方法について説明しましたが、実際に型の再利用を行なう場合、ベースで指定した型を別ファイルにしてそのファイルを<xs:include>、<xs:import>で取り込み、新しい型を作成する方法がよく使用されます。
- <xs:include>:同じ名前空間または名前空間のないXML Schemaファイルを取り込む
- <xs:import>:違う名前空間のファイルをXML Schemaファイルを取り込む
この方法により、頻繁に使用されるカスタムのデータ型を外部スキーマとして別ファイル化しておけるので、より保守性に富んだスキーマを記述できます。
実際に<xs:include>した例が図5です。また、<xs:import>を使用して業界標準の多分野のXML Schemaファイル(この場合、名前空間が異なっている)を取り込んで使用することも可能です。
なお、<xs:include>、<xs:import>はベーシック試験の範囲ではありませんが、ぜひ覚えておいていただきたい知識ですので紹介しました。
今月の確認問題
さて、ここまでXML Schemaのデータ型として、複合型の拡張と制限について解説してきました。ここで、今回解説した内容が理解できたかどうかを、確認問題で試してみましょう。
問題1
次のXML Schema文書に対して、妥当なXML文書を2つ選択してください。
<?xml version="1.0" encoding="Shift_JIS" ?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="顧客情報" type="CustomerType" />
<xs:complexType name="InfoType">
<xs:sequence>
<xs:choice>
<xs:sequence>
<xs:element ref="姓" />
<xs:element ref="名" />
</xs:sequence>
<xs:sequence>
<xs:element ref="LastName" />
<xs:element ref="FirstName" />
</xs:sequence>
</xs:choice>
</xs:complexType>
<xs:complexType name="CustomerType">
<xs:complexContent>
<xs:extension base=“InfoType">
<xs:choice>
<xs:element ref="電話" />
<xs:element ref="携帯" />
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="姓" type="xs:string" />
<xs:element name="名" type="xs:string" />
<xs:element name="LastName" type="xs:string" />
<xs:element name="FirstName" type="xs:string" />
<xs:element name="電話" type="xs:string" />
<xs:element name="携帯" type="xs:string" />
</xs:schema>
- <?xml version="1.0" encoding="Shift_JIS"?>
<顧客情報>
<LastName>masashi</LastName>
<FirstName>okamura</FirstName>
<携帯>090-9231-3678</携帯>
<携帯>090-6345-6989</携帯>
</顧客情報> - <?xml version="1.0" encoding="Shift_JIS"?>
<顧客情報>
<LastName>masashi</LastName>
<FirstName>okamura</FirstName>
<携帯>090-9231-3678</携帯>
</顧客情報> - <?xml version="1.0" encoding="Shift_JIS"?>
<顧客情報>
<姓>岡村</姓>
<名>まさし</名>
<電話>03-0001-6789</電話>
</顧客情報> - <?xml version="1.0" encoding="Shift_JIS"?>
<顧客情報>
<姓>岡村</姓>
<名>まさし</名>
<LastName>masahi</LastName>
<FirstName>okamura</FirstName>
<電話>03-0001-6789</電話>
<携帯>090-9231-3678</携帯>
</顧客情報>
解説
複合型の拡張の問題です。問題で指定されているXML Schema文書を見ると、次のような定義が読み取れると
思います。
- ルート要素は顧客情報要素
- 姓要素、名要素の順番で出現する
- LastName要素、FirstName要素の順番で出現する
- 姓要素、名要素の組み合わせとLastName要素、FirstName要素の組み合わせは、いずれか一方が出現する
- 電話要素と携帯要素は、いずれか一方が1回出現する
したがって、上記の条件を満たしたXML文書だけが妥当なXML文書となります。Aは「携帯」要素が2回出現していますので妥当なXML文書ではありません。B、Cは上記の条件を満たしているので妥当なXML文書です。DはXML Schema文書内で定義されている要素がすべて出現していますので妥当なXML文書ではありません。よって、正解はBとCです。
問題2
次のXML 文書の構造を正しく定義するためにXML Schema文書の(1)に記述するべきものとして正しいものを選択してください。ただし、くだもの要素の産地属性は必須とします。
[XML文書]
<?xml version="1.0" encoding="Shift_JIS"?>
<くだもの 産地="青森">
<名前>リンゴ</名前>
<値段>350</値段>
</くだもの>
[XML Schema文書]
<?xml version="1.0" encoding="Shift_JIS" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="くだもの" type="fruitType" />
<xs:complexType name="baseType">
<xs:sequence>
<xs:element ref="名前" />
</xs:sequence>
</xs:complexType>
<xs:element name="名前" type="xs:string" />
<xs:element name="値段" type="xs:integer" />
</xs:schema>
- <xs:complexType name="fruitType">
<xs:complexContent>
<xs:restriction base="baseType">
<xs:sequence>
<xs:element ref="値段" />
</xs:sequence>
<xs:attribute name="産地"
type="xs:string" use="required" />
</xs:restriction>
</xs:complexContent>
</xs:complexType> - <xs:complexType name="fruitType">
<xs:complexContent>
<xs:extension base="baseType">
<xs:sequence>
<xs:element ref="値段" />
</xs:sequence>
<xs:attribute name="産地"
type="xs:string" use="required" />
</xs:extension>
</xs:complexContent>
</xs:complexType> - <xs:complexType name="fruitType">
<xs:simpleContent>
<xs:extension base="baseType">
<xs:sequence>
<xs:element ref="値段" />
</xs:sequence>
<xs:attribute name="産地"
type="xs:string" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType> - <xs:complexType name="fruitType">
<xs:simpleContent>
<xs:restriction base="baseType">
<xs:sequence>
<xs:element ref="値段" />
</xs:sequence>
<xs:attribute name="産地"
type="xs:string" use="required" />
</xs:restriction>
</xs:simpleContent>
</xs:complexType>
解説
XML文書には、くだもの要素に産地属性、くだもの要素の子要素に名前要素と値段要素があります。XML Schema文書には、くだもの要素はfruitType型で、名前要素だけを持つbaseType型が定義されています。
したがって、解答としてはbaseType型をベースに文字列型の値段要素と産地属性を追加したfruitType型を定義すれば良いのです。複合型の拡張の構文は次のようになります。
<xs:complexType name="新しい型">
<xs:complexContent>
<xs:extension base="ベースとなる型">
モデルグループの指定
属性の指定
</xs:extension>
</xs:complexContent>
</xs:complexType>
この構文を基に、各選択肢を見ていきます。AはcomplexContent要素で内容が複合型であることを定義しており、restriction要素は複合型の制限を定義しますので誤りです。また、元々baseType属性には産地属性がありませんので、妥当性検証時にエラーとなります。BはcomplexContent要素で内容が複合型であることを定義しており、extension要素は複合型の拡張を定義しますので正解です。C、DはsimpleContent要素で内容が単純型であることを定義しますので誤りとなります。よって、正解はBです。
* * *
今回は、XML Schemaにおけるユーザー定義のデータ型を中心に、複合型の拡張と制限について解説しました。複合型を定義/再利用する場合はcomplexType要素を、子要素の内容が複合型である場合はcomplexContent要素を使うこと、複合型と単純型の制限と拡張の違いについてもしっかりと理解しておきましょう。実際にXML Schema文書とXML文書を作成し、妥当性検証を行なうことでさらに理解を深めることができると思います。次回は、XMLファイル変換の仕様である「XSLT」について解説します。
衣笠成一(きぬがさせいいち)
日本ヒューレット・パッカード株式会社HP教育サービス勤務。現在、インフォテリア認定トレーナーとしてXMLトレーニングコースを担当するとともに、大規模Web開発支援コースを含めたITプロフェショナル人材育成プログラムなどにおいて、技術サポートおよびトレーナー支援を行なっている。次回からは別な執筆者にバトンタッチするため私の担当は今回が最後になりますが、またいつかDBマガジンの連載を担当したいと思っています。
<掲載> P.190-194 DB Magazine 2006 August