japan.internet.com The Internet & IT Network


RSSニュース検索
カテゴリ
> トップページ
> Webビジネス
> Eコマース
> Webファイナンス
> Webマーケティング
> パブリック
> Webテクノロジー
> 携帯・ワイヤレス
> Linux Today
> Linux Tutorial
> J.I.C.ブログ
キャリア
> 転職ならen
> 派遣ならen
> アルバイトならen
> IT求人情報
ヘッドライン
> 今日のヘッドライン
> 週間ヘッドライン
Special Link
> フォトコミュニティ
> ストックフォト
> クリップアート
> イラスト
> フェリカ
> Web2.0
> 写真
イベント&セミナー
> イベントカレンダー
> 書評「IT の耳」
> 出張・接待検索
> ニュースガジェット 注目
無料ニュースメール
> 新規登録
> 変更・解除
> オプトインメールの登録・変更・解除
インフォメーション
> パートナーサイト
転職ならエン
就職ならen
求人ならen
履歴書ならen
アルバイトならエン
CRM/SFAならオラクル
> グループ会社
株式会社アエリア
(株)サンゼロミニッツ
株式会社エアネット
> お問い合わせ
> 広告掲載について
> リンクについて
> 著作権について
> その他お問い合わせ
> 利用規約
> 個人情報保護方針
> 会社概要地図
デベロッパー 2007年4月3日 10:00
デベロッパー・バックナンバー
JDBC SQL/XMLの新機能を使ってXMLデータ処理を効率化する

著者: Oliver Kaljuvee  オリジナル版を読む プリンター用 記事を転送
2007年4月3日 10:00 付の記事
海外internet.com発の記事
このエントリーを含むはてなブックマーク この記事をクリップ! Buzzurlにブックマーク Yahoo!ブックマークに登録 newsing it!

はじめに

 新バージョンのJava Database Connectivity API(JDBC 4)は、多数の素晴らしい機能によって大々的な化粧直しが施されています。おそらく、特に重要な新機能は、SQL 2003標準で規定されているXMLデータ型がサポートされたことでしょう。XMLをデータベースに格納してアプリケーションから更新するのは目新しいやり方でありませんが、SQL/XMLデータベースデータ型をサポートするマッピングインターフェイス(java.sql.SQLXML)がJDBCで提供されるのは今回が初めてです。この機能追加に伴い、java.sql.Connectionやjava.sql.ResultSetなど、他のインターフェイスもアップデートされたことは言うまでもありません。

 SQL 2003標準でXMLデータ型が導入される以前は、XMLをBLOB、CLOB、またはTEXT型として格納するしか方法がありませんでした。今日、多くのデータベースベンダーは既にXML型を製品の一部としてサポートしていますが、JDBC 4より前のJavaアプリケーションでは、データベース側のXMLデータ型とJDBCのサポートする型との間で変換を行う必要がありました。JDBCの新インターフェイスはXMLのためのJava固有のバインディングを定義しているので、データベース内のXMLデータを以前よりも簡単かつ効率的に処理できるようになりました。

 この記事では、JDBCの新しいインターフェイスでXMLデータ型を格納および取得する方法について解説します。また、サンプルのソースコードで具体的なやり方を示します。

XMLデータの格納と取得

 XMLデータをテーブル内のXML型の列に格納するには、まずjava.sql.Connection.createSQLXML()を呼び出します。これで、新たに導入されたjava.sql.SQLXML型のインスタンスが返されます。次に、このSQLXMLオブジェクトにXMLデータを追加するために、setOutputStream()setCharacterStream()、またはsetString(String xml)を呼び出す必要があります。この機能はBLOB型やCLOB型のサポートとよく似ていることに注意してください。

 新しいAPIの売りの1つは、java.sql.SQLXML上でsetResult(Class resultClass)を呼び出して、javax.xml.transform.Resultの実装クラス(DOMResult、JAXBResult、SAXResultなど)のインスタンスを取得できることです。つまり、特に変換しなくても以下のことが実現できます。

  1. XMLを取得する。
  2. そこからDOMResultを作成する。
  3. DOMResultをjava.sql.SQLXMLオブジェクトに割り当てる。
  4. XMLをjava.sql.Statementにバインドすることで、XMLをデータベースの列に直接格納する。

 java.sql.ResultSetからSQLXML型を取得するのは簡単です。通常の型でやっているように、列の名前かインデックスを指定してgetSQLXMLを呼び出すだけです。次に実際のXMLデータをjava.io.InputStream、java.io.Reader、または旧来のStringから取得します。具体的には、ResultSetから取得したjava.sql.SQLXMLインスタンス上でgetBinaryStream()getCharacterStream()、またはgetString()を呼び出します。同様にXMLを格納するには、SQLXMLインスタンス上でgetSource(Class sourceClass)を呼び出し、javax.xml.transform.Sourceを実装する任意のクラスからXMLデータに直接アクセスします。

