|
事業仕分けによる次世代スーパーコンピューターの開発予算削減について、どうお考えですか?
|
JDBC SQL/XMLの新機能を使ってXMLデータ処理を効率化するはじめに新バージョンの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型の列に格納するには、まず 新しいAPIの売りの1つは、java.sql.SQLXML上で
java.sql.ResultSetからSQLXML型を取得するのは簡単です。通常の型でやっているように、列の名前かインデックスを指定して サンプルプログラム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... } 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)"); リスト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); 著者紹介Oliver Kaljuvee(Oliver Kaljuvee)
ソフトウェアコンサルタント。ニューヨーク市の金融企業のソフトウェア開発に従事。
|