川久保 智晴 [著] 2010/07/20 14:00

サンプルコード 4.77 KB

 筆者の記事でも何度かXMLを使用してきましたが、XMLの正しさを検査する手段を持っていませんでした。実際の業務で使用する場合、正しさを検査する手段がないXMLの操作は非常に扱いづらいものとなります。今回は、少し高度な話題にも触れ、実務に耐えうる力をつけることを目標にしたいと考えています。

1 2 3 →

W3C XML Schemaの少し高度な話題

 「今からでも遅くない」シリーズは、学習する機会を失ったけれどもまだ間に合うという技術を取り上げています。したがって、概要を知りたい方は前編を、業務でも使えるようになりたい方は後編を読むことにより習得できるように工夫してきました。前回は中編を挟み、W3C XML Schemaの読み書きが少しでもできることを目標としてきました。したがって、まだ業務でも使用できると言うほどには説明ができていません。このような経緯から、今回の後編では少し高度な話題を取り上げ、業務でも通用するようお役にたてればと考えています。

 中編で取り上げたTomcatのweb.xmlのXMLスキーマは、実はその少し高度な知識を必要とします。また、W3C XML Schemaは再利用するにはDTDよりも向いていると説明しましたが、実際に例をもって説明をしていないため煙に巻いた感を残したままになっています。これらの話題を含め、実際に複雑なXMLスキーマを記述できるようになるための足がかりを提供したいと思います。

重複した定義をなくす

 中編ではshop2.xmlを紹介しましたが、shop2.xmlは芋焼酎しか扱っていない店舗です。では、ワインを扱いたい場合にはどのようにXMLスキーマを作成すればいいのでしょうか。オープンソースApache Tuscanyで楽しむSOA 第3回「Web2.0から始めましょう(JSONRPC編)」でトスカーナワイン店という架空のネットショップを紹介しましたが、このショップのワインリストには、銘柄、銘柄(読み方)、ヴィンテージ、ランク、価格を明細として示しています。このうち、銘柄はMEIGARA要素、銘柄(読み方)はMEIGARA要素のKANA属性、価格はPRICE要素に置き換えることが可能です。ランクは芋焼酎にはない概念です。shop2.xmlでは芋焼酎しか扱っていませんでしたが、トスカーナワインも扱いたい場合、どのようなXML文書やXMLスキーマ文書を作成すればいいかは、前編中編を読んでも想像できません。このように重複する要素が存在する場合、同じ要素を繰り返して定義しても冗長になります。まずは冗長さ、つまり重複した要素の定義の仕方を学ぶ必要があります。

 それでは、芋焼酎とトスカーナワインを販売すると仮定した場合のXML文書の例から見ていきましょう。リスト1がその例で、shop3.xmlと命名します。

リスト1. shop3.xml
001:<?xml version="1.0" encoding="UTF-8"?>
002:<SHOP>
003:  <GREETING OWNER="tomoharu">店主の好みの芋焼酎を厳選しました。</GREETING>
004:  <MEIGARAS>
005:      <SHOCHU>
006:          <NAME KANA="ガンコショウチュウヤ">がんこ焼酎屋</NAME>
007:          <ABV UNIT="%">25</ABV><!-- alcohol by volume(アルコール度数)の略 -->
008:          <VOLUME UNIT="ml">1800</VOLUME>
009:          <PRICE UNIT="円">2630</PRICE>
010:          <MANUFACTURER>大石酒造</MANUFACTURER>
011:          <KOJI>白</KOJI>
012:      </SHOCHU>
013:      <WINE>
014:          <NAME KANA="ブルネッロ・ディ・モルタルチーノ">Brunello di Montalcino</NAME>
015:          <VINTAGE>2004</VINTAGE>
016:          <PRICE UNIT="円">10000</PRICE>
017:          <RANK>DOCG</RANK>
018:      </WINE>        
019:      <SHOCHU>
020:          <NAME KANA="キシンジュ">貴心樹</NAME>
021:          <ABV UNIT="%">25</ABV>
022:          <VOLUME UNIT="ml">1800</VOLUME>
023:          <PRICE UNIT="円">1724</PRICE>
024:          <MANUFACTURER>オガタマ酒造</MANUFACTURER>
025:          <KOJI>黒</KOJI>
026:      </SHOCHU>
027:      <SHOCHU>
028:          <NAME KANA="トウジジュンペイベニイモゲンシュ">杜氏潤平紅芋原酒</NAME>
029:          <ABV UNIT="%">38</ABV>
030:          <VOLUME UNIT="ml">500</VOLUME>
031:          <PRICE UNIT="円">2050</PRICE>
032:          <MANUFACTURER>小玉醸造</MANUFACTURER>
033:      </SHOCHU>
034:  </MEIGARAS>
035:</SHOP>

 shop2.xmlと異なる点は、MEIGARAS要素の子要素を、MEIGARAから芋焼酎の場合はSHOCHU要素、トスカーナワインの場合はWINE要素に変えているところです。芋焼酎とトスカーナワインに共通するNAME、ABV、VINTAGE、VOLUME、PRICE、MANUFACTURER要素を、各々の要素の子要素のはじめの方に持ってきています(これらの要素のうち、NAMEとPRICEだけを必須としています)。したがって、芋焼酎に特有なKOJI要素とトスカーナワイン特有のRANK要素はそれ以降に配置しています。また、NAME要素のKANA属性はカタカナとひらがなで統一がとれていないため、カタカナにしました。このXMLスキーマがリスト2のsample4.xsdになります。

