レベル: 中級 Stephen B Morris, CTO, Omey Communications
2009年 6月 09日 更新 2009年 7月 07日 XML のオプション要素 (オンライン・フォームなどに見られます) は、XML ファイル内に現れることもあれば、現れないこともあるという点で特殊です。このようなオプション要素はプログラミング言語でも、データベースでも、簡単には表現できません。大抵は NULL 値をデータベースに挿入して空のオプション要素を表しますが、データベースから NULL の XML 値を取得するのが困難なこともあります。この記事では、XML のオプション要素を処理する方法として、データを多重定義したり、NULL 値やその他の標識値を挿入したりする必要がなく、他への影響の少ない方法を学んでください。
ストレージのコスト・パフォーマンスが向上したことにより、今やデータを捨てる必要は一切なくなりました。しかしその結果、データが山のように増えてきてデータを管理する必要が生じてきました。技術には、(オープンソースも含め) 完全に無料で済むものはないのです。山のようなデータを管理しなければならないという問題は、ストレージを大量に使用する一部のユーザーに影響を及ぼし始めているに過ぎませんが、大量にデータを扱うサービス・プロバイダーの組織には、この問題がかねてから付きまとっています。そこで、この記事ではリレーショナル・データ管理の問題、具体的に言うと XML データ管理の問題に目を向けます。
 |