サンプルプログラム

 JDBC 4が公式に発表されたのは2006年12月11日であるため、そのドライバを提供しているデータベースはごくわずかであり、現時点で完全に対応したデータベースは存在しません。この記事で紹介する例では、最新版のApache Derby 10.2を用いてXMLデータの格納とクエリを行っています(次ページの「リスト1 XMLの格納とクエリを行うサンプルプログラム」を参照)。しかし、Derbyはjava.sql.SQLXMLをまだサポートしていません。つまり、結果セットにXML値を直接バインドしたり、そこからXML値を直接取得したりすることはできません。この記事の目的からすると、これは大きな欠点のようにも見えますが、DerbyはSQL 2003に準拠し、埋め込みモードで簡単に使用できるので、将来的に完全対応のドライバが入手できた場合にXMLデータがどのようにして取得されるかを示すには十分です。

 DerbyのXML関連の演算子(XMLPARSE、XMLSERIALIZEなど)を利用すると、データを文字ストリームまたは文字列に変換してプログラムで使用できます。本稿の各サンプルタスクでは、SQL/XML完全対応のドライバを用いた場合のタスクの実現方法も示しています。実際、サンプルコード内の各タスクを、java.sql.SQLXMLを使用したコードに置き換えてもコードは正常にコンパイルされます。しかし、プログラムを実行すると、Derby固有のエラー(「XML値への直接バインドは許可されない」など)が発生します。要するに、このサンプルコードの主な目的は、SQL/XML対応のデータベースとどうやり取りすればよいかを示すことにあります。java.sql.SQLXMLを用いてサンプルプログラムと同じ処理を実行するコードも、また別の機会に紹介したいと思います。

 最初に、XMLデータ型を含む簡単なテーブルを作成します。

Statement s = c.createStatement();
s.execute("CREATE TABLE ARTICLE(ID INTEGER, DATA XML)");

XMLデータの挿入

 Derbyはjava.sql.SQLXML型をまだサポートしていないので、データをDATA列に挿入するときに、XMLとして解析可能な他の型へのバインドが必要になります。ここではCLOB型を使用しています。

ps = c.prepareStatement("INSERT INTO ARTICLE (ID, DATA) VALUES "
   + "(?, XMLPARSE (DOCUMENT CAST (? AS CLOB) PRESERVE "
   + "WHITESPACE))");
ps.setInt(1, id++);
ps.setClob(2, new StringReader(insert));

 さて、JDBC 4完全対応ドライバがある場合は、同じ処理をjava.io.Writerで実現できます(この変更を行ってもコードは正常にコンパイルされます)。

ps = c.prepareStatement(
            "INSERT INTO ARTICLE (ID, DATA) values (?, ?)");
SQLXML article = c.createSQLXML();
Writer writer = article.setCharacterStream();
writer.write(insert);
writer.close();
ps.setInt(1, id++);
ps.setSQLXML(2, article);

 あるいは、javax.xml.transform.dom.DOMSourceを使用する方法もあります。

ps = c.prepareStatement(
          "INSERT INTO ARTICLE (ID, DATA) values (?, ?)");
SQLXML article = c.createSQLXML();
DOMResult dom = (DOMResult)article.setResult(DOMResult.class);
dom.setNode(doc); // doc is instance of org.w3c.dom.Document
ps.setInt(1, id++);
ps.setSQLXML(2, article);