リスト2. sample4.xsd
001:<?xml version="1.0" encoding="UTF-8"?>
002:<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
003:
004:<xsd:group name="meigaraGroup">
005:  <xsd:annotation>
006:      <xsd:documentation xml:lang="jp">
007:          このグループは芋焼酎とトスカーナワインに共通した
008:          要素を集めたもの。置換グループ(substitutionGroup)
009:          を使っても要素の塊を再利用することができる。
010:      </xsd:documentation>
011:  </xsd:annotation>
012:  <xsd:sequence>
013:      <xsd:element ref="NAME"/>
014:      <xsd:element ref="ABV" minOccurs="0" maxOccurs="1"/>
015:      <xsd:element ref="VINTAGE" minOccurs="0" maxOccurs="1"/>
016:      <xsd:element ref="VOLUME" minOccurs="0" maxOccurs="1"/>
017:      <xsd:element ref="PRICE"/>
018:      <xsd:element ref="MANUFACTURER" minOccurs="0" maxOccurs="1"/>
019:  </xsd:sequence>
020:</xsd:group>
021:
022:<xsd:element name="SHOP" type="ShopType"/>
023:
024:<xsd:complexType name="ShopType">
025:  <xsd:sequence>
026:      <xsd:element name="GREETING" type="GreetingType"/>
027:      <xsd:element name="MEIGARAS" type="MeigarasType"/>
028:  </xsd:sequence>
029:</xsd:complexType>
030:
031:<xsd:complexType name="GreetingType">
032:  <xsd:simpleContent>
033:      <xsd:extension base="xsd:string">
034:          <xsd:attribute name="OWNER" type="xsd:string" use="required"/>
035:      </xsd:extension>
036:  </xsd:simpleContent>
037:</xsd:complexType>
038:
039:<xsd:complexType name="MeigarasType">
040:  <xsd:choice minOccurs="0" maxOccurs="unbounded">
041:      <xsd:element name="SHOCHU" type="ShochuType"/>
042:      <xsd:element name="WINE" type="WineType"/>
043:  </xsd:choice>
044:</xsd:complexType>
045:
046:<xsd:complexType name="ShochuType">
047:  <xsd:sequence>
048:      <xsd:group ref="meigaraGroup"/>
049:      <xsd:element ref="KOJI" minOccurs="0" maxOccurs="1"/>
050:  </xsd:sequence>
051:</xsd:complexType>
052:
053:<xsd:complexType name="WineType">
054:  <xsd:sequence>
055:      <xsd:group ref="meigaraGroup"/>
056:      <xsd:element ref="RANK"/>
057:  </xsd:sequence>
058:</xsd:complexType>
059:
060:<xsd:element name="NAME" type="NameType"/>
061:<xsd:element name="ABV" type="ABVType"/>
062:<xsd:element name="KOJI" type="KojiType"/>
063:<xsd:element name="VOLUME" type="VolumeType"/>
064:<xsd:element name="PRICE" type="PriceType"/>
065:<xsd:element name="MANUFACTURER" type="xsd:string"/>
066:<xsd:element name="VINTAGE" type="VintageType"/>
067:<xsd:element name="RANK" type="RankType"/>
068:
069:<xsd:complexType name="NameType">
070:  <xsd:simpleContent>
071:      <xsd:extension base="xsd:string">
072:          <xsd:attribute name="KANA" type="xsd:string" use="required"/>
073:      </xsd:extension>
074:  </xsd:simpleContent>
075:</xsd:complexType>
076:
077:<xsd:complexType name="ABVType">
078:  <xsd:simpleContent>
079:      <xsd:extension base="xsd:positiveInteger">
080:          <xsd:attribute name="UNIT" type="xsd:string" fixed="%"/>
081:      </xsd:extension>
082:  </xsd:simpleContent>
083:</xsd:complexType>
084:
085:<xsd:simpleType name="KojiType">
086:  <xsd:restriction base="xsd:string">
087:      <xsd:enumeration value="白"/>
088:      <xsd:enumeration value="黒"/>
089:      <xsd:enumeration value="黄"/>
090:  </xsd:restriction>
091:</xsd:simpleType>
092:
093:<xsd:complexType name="VolumeType">
094:  <xsd:simpleContent>
095:      <xsd:extension base="xsd:positiveInteger">
096:          <xsd:attribute name="UNIT" type="xsd:string" fixed="ml"/>
097:      </xsd:extension>
098:  </xsd:simpleContent>
099:</xsd:complexType>
100:
101:<xsd:complexType name="PriceType">
102:  <xsd:simpleContent>
103:      <xsd:extension base="xsd:positiveInteger">
104:          <xsd:attribute name="UNIT" type="xsd:string" fixed="円"/>
105:      </xsd:extension>
106:  </xsd:simpleContent>
107:</xsd:complexType>
108:
109:<xsd:simpleType name="VintageType">
110:  <xsd:restriction base="xsd:positiveInteger">
111:      <xsd:minInclusive value="1900"/>
112:      <xsd:maxInclusive value="2099"/>
113:  </xsd:restriction>
114:</xsd:simpleType>
115:
116:<xsd:simpleType name="RankType">
117:  <xsd:restriction base="xsd:string">
118:      <xsd:enumeration value="DOC"/>
119:      <xsd:enumeration value="DOCG"/>
120:      <xsd:enumeration value="IGT"/>
121:      <xsd:enumeration value="スーパーIGT"/>
122:  </xsd:restriction>
123:</xsd:simpleType>
124:
125:</xsd:schema>