よく使われる頭字語
- JAR: Java Archive
- XML: Extensible Markup Language
- XSD: XML Schema Infoset Model
|
|
データを管理するには、バックアップとリストア、データベース設計、そしてサービス・プロバイダーの選択といった、さまざまな分野での特定のスキルが必要になります。例えば、バックアップは毎日行うべきか、データベースにはどの設計方式を採用するべきか、自然キーまたはアプリケーションが生成する主キーのどちらを使うべきか、サービス・プロバイダーの場合はデータをリモートとオンサイトのどちらで保管するか、などの質問に答えられなければなりません。
これらの質問はいずれも重要ですが、この記事ではデータ設計、データの取得、そしてクライアント・コードの管理に重要な影響を及ぼす 1 つの具体的な問題に目を向けます。それは、リレーショナル・データベースで XML のオプション要素を表現するという問題です。この後わかるように、XML のオプション要素のモデル化に採用するソリューションは広範囲にわたって影響を及ぼします。
この記事で説明する内容
この記事ではさまざまな技術を取り上げます。どのように話が進められるのかを明らかにするため、説明する内容を順に紹介します。
- XSD と XML の概要
- JAXB (Java Architecture for XML Binding) による XML と Java™ の 2 つの世界の架け橋
- 単純なエンジンによる Java クラス・データのパブリッシュ
- データベース・エンティティー・クラス
- XML のオプション・データの問題の解決
それでは、まずはデータ定義から取り掛かります。
XSD での XML のオプション要素
リスト 1 に記載する XSD 文書の抜粋では、comment というオプション要素を指定しています。この XSD 文書が定義しているのは注文書です。ビジネス・オブジェクトと呼ばれることの多い、このような注文書については、アプリケーション・ドメインの重要なエンティティーであるとみなすことができます。言い換えると、システムのユーザーが注文書を作成したり、既存の注文書を変更したりする等の作業を行う場合、通常はこのようなビジネス・オブジェクトを操作することになります。重要な点は、リスト 1が典型的なビジネス・オブジェクトをモデル化するための出発点を表しているということです。
リスト 1. オプション要素が含まれる XSD の型定義
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:element name="shipTo" type="EuropeanAddress"/>
<xsd:element name="billTo" type="EuropeanAddress"/>
<xsd:element ref="comment" minOccurs="0"/>
<xsd:element name="items" type="Items"/>
</xsd:sequence>
<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
|
XSD のコンテキストでは、XML のオプション要素とは何のことを指すのでしょうか。その答えは、オプション要素とは単に、関連する XML 文書に出現しないこともあれば、何回か出現することもある要素です。XSD 文書と XML 文書の関係について考える必要はありません。XSD は、XML 文書に現れる構造と型を定義するためのフォーマットに過ぎないからです。基本的に、リスト 1 のそれぞれの xsd:element が XML 文書内の項目を対象としたプレースホルダーを定義します。次はより具体的な説明として、もう 1 つの技術、JAXB について紹介します。
JAXB: XML と Java 技術を結ぶ架け橋
XML を現代のコンピューティングにおける共通語と呼んでも議論を招くことはありませんが、XML そのものだけでは持て余すほど大きく、読みやすいフォーマットでもありません。そこで、例えば XML を Java コードに変換できたとしたら理想的だと思いませんか?幸い、この変換を可能にする方法はいくつかあります。そのうちの 1 つが、これから取り上げる JAXB です。
JAXB は XSD ファイルをサンプル XML ファイルと併せて使用することによって Java クラスを生成し、生成された Java クラスが XSD 要素を表します。難解に聞こえるかもしれませんが、難しいことではありません。次のセクションでは完全な変換の例を説明しますが、この手順に従うには Sun Microsystems Java Web Services Developer Pack (「参考文献」を参照) をインストールする必要があります。この記事で使用したのはバージョン 2.0 です。
手順に従ってインストールを行いますが、%JAVA_HOME%\jre\lib\endorsed という名前のディレクトリーを作成して、そこに JAR ファイルをコピーするステップについては特に慎重に行ってください。このステップは、Java ソフトウェア開発キット (JDK) バージョン1.5.x にビルドされる JAXB クラスをオーバーライドするために必要です。
XML の Java コードへの変換
リスト 2 に記載する XML ファイルは、リスト 1 の XSD 文書をインスタンス化したものだと考えてください。
リスト 2. XML 文書の例
<?xml version="1.0"?>
<purchaseOrder orderDate="1999-10-20">
<shipTo country="IE">
<name>Alice Smith</name>
<street>123 Maple Street</street>
<city>Cambridge</city>
<postcode>12345</postcode>
</shipTo>
<billTo country="IE">
<name>Robert Smith</name>
<street>8 Oak Avenue</street>
<city>Cambridge</city>
<postcode>12345</postcode>
</billTo>
<items>
<item partNum="242-NO" >
<productName>Nosferatu - Special Edition (1929)</productName>
<quantity>5</quantity>
<USPrice>19.99</USPrice>
</item>
<item partNum="242-MU" >
<productName>The Mummy (1959)</productName>
<quantity>3</quantity>
<USPrice>19.98</USPrice>
</item>
<item partNum="242-GZ" >
<productName>Godzilla and Mothra: Battle for Earth
/Godzilla versus
King Ghidora</productName>
<quantity>3</quantity>
<USPrice>27.95</USPrice>
</item>
</items>
</purchaseOrder>
|
ここでの問題は単純で、それは、リスト 2 の内容を一連の関連 Java クラスに変換することです。この変換プロセスは、JAXB と Apache Ant を使用すれば至って簡単に行えます。
ant compile -Djwsdp.home=C:\Sun\jwsdp-2.0
|
上記のコマンドによって、新しいフォルダーと Java クラス・ファイルが作成されます。新規に作成される Java クラスは、XSD ファイル内の要素に関連しています。次は、これらのクラスが機能するようにします。
単純なエンジンによる Java クラス・データのパブリッシュ
まず必要なのは、生成されたクラスを 1 つの単純なプログラムにまとめることです。リスト 3 に、プログラムの重要な部分を記載します。このプログラムは、Java Web Services Developer Pack にバンドルされているサンプルの 1 つに変更を加えたものです。
リスト 3. JAXB プログラム
JAXBElement<?> poElement =
(JAXBElement<?>)u.unmarshal(new FileInputStream("po.xml"));
PurchaseOrderType po = (PurchaseOrderType)poElement.getValue();
// examine some of the content in the PurchaseOrder
System.out.println("Ship the following items to: ");
// display the shipping address
EuropeanAddress address = po.getShipTo();
displayAddress(address);
// display the items
Items items = po.getItems();
displayItems(items);
|
リスト 3 では、po.xml という XML ファイルをアンマーシャリングして、PurchaseOrderType というクラスのインスタンスにしています。次に、このクラスを詳しく調べて、構成要素を抽出します。この作業はすべて、JAXB が生成したクラスを使って行います。自動生成されたクラスを使用するには、以下のようにします。
ant run -Djwsdp.home=C:\Sun\jwsdp-2.0
|
リスト 4 に、このコマンドによるプログラムの出力を記載します。
リスト 4. 変換とプログラムの出力
ant run -Djwsdp.home=C:\Sun\jwsdp-2.0
compile:
[echo] Compiling the schema...
[xjc] C:\java\ibmcode\unmarshal-read\gen-src\primer.po is not found and thus
excluded from the dependency check
[xjc] Compiling file:/C:/java/ibmcode/unmarshal-read/po.xsd
[xjc] Writing output to C:\java\ibmcode\unmarshal-read\gen-src
[echo] Compiling the java source files...
[javac] Compiling 4 source files to C:\java\ibmcode\unmarshal-read\classes
run:
[echo] Running the sample application...
[java] Ship the following items to:
[java] Alice Smith
[java] 123 Maple Street
[java] Cambridge null
[java] IE
[java]
[java] 5 copies of "Nosferatu - Special Edition (1929)"
[java] 3 copies of "The Mummy (1959)"
[java] 3 copies of "Godzilla and Mothra: Battle for Earth/Godzilla versus
King Ghidora"
BUILD SUCCESSFUL
Total time: 9 seconds
|
リスト 4 では、JAXB を利用してリスト 2 のデータをどのように再現するかに注目してください。
これで、ドメイン・データを XSD ファイルと XML ファイルのペアで表現することができました。ここではまず、XSD ファイルを JAXB と併せて使用して、関連する Java クラスを作成しました。そして単純な Java プログラムを使って、生成されたクラスと XML ファイルを操作して、XML ファイルの内容を表示しました。次に必要となる作業は一体何でしょう。
XSD ファイルを振り返ってみると、XML のオプション・データも生成されています。そこで次のステップでは、XML データをリレーショナル・データベースに永続化させることです。この作業は難しそうに聞こえますが、Java Persistence アプリケーション・プログラミング・インターフェース (JPA) と Hibernate を使えば、比較的簡単な作業になります。
データベース・エンティティー・クラス
リスト 5 に新しい Java クラス PurchaseOrder の最も重要な部分を記載します。
リスト 5. PurchaseOrder Java クラス
@Id @GeneratedValue
@Column(name = "PO_ID")
private Long id;
@Embedded
private ShippingAddress shippingAddress;
@Embedded
private BillingAddress billingAddress;
@Column(name = "COMMENT")
private String comment;
@Column(name="COMMENT_ENTERED", columnDefinition="boolean default false")
private boolean commentEntered;
|
リスト 5 には、PO_ID (つまり、注文書 ID) という名前の標準的な主キーの列があります。この列の後には、配送先の住所と請求先の住所という 2 つの住所タイプがあります。面白いのはここからです。COMMENT というデータベース列がその後に続いていますが、この列がXML のオプション要素を表します。
リスト 5 の最後の列、COMMENT_ENTERED 列に注目してください。これはブール型の列で、以下のユーザー・アクションを反映します。
- ユーザーがコメントを入力した場合、
COMMENT_ENTERED は True となります。
- ユーザーがコメントを入力しなかった場合、
COMMENT_ENTERED は False となります。
これがまさに、XML のオプション要素という当初の問題に対するソリューションです。このソリューションの何がそれほど特殊なのかを知るには、リレーショナル・データベースでの NULL 値について多少の知識が必要になります。
NULL 列を使用する必要はありません
一般に有効なプラクティスとされているのは、リレーショナル・データベースでは NULL (つまり、値がないこと) 列を許可しないことです。NULL 列を読み取ろうとすると、NULL 値の例外を受け取ることになるからです。これはまた、Java によるデータ抽出コードがこの例外をキャッチしなければならないという意味でもあります。そうなると Java コードは複雑になり、ビジネスに真のメリットはもたらされなくなります。
上記の COMMENT 列を例に取ると、指定の注文書オブジェクトにコメントが関連付けられていない場合に、エンティティーを永続化させると、おそらく皆さんはこの列が NULL になると考えるのではないでしょうか。このことは、Java によるデータ抽出コードは NULL 値 (およびこれに関連付けられた例外) の可能性を想定しなければないということを意味しています。事実上、このような NULL 値はある種のデータ列多重定義であり、このコンテキストでは、NULL 値がデータの何らかの側面を表していると理解される可能性もあります。しかし、このように NULL 値を使用する必要はまったくありません!上記に示されている追加のブール列が、すべての問題を解決します。
つまり、Java によるデータ抽出コードの中で COMMENT 列を読み取る前に、COMMENT_ENTERED 列の値を確認できるということです。その上でようやく、COMMENT 列の読み取りを試行することができます。このどこにメリットがあるのかと言うと、第一のメリットは単純さです。データ定義は、ユーザーとデータとの間の相互作用を反映するため単純になります。同様に、Java によるデータ抽出コードはより簡潔で高速になり、NULL 値の例外がスローされることもありません。
まとめ
XML は現代のコンピューティングでの共通語となっているものの、リレーショナル・データベースとの間で XML データを出し入れするにはまだ多少の課題が残っています。そのため通常は Java マーシャリング技術の 1 つ、例えば JAXB が頼りにされることになります。JAXB では、ビジネス・オブジェクトを XSD ファイルという形式で簡潔に定義することができます。そして、コード生成機能によって、これらのビジネス・オブジェクトを Java クラスに変換することができ、さらにこれらの Java クラスをそれぞれのパーシスタンス・ソリューションに適したエンティティーに変換することができます。
それでは、XML のオプション要素の問題にはどうやって取り組めばよいのでしょうか。多くの組織で採用している方法は、NULL 値を関連するデータベース列に挿入する方法です。この方法は適切でしょうか、それとも不適切でしょうか。さらに言えば、必要でしょうか。NULL 値をリレーショナル・データベースに挿入するのは不適切なプラクティスです。これはレガシー (XML 以外の) データの場合に当てはまることですが、XML データにも同じく当てはまります。XML にオプション要素が含まれているとしても、NULL 値が必要とならないようにすることは可能です。アプリケーション・ドメインがいかに複雑であれ、長年にわたる設計プラクティスに従って意思決定を行ってください。
NULL 値の代わりに、データのセマンティクスを反映するメタデータを追加で定義すればよいだけのことです。つまり、NULL になる可能性のある列に対しては、追加でブール列を定義すれば済むことになります。追加の列にはデフォルト値 (false) を設定し、対応する列に値がある場合にだけこのデフォルト値が変更されるようにすることができます。こうすれば、NULL の必要がなくなるというわけです。
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Stephen Morris は、アイルランドを拠点とするフリーランス・ライター兼コンサルタントです。エンタープライズ開発とネットワーク・アプリケーションに幅広い経験を持つ彼は、これまでネットワークを専門とする世界最大規模の企業に協力し、J2EE/J2SE ベースのネットワーク管理システム、課金アプリケーション、金融システム、SNMP エンティティーの移植/開発、ネットワーク・デバイス技術、そしていくつかのモバイル・コンピューティング・アプリケーションなどのプロジェクトに取り組みました。彼はコンピューター・サイエンスで修士号を取得し、ネットワーク管理の分野で 3 つの特許を持っています。著書に『Moving Your Career Up the Value Chain: Building Specialized Development Skills in a Global Economy』がある他、ネットワーク管理やその他の話題に関する数々の記事も書いています。 |
記事の評価
|