XMLデータの取得

 DerbyからXML型を取得するときは、以前と同様、XMLデータベース型を文字型に変換する必要があります。

ResultSet rs = s.executeQuery("SELECT XMLSERIALIZE (DATA AS CLOB) "
                              + "FROM ARTICLE WHERE ID = 2");

 java.sql.SQLXMLがサポートされている場合は、XMLデータベース型の列を選択するだけで同じタスクを実現できます。XMLデータを直接取得できるわけです。ここでは、結果セットから取得したXMLをDOMパーサーで評価するものとします。

PreparedStatement st 
  = c.prepareStatement("SELECT ID, DATA FROM ARTICLE");
ResultSet rs = st.executeQuery();

while (rs.next())
{
   SQLXML article = rs.getSQLXML("DATA");
   InputStream stream = article.getBinaryStream();
   DocumentBuilder parser =
   DocumentBuilderFactory.newInstance().newDocumentBuilder();
   Document doc = parser.parse(stream);
   // Do something...
}

 getBinaryStream()を呼び出す代わりにgetSource(Class sourceClass)を呼び出します。これでDOMSourceやSAXSourceなど、javax.xml.transform.Sourceを実装するクラスのインスタンスが返されます。

XMLEXISTSでXPathを判定

 最後の例では、SQL 2003の新しいXMLEXISTS述語でのXPathの使い方を示します。

Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT ID FROM ARTICLE WHERE "
   + "XMLEXISTS(’//author[text()="John Smith"]’ PASSING BY REF "
   + "DATA)");

 XMLQUERY関数を使用して任意のXQuery式を実行することもできます。しかし、XMLEXISTS述語とXMLQUERY関数は機能的にJDBC 4よりもSQL 2003寄りであるため、この記事ではこれ以上言及しません。

リスト1 XMLの格納とクエリを行うサンプルプログラム
import java.io.StringReader;
import java.sql.*;

public class XmlDbTester
{
   static final String XML1 =
      "<article>"
        +"<title>First Article</title>"
        +"<author>John Smith</author>"
        +"<body>A very short article.</body>"
    +"</article>";

   static final String XML2 =
      "<article>"
        +"<title>Second Article</title>"
        +"<author>Mary Jones</author>"
        +"<body>Another short article.</body>"
    +"</article>";

   static final String XML3 =
      "<article>"
        +"<title>Third Article</title>"
        +"<author>John Smith</author>"
        +"<body>Last short article.</body>"
    +"</article>";

   static final String[] ARTICLES = {XML1, XML2, XML3};

   public static void main(String s[])
   {
      XmlDbTester xdt = new XmlDbTester();
      Connection c = xdt.getConnection();
      xdt.loadDemoData(c);
      xdt.demoXmlResult(c);
      xdt.demoXPath(c);
      xdt.closeConnection(c);
      System.out.println("Done");
      System.exit(0);
   }
    
   void demoXmlResult(Connection c)
   {
      try
      {
         Statement s = c.createStatement();
         ResultSet rs 
          = s.executeQuery("SELECT XMLSERIALIZE (DATA AS CLOB) "
          + "FROM ARTICLE WHERE ID = 2");

         while(rs.next())
            System.out.println(
               "The article XML for article with ID = 2: 
"
               + rs.getString(1));

         s.close();
         rs.close();
      }
      catch(Exception e)
      {
         e.printStackTrace();
      }
   }

   void demoXPath(Connection c)
   {
      try
      {
         Statement s = c.createStatement();
         ResultSet rs
          = s.executeQuery("SELECT ID FROM ARTICLE WHERE "
        + "XMLEXISTS(’//author[text()="John Smith"]’ PASSING BY REF "
        + "DATA)");

         while(rs.next())
            System.out.println("John Smith wrote article with ID: "
                               + rs.getInt(1));

         s.close();
         rs.close();
      }
      catch(Exception e)
      {
         e.printStackTrace();
      }
   }
    