1 2 3
→
INDEX
今からでも遅くない W3C XML Schemaを学ぼう!(後編) 少し高度な話題を
Page1
W3C XML Schemaの少し高度な話題
重複した定義をなくす
XML文書とXMLスキーマ文書を関連付ける
データ型
おさらい
参考サイト
サンプルコード
プロフィール
川久保 智晴 カワクボ トモハル

COBOLで13年、Javaを中心としたWeb開発で11年。2つしか言語知らないのかというとそうでもなく、sed/awk、Perl、Pythonなども一時期は業務で使えるレベルまで達したと思っています(自己申告)。

最近はプロジェクトマネージャやソフトウェアアーキテクトという一見相容れない仕事を繰り返してきましたが、実は両者の技術は密接に絡んでいるというのが最近考えていることです。プロジェクトマネージャがあまりにも技術に疎かったり、ソフトウェアアーキテクトがあまりにもコストに鈍感であったりするのを見るにつけ思いが深まっています。

そういう会社員生活も2010年10月でピリオドを打ち、長年構想中のビジネスモデルをシステム化するために独立。2年後のビジネス化を目指しています。それまでの2年間はJavaを含めたプログラミング教室(http://www.programclass.com)で食いつなぐつもりです。2010年末時点で20名のJava教室の生徒さんがいます。Skypeを使っているので全国から問い合わせがあります。まだまだ募集していますので、気軽にメールを頂ければと思います。

以前はお酒が大好きでいろんなところに出没していましたが、今はおとなしく家飲みに徹しています。土日は20キロ近くジョギングしたりして爽やかなIT起業家となり雇用の創出に貢献できればと思っています。


記事へのコメント・トラックバック機能は2011年6月に廃止させていただきました。記事に対する反響はTwitterやFacebook、ソーシャルブックマークサービスのコメントなどでぜひお寄せください。

スポンサーサイト