W3C XML Schemaの読み書き能力
XMLの理解の深浅により、ある技術の理解の深浅も大きな影響を受ける場合があります。例えばTomcatというアプリケーションサーバを使いこなすには、server.xmlやweb.xmlの理解が必須です。Tomcat5.5のweb.xmlの最上位要素はリスト1のような宣言になっています。
001:<web-app xmlns="http://java.sun.com/xml/ns/j2ee" 002: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 003: xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 004: version="2.4">
この宣言を見ただけでも難しそうに感じます。しかし、どうやらweb-app_2_4.xsdがweb.xmlのXMLスキーマだということだけは分かります。記述方法が分からない場合、このXMLスキーマを見ればよさそうです。http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsdをクリックすると、web-app_2_4.xsdの内容がブラウザに表示されます。リスト2がその冒頭の抜粋です。
001:<?xml version="1.0" encoding="UTF-8"?> 002:<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" 003: targetNamespace="http://java.sun.com/xml/ns/j2ee" 004: xmlns:j2ee="http://java.sun.com/xml/ns/j2ee" 005: xmlns:xsd="http://www.w3.org/2001/XMLSchema" 006: elementFormDefault="qualified" 007: attributeFormDefault="unqualified" 008: version="2.4"> 009: <xsd:annotation> 010: <xsd:documentation> 011: @(#)web-app_2_4.xsds 1.61 04/04/16 012: </xsd:documentation> 013: </xsd:annotation>
最上位要素のxsd:schemaを見ただけでも、web.xmlより理解するのが困難に思えます。ただし、これらの理解なくしてXMLの理解は深まりません。本連載を読み終えるときにはこれらが理解できるようになっているはずですが、実は最上位要素の定義が1番難しいと言えます。まずはW3C XML Schemaを読めるようになることが大切です。
読むだけでも大変なのに、書くのはとんでもないという方も多いかと思います。しかし、言語は読み書きを同時に進めた方が、理解する速度は読むことに専念するよりも格段に速くなります。最初は簡単なXMLスキーマを書くことから始め、要素の制限や拡張の仕方を覚え、他のスキーマのimportやincludeの仕方を覚えたりしつつ上達していけばいいでしょう。いきなりXMLスキーマを完璧に書けるようになるのは天才以外いないと思うので、最初の一歩が必要です。
前回のXMLスキーマの書き換えから
前回はMeigara2.xmlというXML文書の妥当性をsample1.xsdというXMLスキーマ文書で検証しました。リスト3がMeigara2.xml、リスト4がsample1.xsdです。
001:<?xml version="1.0" encoding="UTF-8"?> 002:<MEIGARAS> 003: <MEIGARA> 004: <NAME>がんご焼酎屋</NAME> 005: <ABV>25</ABV><!-- alcohol by volume(アルコール度数)の略 --> 006: <VOLUME>1800</VOLUME> 007: <PRICE>2630</PRICE> 008: </MEIGARA> 009: <MEIGARA> 010: <NAME>一壺春</NAME> 011: <ABV>25</ABV> 012: <VOLUME>720</VOLUME> 013: <PRICE>1360</PRICE> 014: </MEIGARA> 015: <MEIGARA> 016: <NAME>杜氏潤平紅芋原酒</NAME> 017: <ABV>38</ABV> 018: <VOLUME>500</VOLUME> 019: <PRICE>2050</PRICE> 020: </MEIGARA> 021:</MEIGARAS>
001:<?xml version="1.0" encoding="UTF-8"?> 002:<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 003: 004:<xsd:element name="MEIGARAS"> 005: <xsd:complexType> 006: <xsd:sequence> 007: <xsd:element name="MEIGARA" minOccurs="0" maxOccurs="unbounded"> 008: <xsd:complexType> 009: <xsd:sequence> 010: <xsd:element name="NAME" type="xsd:string"/> 011: <xsd:element name="ABV" type="xsd:int"/> 012: <xsd:element name="VOLUME" type="xsd:int"/> 013: <xsd:element name="PRICE" type="xsd:int"/> 014: </xsd:sequence> 015: </xsd:complexType> 016: </xsd:element> 017: </xsd:sequence> 018: </xsd:complexType> 019:</xsd:element> 020: 021:</xsd:schema>
W3C XML Schemaの説明をほとんどすることなく妥当性検証を行ったため、sample1.xsdの理解のないままで前回は終わりました。今回はsample1.xsdの説明をし、それを分かりやすいように書き換えます。
sample1.xsdの説明
sample1.xsdは省略した記法を用いたため、XMLスキーマの構造が見えにくくなっています。また省略したことによって、再利用性が低いものとなっています。では、基本に立ち返りsample1.xsdを説明します。
- 2行目:W3C XML Schema自身の名前空間宣言です。前回は接頭辞をxsとしましたが、今回はxsdです。内容に違いはありません。名前空間である「
http://www.w3.org/2001/XMLSchema
」さえ同じであれば、それは同じものを指します。従って「xmlns:xsd="http://www.sample/XMLSchema
」と宣言すれば、それはW3C XML Schemaとはまったく異なる名前空間となります。 - 5行目:complexTypeとは複合型と呼ばれます。complexTypeの他にはsimpleTypeと呼ばれる型も存在します。まずはこの違いを理解することが大切です。simpleTypeは単純型と呼ばれます。単純型とは要素内容がテキストのみで属性を持たない型を指します。よくある間違いは空要素です。空要素は要素内容を持たないため単純型ではありません。「単純」という日本語の持つイメージからすれば空要素は「単純」そのものですが、単純型ではありません。あくまでもテキストのみ持つものを単純型と呼び、単純型でないものが複合型です。
- 6行目:sequenceとはモデルグループ・スキーマコンポーネントの1種です。その他、all、choiceがあります。これらは要素の出現の仕方を定義するものです。sequenceとは指定された順序で出現することを定義します。10行目から13行目の要素がその順番で出現することを定義しています。この例では、NAME、ABV、VOLUME、PRICEの順番で出現することを示しています。従って、NAME、VOLUME、ABV、PRICEやABV、NAME、PRICE、VOLUMEで出現する要素は妥当でないとみなされます。choiceはその子要素のいずれかが出現することを定義します。sample1.xsdの例で、sequenceの替わりにchoiceを指定した場合、NAME、ABV、VOLUME、PRICEのいずれか1つが出現することを示します。allは順序に関係なく要素が出現することを定義します。sample1.xsdの例で、sequenceの替わりにallを指定した場合、ABV、PRICE、VOLUME、NAMEなどの出現を許します。ただし、allの子要素は要素だけに限定されます。
- 5、8行目:xsd:complexTypeは型の定義を行っています。しかし、型に名前がありません。このような定義を「名前を持たない型の定義」と呼びます。Meigara2.xmlのような簡単なXML文書のスキーマを表現するには非常に簡潔な表現になり便利です。ただし、複雑なXML文書を扱う場合、型に名前を与える場合がほとんどです。再利用を考えると型に名前を付けることをお薦めします。
sample1.xsdを再利用しやすい記法に書き換える
上記の再利用という観点から、型に名前のない状態から名前のある状態に書き換えます。リスト5が書き換え後のXMLスキーマであるsample2.xsdです。
001:<?xml version="1.0" encoding="UTF-8"?> 002:<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 003: 004:<xsd:element name="MEIGARAS" type="MeigarasType"/> 005: 006:<xsd:complexType name="MeigarasType"> 007: <xsd:sequence> 008: <xsd:element name="MEIGARA" type="MeigaraType" minOccurs="0" maxOccurs="unbounded"/> 009: </xsd:sequence> 010:</xsd:complexType> 011: 012:<xsd:complexType name="MeigaraType"> 013: <xsd:sequence> 014: <xsd:element ref="NAME"/> 015: <xsd:element ref="ABV"/> 016: <xsd:element ref="VOLUME"/> 017: <xsd:element ref="PRICE"/> 018: </xsd:sequence> 019:</xsd:complexType> 020: 021:<xsd:element name="NAME" type="xsd:string"/> 022:<xsd:element name="ABV" type="ABVType"/> 023:<xsd:element name="VOLUME" type="xsd:positiveInteger"/> 024:<xsd:element name="PRICE" type="xsd:positiveInteger"/> 025: 026:<xsd:simpleType name="ABVType"> 027: <xsd:restriction base="xsd:positiveInteger"> 028: <xsd:minInclusive value="1"/> 029: <xsd:maxInclusive value="99"/> 030: </xsd:restriction> 031:</xsd:simpleType> 032: 033:</xsd:schema>
新たな概念
sample2.xsdはsample1.xsdと比較すると可読性に欠けると感じるかもしれませんが、ひとつひとつ整理していくとかえって読みやすいと感じるはずです。
宣言と定義
宣言(declaration)と定義(definition)の区別ができれば可読性の高いXMLスキーマを作ることができるようになります。宣言とは4、8、14~17、21~24の部分を指します。sample2.xsdには属性が存在しませんから、この場合要素名を宣言しています。定義とは宣言においてtypeで指定した部分を指します。この例では、6~10、12~19、26~31の部分を指します。見ての通り要素内の構成やデータ型(後述)を示しています。
制限
データ型にはW3C XML Schemaに組み込まれたデータ型が存在します。23、24行目がビルトインデータ型(組み込まれた型)と呼ばれるものです。この場合、VOLUME(容量)やPRICE(価格)は0以上の値を取るため、xsd:positiveIntegerという型を指定しています。容量も価格も上限はあるのですが、特に上限の値を指定しなくてもいいような場合はpositiveIntegerで済みます。それではABV(アルコール度数)の場合はどうでしょうか。アルコール度数が0というのは、アルコールという概念と矛盾するためありえません。また100という値も単なるエタノールに過ぎなくなるため酒店での販売には向いていません。このような場合、26~31行目のようにsimpleType内において制限を加えます。制限を加えるにはrestriction要素を使用します。その中のbase属性が制限を加える対象となります。アルコール度数は正の整数であるためpositiveIntegerを指定します。
これに対し上限と下限を設定しているのが28行目と29行目です。minInclusiveの場合、その値を含みます。minExclusiveと指定するとその値を含みません。maxInclusiveも同様でその値を含み、maxExclusiveと指定するとその値を含みません。このように制限を使用することにより、より正確な値のチェックを行うことが可能となります。
参照
14行目~17行目でデータ型を指定せず、ref属性を使用して、21行目~24行目を参照しています。これも簡単なXML文書では意味のないもののように思えます。直接、型を指定しても済みます。ただし、要素の型は出来るだけschema要素の子要素として宣言することをお薦めします。後で紹介しますが、同じ要素を再利用する場合に便利です。