   void loadDemoData(Connection c)
   {
      try
      {
         Statement s = c.createStatement();
         s.execute("CREATE TABLE ARTICLE(ID INTEGER, DATA XML)");
         System.out.println("Created demo table: ARTICLE");
         s.close();

         PreparedStatement ps = null;
         int id = 1;

         for(String insert : ARTICLES)
         {
            ps = c.prepareStatement(
               "INSERT INTO ARTICLE (ID, DATA) VALUES "
               + "(?, XMLPARSE (DOCUMENT CAST (? AS CLOB) PRESERVE "
               + "WHITESPACE))");
            ps.setInt(1, id++);
            ps.setClob(2, new StringReader(insert));
            ps.executeUpdate();
         }

         System.out.println("Inserted test data into ARTICLE");

         if(ps != null )
            ps.close();
      }
      catch(SQLException e)
      {
         e.printStackTrace();
      }
   }

   Connection getConnection()
   {
      Connection c = null;

      try
      {
         c = DriverManager.getConnection(
                                  "jdbc:derby:XmlDemo;create=true");
         c.setAutoCommit(false);
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }

      return c;
   }
    
   void closeConnection(Connection c)
   {
      try
      {
         c.close();
      }
      catch(Exception e) {}
   }
}

無限の可能性

 SQL/XMLのサポートでコードの見通しがよくなり、開発期間が短縮されます。通常、XMLデータをデータベースに格納するのは、それなりの事情があるからです。記事、イベントリスト、製品情報など、さまざまなメディアをオンラインで表示する最も一般的な手法の1つは、データ全体をXMLとして格納し、変換を経てそのデータをオンラインで表示するというものでしょう。java.sql.SQLXML APIドキュメントには、新しいデータ型からの変換方法が多数掲載されていますが、次の例を見てみましょう。これもJava SE 6ドキュメントに掲載されているものです。

File xsltFile = new File("transformer.xslt");
File xhtmlFile = new File("xhtml.xml");
Transformer xslt =
   TransformerFactory.newInstance().newTransformer(
     new StreamSource(xsltFile));
Source source = sqlxml.getSource(null);
Result result = new StreamResult(xhtmlFile);
xslt.transform(source, result);

 sqlxml変数は、データベースから取得したjava.sql.SQLXMLのインスタンスです。変換は必要ありません。データベースに格納されたXMLコンテンツを、わずか5行でXHTMLに変換できるというわけです。

著者紹介

Oliver Kaljuvee(Oliver Kaljuvee)
ソフトウェアコンサルタント。ニューヨーク市の金融企業のソフトウェア開発に従事。


