mb_language("uni"); mb_internal_encoding("utf-8"); mb_http_input("auto"); mb_http_output("utf-8"); ?>
XML DBを採用する利点については、別稿「徹底比較!RDB vs XML DB」で、「スキーマ変更に対する耐性」という観点から検討した。RDB(リレーショナル・データベース)においてスキーマの変更を施す場合には、対応するアプリケーションの変更はもちろん、テーブル、インデックス、リレーションシップなどあらゆる側面から設計を見直す必要がある。極端な話、たった1つのフィールドを追加するにも、設計からアプリケーション・テストまでの多大な工数を割く必要があるのだ。一方で、XML DBの場合はこのような必要はない。必要なデータを必要なノードツリーに自由に追加することができる。この際、テーブル・レイアウトの再設計は一切必要ないし、インデックスも新規のノードツリーがロードされたタイミングで、自動的に追加されるので、開発者はアプリケーション側の改定だけに集中できる。
このような理論は、上述の記事で理解できただろう。しかし、「理屈だけを聞いていても、なかなか具体的なイメージが湧かない」という方も少なくないはずだ。そこで本稿では、Xprioriを採用して、具体的なXML DBプログラミングに挑戦してみよう。スキーマ変更がシステム全体に影響を及ぼさないXML DBの特性を、実際に手を動かしながら体感してほしい。
まずは、「徹底比較!RDB vs XML DB」で使用したコード1を個々の<注文>要素の単位に分解し、Xprioriに初期データとして投入しておこう。初期データは以下のリンクからダウンロードすることができる。
初期データ
初期データの投入は、別稿「Xprioriで始めるXML DBプログラミング ~リレーショナルデータベースからXML DBへのデータ移行を進めよう~」で紹介したXmlStoreクラスを利用してもよいが、ここでは、Xpriori標準の管理コンソールから行う方法について紹介する。
管理コンソールの[Database Access]タブから[Store]を選択し、[XML File]欄に格納したいXMLファイルの絶対パスを指定する。[Store XML]ボタンをクリックして、以下のような成功ステータスが表示されれば成功だ。
図1 [Store XML]の実行結果
これをダウンロードしたorder1~3.xmlまで繰り返せばよい。格納に成功したかどうか確かめるには、同じく管理コンソールのメニューから[Query]を選択し、XQuery Targetとして、以下の式を指定する。
/ND/注文
このクエリの結果、以下のように注文データが3件表示されれば成功だ。このように、Xprioriでは、すべての結果が
図2 [Query XML]の実行結果
上の例では、投入したすべての注文データを取得しているが、特定の注文番号をキーにして注文データを取得したいならば、以下のように指定すればよい。
/ND/注文[注文番号='XXXX-012-X']
今度は、注文番号が「XXXX-012-X」のデータだけが取得できたはずだ。
次に、管理コンソール上で行った処理をJavaアプリケーションに実装してみよう。以下は、指定された注文番号をキーにXprioriデータベースを検索し、マッチした注文データをコマンドプロンプト上に表示するサンプルだ。
[XmlSearch.java]package to.msn.wings.samples; import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.xml.sax.inputSource; import com.neocore.httpclient.SessionManagedNeoConnection; public class XmlSearch { public static void main(String[] args) { try { // データベースへのセッションを確立 SessionManagedNeoConnection session= new SessionManagedNeoConnection("localhost",7700); String id=session.login("Administrator","admin"); // Xprioriデータベースを検索し、注文情報を取得 StringReader objSr=new StringReader( session.queryXML("/ND/注文[注文番号='XXXX-012-X']")); // 取得したXML文字列からDOMツリーを生成 DocumentBuilderFactory objDbf=DocumentBuilderFactory.newInstance(); DocumentBuilder objDb=objDbf.newDocumentBuilder(); Document objDoc=objDb.parse(new inputSource(objSr)); // 生成したDOMツリーから必要な注文情報を出力 System.out.println("注文番号:" + objDoc.getElementsByTagName("注文番号").item(0) .getFirstChild().getNodeValue()); System.out.println("商品名:" + objDoc.getElementsByTagName("商品名").item(0) .getFirstChild().getNodeValue()); System.out.println("購入先名:" + objDoc.getElementsByTagName("購入先名").item(0) .getFirstChild().getNodeValue()); // データベースからログアウト session.logout(); } catch (Exception e) { e.printStackTrace(); } }
queryXMLメソッドは、Xprioriデータベースに対して問い合わせを行い、その結果を文字列で返すためのメソッドだ。ここでは、queryXMLメソッドが返した文字列を元にDOMツリーを生成しているが、Xprioriに対して問い合わせを何度も発行して直接に文字列を取得しても構わない。
以上のコードを実行するには、コマンドプロンプトから以下のコマンドを入力すればよい。
> SET CLASSPATH=".;C:\Xpriori\API\Java\lib\xmsclient.jar;" > javac ./to/msn/wings/samples/XmlSearch.java > java to.msn.wings.samples.XmlSearch 注文番号:XXXX-012-X 商品名:工作機械 購入先名:新野電子機器
上のように、注文番号に対応する注文情報が表示されれば、まずは成功だ。
次は、いよいよ本題であるスキーマ情報の変更を行ってみよう。もっとも、XprioriはRDBのように厳密なスキーマを持たない(持つ必要がない)ので、開発者は特にスキーマ変更を意識する必要はない。スキーマ変更が必要になったデータから、適宜、データを投入していけばよいのだ。すでに投入済みのデータを「変更」するのでなければ、既存データへの影響も一切ない。例えば、ここでは以下のような注文データを管理コンソールから投入してみよう。order1~3.xmlと異なる点は、新たに仲介情報を追加している点だ。
[order4.xml]<?xml version="1.0" encoding="UTF-8" ?> <注文> <注文番号>OOOO-111-0</注文番号> <発注個数>10</発注個数> <商品情報> <商品名>電子回路A</商品名> <単価>100</単価> </商品情報> <購入先情報> <購入先名>新野電子機器</購入先名> <購入先連絡先>142-888-8888</購入先連絡先> </購入先情報> <仲介情報> <仲介業者名>宮下物産</仲介業者名> <営業担当者名>宮下</営業担当者名> <仲介業者アドレス>miyashita@miyabussan.xx</仲介業者アドレス> <仲介手数料>5</仲介手数料> </仲介情報> </注文>
Xpriori上での作業はこれだけだ。後は、先ほどのデータ検索用クラスであるXmlSearchに仲介情報を取得できるような変更を加えればよい。以下のサンプルコードの太字部分がXmlSearchクラスからの変更部分になる。
[XmlSearch2.java]package to.msn.wings.samples; import java.io.StringReader; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.inputSource; import com.neocore.httpclient.SessionManagedNeoConnection; public class XmlSearch2 { public static void main(String[] args) { try { SessionManagedNeoConnection session= new SessionManagedNeoConnection("localhost",7700); String id=session.login("Administrator","admin"); StringReader objSr=new StringReader( session.queryXML("/ND/注文[注文番号='OOOO-111-0']")); DocumentBuilderFactory objDbf=DocumentBuilderFactory.newInstance(); DocumentBuilder objDb=objDbf.newDocumentBuilder(); Document objDoc=objDb.parse(new inputSource(objSr)); System.out.println("注文番号:" + objDoc.getElementsByTagName("注文番号").item(0) .getFirstChild().getNodeValue()); System.out.println("商品名:" + objDoc.getElementsByTagName("商品名").item(0) .getFirstChild().getNodeValue()); System.out.println("購入先名:" + objDoc.getElementsByTagName("購入先名").item(0) .getFirstChild().getNodeValue()); Element objElm=(Element)objDoc.getElementsByTagName("仲介業者名").item(0); if(objElm!=null){ System.out.println("仲介業者名:" + objElm.getFirstChild().getNodeValue()); } session.logout(); } catch (Exception e) { e.printStackTrace(); } }
<仲介業者名>要素のように必ずしもすべてのデータに含まれない要素が生じても、XmlSearch2.javaに示したとおりアプリケーション側でnull判定のコードを追加するだけで簡単に対応できる。本稿のサンプルでは、XMLデータのスキーマ変更がアプリケーションに与える影響を分かりやすく解説するために、<仲介業者名>要素についてのみチェックを追加したが、実際の開発では各ノードにあらかじめnull判定のコードを実装しておけば、スキーマ変更時のインパクトはさらに小さくなるだろう。
このコードを実行するには、コマンドプロンプトから以下のコマンドを入力すればよい。
> SET CLASSPATH=".;C:\Xpriori\API\Java\lib\xmsclient.jar;" > javac ./to/msn/wings/samples/Rdb2Xmldb.java > java to.msn.wings.samples.Rdb2Xmldb 注文番号:OOOO-111-0 商品名:電子回路A 購入先名:新野電子機器 仲介業者名:宮下物産
以上、スキーマ変更時の実例を見てきたが、このように、XML DBではスキーマの変更がデータベースそのものには何ら影響しないことが分っただろう。必要に応じて必要なデータを追加してさえおけば、開発者はアプリケーションの変更だけに集中できる。同様の対応をRDBで行おうとした場合、テーブル設計の変更からインデックスの再設定、実行計画の再検討などの作業が発生し、ここで示したXML DBのようにはいかないことは、RDBでアプリケーションを構築したことがある方ならば容易に想像できるだろう。
前回と今回はJava言語をベースにXML DBの取り扱い方を説明してきたが、当然ながらXML DBはJavaだけのものではない。次回は同様の操作を.NETアプリケーションから行ってみることにしたい。
▲このページのTOPへ