レベル: 中級 Deepak Vohra (dvohra09@yahoo.com), Consultant, Independent
2006年 5月 09日 2008年 4月 07日 更新 もし皆さんが J2EE (Java™ 2 Enterprise Edition) 開発者であるなら、SQLXML 技術を先行して学ぶ必要があります。SQLXML という Java データ型を使って XML 文書を作成し、XML 文書をリレーショナル・データベースに保管し、データベースから XML 文書を取得し、そして XML 文書をナビゲートする手順について調べましょう。
概要
J2EE 開発者は一般的に、XML 文書をリレーショナル・データベースに保管したり、またデータベースから XML 文書を取得して要素や属性の値を取得したりする必要があります。現状では、リレーショナル・データベースに XML 文書を保管するために利用できる技術やデータ型にはベンダー固有のものしかありません。例えば、IBM DB2 UDB (Universal Database™) は、XML 文書と XML の UDT (user-defined type: ユーザー定義型) を保管するために DB2 XML Extender を提供しています。XML 型の列用の標準データ型と、XML 型の列に対応した Java データ型によって、リレーショナル・データベースへの XML 文書の保管とリレーショナル・データベースからの XML 文書の取得を容易に行えるようになります。SQL:2003 標準は、そうしたデータ型をサポートしています。つまりリレーショナル・データベースに XML 文書を保管するための、新しい XML データ型です。XML データ型を使うことによって、他のデータ型と同じように XML 文書をデータベース・テーブルの列に保管することができます。DB2 データベースのバージョン 9.x は XML データ型をサポートしています。JDBC (Java Database Connectivity) 4.0 仕様は SQL:2003 標準をサポートしています。そして IBM Data Server Driver for JDBC and SQLJ バージョン 4.0 は JDBC 4.0 仕様をサポートしています。
準備
作業を始める前に、この先に進むために必要なコンポーネントが揃っていることを確認します。SQLXML は JDBC 4.0 のデータ型です。SQLXML データ型は JDK (Java Development Kit) 6.0 で実装されているため、この JDK をインストールする必要があります。もう 1 つ必要なことは、XML データ型をサポートするリレーショナル・データベースの中に SQLXML 型のオブジェクトを作成することです。DB2 データベースのバージョン 9.x は XML データ型をサポートしています。この記事に含まれているサンプル・アプリケーション (SQLXMLDB.java) を実行するためには、DB2 9.x データベースをインストールし、DB2 データベースのサンプル・インスタンス (Sample) を作成します。JDK 6.0 と DB2 9、そして SQLXMLDB.java は、それぞれ「参考文献」と「ダウンロード」のセクションから入手することができます。
また、JDBC 4.0 ドライバーも必要です。IBM Data Server Driver for JDBC and SQLJ バージョン 4.0 は JDBC 4.0 ドライバーです。IBM Data Server Driver for JDBC and SQLJ バージョン 4.0 を使って SQLXMLDB.java を実行するためには、JAR ファイル (db2jcc4.jar と db2jcc_license_cu.jar) をクラスパスに追加します。
はじめに
SQLXML という Java データ型を使うと、XML 型のデータベースの列を Java データ型にマッピングすることができます。JDBC 4.0 の仕様では、java.sql.Connection インターフェースは SQLXML オブジェクトを作成します。このオブジェクトは最初はデータを持っていませんが、データは setString() メソッド、setBinaryStream() メソッド、setCharacterStream() メソッド、または setResult() メソッドを使って追加することができます。SQLXML オブジェクトは、ResultSet オブジェクトまたは CallableStatement オブジェクトから getSQLXML(int columnIndex) メソッドまたは getSQLXML(String columnName) メソッドを使って取得することができます。SQLXML オブジェクトの中のデータを取得するためには、getString() メソッド、getBinaryStream() メソッド、getCharacterStream() メソッド、または getSource() メソッドのうちの 1 つを使います。SQLXML オブジェクトは他のデータ型の場合と同じように、PreparedStatement インターフェースの setSQLXML(int parameterIndex, SQLXML sqlXML) メソッドを使ってデータベース・テーブルの XML 型の列に保管することができます。
リスト 1 は catalog.xml という XML 文書の例を示しています。
リスト 1. XML 文書の例 (catalog.xml)
<catalog title="XML Zone" publisher="IBM developerWorks">
<journal date="Jan 2006">
<article>
<title>Managing XML data: Tag URIs</title>
<author>Elliotte Harold</author>
</article>
<article>
<title>Practical data binding: XPath as data binding tool, Part 2</title>
<author>Brett McLaughlin</author>
</article>
</journal>
</catalog> |
データベースを選択する
リレーショナル・データベースが XML 文書を保管するためには XML データ型をサポートする必要があります。すべてのデータベースが XML データ型をサポートしているわけではありません。あるデータベースが XML データ型をサポートしているかどうかを調べるためには、そのデータベースのメタデータを Connection オブジェクトから取得します。例えば DB2 9 が XML データ型をサポートしているかどうかをテストするためには、DB2 の JDBC Type 4 ドライバーである com.ibm.db2.jcc.DB2Driver という JDBC ドライバーをロードして登録します。
Class.forName("com.ibm.db2.jcc.DB2Driver"); |
DB2 UDB データベースに対する接続 URL を指定します。DB2 UDB の Type 4 ドライバーのフォーマットは jdbc:db2://<server>:<port>/<database> です。接続 URL の中で、<server> は DB2 UDB サーバーの名前、<port> は DB2 データベースのポート、そして <database> は DB2 データベースのインスタンスです。DB2 UDB データベースに対する接続 URL は次のようになります。
String url = "jdbc:db2://localhost:50000/Sample"; |
DriverManager の静的メソッド getConnection() を使ってデータベースと接続詞、その接続を Connection オブジェクトとして取得します。
Connection connection = DriverManager.getConnection(url,
"username", "password");
|
次に、Connection オブジェクトからデータベースのメタデータを取得します。
DatabaseMetaData metadata = connection.getMetaData(); |
続いて、このデータベースがサポートしているデータ型を getTypeInfo() メソッドを使って取得します。
ResultSet rs = metadata.getTypeInfo(); |
データ型に関する結果セットに対して繰り返し処理を行い、TYPE_NAME 列を出力します。
System.out.println("TYPE_NAME:"+rs.getString("TYPE_NAME")); |
データベースが XML データ型をサポートしている場合には、XML という TYPE_NAME が出力されます。DB2 9 データベースは XML データ型をサポートしているため、SQLXMLDB.java アプリケーションを実行したことによる出力には、次のように XML データ型が含まれています。
SQLXML オブジェクトを作成する
このセクションでは、SQLXML オブジェクトを作成するための手順を説明します。まず、java.sql パッケージと javax.xml.stream パッケージをインポートします。javax.xml.stream パッケージには、SQLXML オブジェクトをインスタンス化し、SQLXML オブジェクトの中のデータを取得するための、XMLStreamWriter インターフェースと XMLStreamReader インターフェースがあります。
import java.sql.*;
import javax.xml.stream.*;
|
データベース・テーブルの XML 型の列の中にある XML 文書の Java 表現は SQLXML です。XML 型の列に保管する XML 文書を作成するためには、createSQLXML() メソッドを使って Connection オブジェクトから SQLXML オブジェクトを作成します。
SQLXML sqlXML = connection.createSQLXML();
|
createSQLXML() メソッドを使って作成された SQLXML オブジェクトには何もデータが含まれていません。次のセクションでは SQLXML オブジェクトにデータを追加するための方法を説明します。
SQLXML オブジェクトを初期化する
SQLXML オブジェクトを初期化するためには、setString() メソッド、setBinaryStream() メソッド、setCharacterStream() メソッド、または setResult() メソッドのうちの 1 つを使います。SQLXML オブジェクトを初期化するためには setResult() メソッドと StAXResult クラスを使います。getXMLStreamWriter() メソッドを使って StAXResult オブジェクトから XMLStreamWriter オブジェクトを作成します。
StAXResult staxResult = sqlXML.setResult(StAXResult.class);
XMLStreamWriter xmlStreamWriter = staxResult.getXMLStreamWriter();
|
setResult() メソッドを呼び出した後は、SQLXML オブジェクトは書き込み不可になります。
XML 文書の先頭部分を writeStartDocument(String encoding, String version)メソッドを使って追加します。writeStartDocument() メソッドの中で指定されるエンコードは XML 文書出力のエンコードを設定するわけではなく、XML 宣言の中のエンコードのみを設定します。また XMLStreamWriter インターフェースには、エンコードとバージョンを指定しない XML 文書を作成するための writeStartDocument() メソッドと、バージョンを持つ XML 文書を作成するための writeStartDocument(String version) メソッドも含まれています。
xmlStreamWriter.writeStartDocument("UTF-8","1.0");
|
下記のコード・スニペットに示すように、writeStartElement(String localName) メソッドを使ってルート要素 (catalog) の先頭部分を追加します。名前空間と接頭辞を指定して要素を作成する場合は、writeStartElement(String prefix, String localName, String namespaceURI) メソッドを使用します。空の要素を生成するには、writeEmptyElement(String localName) メソッドを使用します。
xmlStreamWriter.writeStartElement("catalog"); |
下記のコード・スニペットに示すように、writeAttribute(String localName, String value) メソッドを使って title 属性を追加します。publisher 属性も同様に追加します。属性に名前空間接頭辞がついている場合には、writeAttribute(String prefix, String namespaceURI, String localName, String value)メソッドを使用します。
xmlStreamWriter.writeAttribute("title", "XML Zone");
mlStreamWriter.writeAttribute("publisher", "IBM developerWorks");
|
同様にして、journal 要素とその属性 date を追加します。
xmlStreamWriter.writeStartElement("journal");
xmlStreamWriter.writeAttribute("date", "Jan 2006");
|
さらに、article 要素と title 要素を追加します。
xmlStreamWriter.writeStartElement("article");
xmlStreamWriter.writeStartElement("title");
|
下記のコード・スニペットに示すように、writeCharacters(String text) メソッドを使って title 要素にテキストを追加します。あるいは、メソッド writeCharacters(char[] text,int start,int len) を使って char[] 配列からテキストを追加します。
xmlStreamWriter.writeCharacters("Managing XML data: Tag URIs"); |
start 要素に対応して必ず end 要素タグがあるようにするため、writeEndElement() メソッドを使って end 要素を追加します。
xmlStreamWriter.writeEndElement(); |
writeEndElement() メソッドは writeStartElement() とは違って要素のローカル名を指定しません。同様に、他の要素を追加してリスト 1 に示す XML 文書を作成します。この XML 文書を完成するためには、writeEndDocument() メソッドを呼び出します。また、XMLStreamWriter オブジェクトをクローズします。
xmlStreamWriter.writeEndDocument();
xmlStreamWriter.close();
|
また、SQLXML インターフェースの setString(String) メソッドを使って XML ストリングから SQLXML オブジェクトに XML 文書を追加することもできます (リスト 2)。
リスト 2. SQLXML オブジェクトに XML 文書を追加する
sqlXML.setString("<catalog title="DB2 Zone" publisher="IBM developerWorks">
<journal date="Jan 2006">
<article>
<title>Managing XML data: Tag URIs</title>
<author>Elliotte Harold</author>
</article>
<article>
<title>Practical data binding: XPath as data binding tool, Part 2</title>
<author>Brett McLaughlin</author>
</article>
</journal>
</catalog>");
|
SQLXML オブジェクトは setString() メソッドが呼び出された後は書き込み不可になります。その前に起動されていた SQLXML オブジェクトの setString() メソッド、setBinaryStream() メソッド、setCharacterStream() メソッド、または setResult() メソッドが呼び出された場合には、SQLExceptionが発生します。次のセクションでは、作成した SQLXML オブジェクトをデータベースの中に保管する方法を説明します。
SQLXML オブジェクトを保管する
SQLXML という Java データ型は、他の Java データ型とまったく同じように XML 文書の中に保管されます。それにはまず、XML 型の列を持つデータベース・テーブルを作成します。SQL コマンドライン・ツール、または JDBC API を使えば、XML 型の列を持つデータベース・テーブルを作成できますが、JDBC を使う場合は、以下のように Connection オブジェクトから Statement オブジェクトを取得します。
Statement stmt = connection.createStatement();
|
次に、XML 型の列を持つ、例えば Catalog というデータベース・テーブルを作成します。
stmt.executeUpdate("CREATE Table Catalog(CatalogId INTEGER, Catalog XML)"); |
この前のセクションで作成された SQLXML オブジェクトを、このデータベースに保管するために、Catalog データベース・テーブルに値を追加するための PreparedStatement オブジェクトを作成します。PreparedStatement は、以下のようにデータベースに追加される値に対するパラメーター・マーカーを持つ SQL の INSERT 文から構成されます。
PreparedStatement statement =
connection.prepareStatement("INSERT INTO CATALOG(catalogId, catalog) VALUES(?,?)"); |
さらに以下に示すように、int の値を setInt(int parameterIndex, int value) メソッドを使って設定し、また SQLXML の値を PreparedStatement インターフェースの setSQLXML(int parameterIndex, SQLXML value) メソッドを使って設定します。setSQLXML() メソッドを呼び出す前に XMLStreamWriter オブジェクトをクローズしておかないと、SQLExceptionがスローされます。
statement.setInt(1, 1);
statement.setSQLXML(2, sqlXML);
|
最後に、executeUpdate() メソッドを使ってデータベースを更新します。
statement.executeUpdate(); |
SQLXML オブジェクトは、少なくともその SQLXML オブジェクトが作成されたトランザクションの間は有効です。SQLXML オブジェクトを使わない場合には、free() メソッドを使って SQLXML オブジェクトのリソースを解放します。
SQLXML オブジェクトを更新する
JDK 6.0 は ResultSet インターフェースの中に、SQLXML の値を更新するためのメソッドも提供しています。更新用のメソッドである updateSQLXML(int columnIndex, SQLXML sqlXML) と updateSQLXML(String columnName, SQLXML sqlXML) を使うと、ResultSet オブジェクトの現在の行または挿入した行の SQLXML の値を修正することができます。例えば、ResultSet オブジェクトに新しい行を追加するためには、更新可能な ResultSet 型の Statement オブジェクトを取得します。
Statement stmt = connection.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
|
そして、XML 型の列を持つ Catalog データベース・テーブルから ResultSet を取得し、行を挿入するために ResultSet カーソルを移動します。さらに、updateSQLXML() メソッドを使って SQLXML 列の値を追加します。updateSQLXML() メソッドはデータベースを更新するわけではありません。データベースを更新するためには insertRow() メソッドを呼び出します。
ResultSet rs = stmt.executeQuery("SELECT * from Catalog");
rs.moveToInsertRow();
rs.updateSQLXML(2, xmlObject);
rs.insertRow();
|
あるいは、スクロール可能な ResultSet の中で現在の行から ResultSet を更新するためには、absolute(int) メソッドまたは relative(int) メソッドを使って ResultSet 行に移動します。そして、更新用メソッドの 1 つを使って SQLXML の値を変更し、さらに updateRow() メソッドを使ってデータベースを更新します。
rs.absolute(5);
updateSQLXML("catalog", xmlObject)
rs.updateRow();
|
ただし、更新用のメソッドを呼び出す前に XMLStreamWriter オブジェクトをクローズしないと、SQLExceptionがスローされます。
ResultSet オブジェクトから SQLXML オブジェクトを取得する
データベースのデータが XML 型の列の値を、SQLXML Java 型として取得します。Catalog データベース・テーブルから ResultSet を取得するための SQL クエリーである SELECT 文用の PreparedStatement を作成します (これを下記のコード・スニペットに示します)。この SQL 文は CatalogId の値に対するパラメーター・マーカーを持っています。
PreparedStatement stmt =
connection.prepareStatement("SELECT * FROM CATALOG WHERE CatalogId=?");
|
XML 文書を取得するための CatalogId の値を指定します。
executeQuery() メソッドを使って結果セットを取得します。
ResultSet rs = stmt.executeQuery(); |
ResultSet インターフェースのメソッド getSQLXML(int columnIndex) または getSQLXML(String columnName) を使って、XML 型の Catalog 列に対する SQLXML オブジェクトを取得します。
SQLXML sqlXML = rs.getSQLXML("Catalog"); |
SQLXML オブジェクトの中に XML 文書を出力するためには、SQLXML インターフェースの getString() メソッドを使うことができます。
System.out.println(sqlXML.getString()); |
SQLXML オブジェクトにアクセスする
SQLXML オブジェクトの中の XML 文書を、getBinaryStream() メソッド、getCharacterStream() メソッド、または getSource() メソッドのうちの 1 つを使って取得します。そして、XMLStreamReader インターフェースを使って、イベント・イテレーターを持つ SQLXML オブジェクトの中の XML 文書を読み取り、ナビゲートされる SQLXML オブジェクトから XMLStreamReader を作成します。
InputStream binaryStream = sqlXML.getBinaryStream();
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader xmlStreamReader = factory.createXMLStreamReader(binaryStream); |
SQLXML オブジェクトは getBinaryStream() メソッドが呼び出された後は読み取り不可になります。次の構文解析イベントを取得するには、next() メソッドを使用します。
while(xmlStreamReader.hasNext()){
int parseEvent = xmlStreamReader.next();
}
|
next() メソッドは定数 XMLStreamConstants に対応する int の値を返します。表 1 は next() メソッドの戻り値の一覧です。
表 1. next() メソッドの戻り値
| 構文解析イベント | 説明 |
|---|
| ATTRIBUTE | 属性が指定されます | | CDATA | CDATA セクション | | CHARACTERS | テキスト | | NOTATION_DECLARATION | 表記法の宣言が指定されます | | COMMENT | XML 文書のコメント | | PROCESSING_INSTRUCTION | 処理命令が指定されます | | START_DOCUMENT | 文書の先頭が指定されます | | START_ELEMENT | 要素の先頭が指定されます | | END_ELEMENT | 要素の終了が指定されます | | ENTITY_DECLARATION | 実体宣言が指定されます | | ENTITY_REFERENCE | 実体参照が指定されます | | NAMESPACE | 名前空間の宣言が指定されます | | SPACE | 無視することができる空白が指定されます | | END_DOCUMENT | 文書の終了が指定されます | | DTD | DTD が指定されます |
戻り値が START_ELEMENT の場合には、構文解析イベントは要素の構文解析が完了したことを示しているので、getLocalName() メソッド、getPrefix() メソッド、getNamespaceURI() メソッドを使って、ローカル名要素、接頭辞要素、名前空間要素を取得します。
if(parseEvent==XMLStreamConstants.START_ELEMENT){
System.out.println("Element Local Name: "+xmlStreamReader.getLocalName());
System.out.println("Element Prefix: "+xmlStreamReader.getPrefix());
System.out.println("Element Namespace:"+xmlStreamReader.getNamespaceURI());
}
|
次に、要素の中の属性カウントを getAttributeCount() メソッドを使って取得します。これらの属性に対して繰り返し処理を行い、getAttributeLocalName() メソッドを使って属性のローカル名を、getAttributeValue() メソッドを使って属性の値を、getAttributePrefix() メソッドを使って属性の接頭辞を、そして getAttributeNamespace() を使って属性の名前空間を取得します。
for(int i=0; i<xmlStreamReader.getAttributeCount();i++){
System.out.println("Attribute Prefix:"+xmlStreamReader.getAttributePrefix(i));
System.out.println("Attribute Namespace:"+xmlStreamReader.getAttributeNamespace(i));
System.out.println("Attribute Local Name:"+xmlStreamReader.getAttributeLocalName(i));
System.out.println("Attribute Value:"+xmlStreamReader.getAttributeValue(i));
}
|
構文解析イベントが CHARACTERS 型の場合には、構文解析イベントのテキストを getText() メソッドを使って取得します。
if(parseEvent==XMLStreamConstants.CHARACTERS){
System.out.println("CHARACTERS text: "+xmlStreamReader.getText());
}
|
まとめ
SQLXML データ型を使うと、データベースの XML 型に対してデータベースから Java へのマッピングを行うことができます。SQLXML データ型は、XML データ型をサポートするデータベースのうち、JDBC 4.0 ドライバーを提供するすべてのデータベースで使用することができます。SQLXML では、XML から SQL へのベンダー固有の API は必要ありません。SQLXML API は JDK 6.0 に含まれています。DB2 9 は XML データ型をサポートするデータベースであり、このデータベース用の JDBC 4.0 ドライバーとして IBM Data Server Driver for JDBC and SQLJ バージョン 4.0 が提供されています。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Sample application SQLXMLDB.java | x-sqlxmldb.zip | 2KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Deepak Vohra は Web 開発者であり、独立コンサルタントであり、Sun 認定の Java プログラマーであり、そして Sun 認定の Web コンポーネント開発者でもあります。彼は ONJava.com、java.net、XML Journal、そして Oracle Magazine にさまざまな記事を発表しています。 |
記事の評価
|