関連記事
  • 楕円曲線暗号公開鍵方式対応「Sun Java System Web Server 7.0 日本語版」を発表
  • 『Java プログラマガ知ッテオクベキコト』―プログラミングに関する最良の書
  • 日本オラクル、Visual Basic 開発者の Java 移行支援で無償トレーニングを開始
  • Sun、アプリケーションサーバー『Glassfish V2』のベータ版を発表
  • ウェブルート、閲覧しただけでトロイの木馬がインストールされる例を発見


  • 関連テーマ
  • XML
  • Java
  • Apache


  • ★最新トップニュース
    国内 KDDI、au one net の WEB メールサービスを停止―他ユーザーのメールが閲覧できる不具合(Webビジネス 7月25日 21:00)
    KDDI は、2008年7月25日、固定系インターネット接続サービス「au one net」(旧 DION)にて提供している「WEB メール」サービスを、同日停止したことを発表した。
    コラム Apple がどうしても中国と相容れない理由(Webビジネス 7月25日 18:00)
    同社は7月19日、新しいピカピカの Apple ストアを北京にオープンさせた。Apple 関係者によると、中国には Apple ストアを「今後続々」オープンさせていくという。レースは始まっているのだ。しかし、Apple はこの競技で勝てるのだろうか?
    国内 キューピーが「犬夜叉」「めぞん一刻」などとコラボ、「キュージョン」新バージョン登場画像のある記事(E-コマース 7月25日 18:00)
    株式会社ラナは、2008年7月25日、ローズオニールキューピーと有名キャラクターとのコラボレーション「キュージョン」の第5弾として、「キュージョン るーみっくわーるど」バージョンを発売した。
    国内 【今週の Web ミミズク】まだまだ続く HP ミニノート騒動(Webテクノロジー 7月25日 17:40)
    「HP 2133 Mini-Note PC」の後継となるモデルが8月中に販売される予定だが、さて、どうなることやら。iPhone もすごかったが、Mini-Note も、まだまだ後を引きそうだ。
    国内 マイスペース、未成年者対応を強化―米国での15歳未満への対応を国内の18歳未満に適用(Webマーケティング 7月25日 17:00)
    マイスペース株式会社は、2008年7月25日、同社の提供する SNS「MySpace Japan」にて、18歳未満の未成年者への対応の強化を PC、モバイルともに完了したと発表した。
    トピックス
    > オススメのIT系求人情報【毎週月曜日更新】
    footer_301.gif


    リサーチ
    > デイリーリサーチDLサイト
    > OnlineResearchPortal (リサーチデータバンク)
    > モバイルリサーチ with goo
    footer_301.gif
    キーワード
    > iPhone > Youtube
    > Google > モバイルノート
    > 半導体 > ウィルコム
    > テーマ一覧はこちら
    footer_301.gif
    セミナー情報
    > 第1回インターネットコムマーケティングセミナー「新規クライアントを効率的に獲得する Web マーケティング手法とは」(3月26日)多数のご参加ありがとうございました
    footer_301.gif
    デベロッパー
    > DevX
    > CodeGuru
    > developer.com
    footer_301.gif
    日本Oracle
    footer_301.gif
    j.i.c.ブログ
    ブログ一覧
    デスマーチからの脱却 【デスマーチからの脱却】
    独自ドメインでiPhoneのメール送受信(7月25日)
    データメーション 【データメーション】
    本物のスパム王様はお名乗り出ください(7月24日)
    Graphic Design Forum 【Graphic Design Forum】
    興味深い(?)90年代 (7月24日)
    エンジニアの独り言 【エンジニアの独り言】
    新入社員が配属される季節ですね。(7月23日)
    ジュピターメディア創設者がITを斬る 【ジュピターメディア創設者がITを斬る】
    Alan を探せ(7月18日)
    ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」 【ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」】
    「『訪問歯科診療』のパイオニア」/デンタルサポート株式会社(7月15日)
    footer_301.gif
    最新コラム一覧
    IT マネジメント IT マネジメント

    Apple がどうしても中国と相容れない理由(7月25日)
    CodeGuru CodeGuru

    Visual C++ 2008 Feature Pack: MFCの強化 (2)(7月25日)
    最新アフィリエイト事例にみる成功の法則 最新アフィリエイト事例にみる成功の法則

    メディアのニーズ 〜アフィリエイトに対する思い〜(7月25日)
    最新ハイテク講座 最新ハイテク講座

    Blu-ray がノート PC でも快適に!インテル「Centrino 2」(7月25日)
    百式のネットビジネス研究 百式のネットビジネス研究

    究極にシンプルなタスク管理ツール「now do this」(7月25日)
    週刊-サイト別アクセス状況データ 週刊-サイト別アクセス状況データ

    ビデオリサーチインタラクティブ調査(月間インターネットオーディエンスデータ)(7月24日)
    ハードウェアから見たデータベース ハードウェアから見たデータベース

    表計算ソフトの計算を支える仕組(7月24日)
    「IT の耳」 「IT の耳」

    【書評】『ネットオークションで騙す。』―全米を揺るがした絵画詐欺犯の告白―(7月24日)
    検索エンジンマーケティング 検索エンジンマーケティング

    ピンポイントマーケティングにおける P4P(検索連動型広告)の“当たり前”(7月24日)
    Eメールマーケティング事情 Eメールマーケティング事情

    大量送信のスパムからターゲット絞り込みスパムメールへ(7月23日)
    footer_301.gif
    専門チャンネル
    > セキュリティチャネル > テレコムチャネル
    > サーチエンジンウォッチ
    footer_301.gif
    海外のインターネットコム アメリカ韓国ドイツトルコ
    関連企業のサイト:ストックフォト イラスト ネットストリート ホテル予約サイト タウン情報 出張 事業継承 シミュレーション トランクルーム 優待映画チケット 田舎暮らしガイド オリジナルデザインTシャツ ニタコエ
    Copyright 2008 Jupitermedia Corporation All Rights Reserved. http://www.internet.com/
    space.gif space.gif