XML と Java 技術: 3 つのタイプの XML パーシスタンス

シリアライズあるいは TrAX、あるいはデータ・バインディングのうち、どれを選びますか

XML を利用すると、ありとあらゆる興味深いことができます。しかし XML をファイルに保持することができないと、すべては無駄になってしまいます。この記事では Brett McLaughlin が、XML のパーシスタンスに関するさまざまな戦略と、それぞれの長所、短所を解説します。

Brett D. McLaughlin, Sr., Author and Editor, O'Reilly Media, Inc.

Photo of Brett McLaughlinBrett McLaughlin氏は、Logo (小さな三角形を覚えていますか?) の時代からコンピューターの仕事をしています。現在の専門は、JavaおよびJava関連のテクノロジーを使ったアプリケーション・インフラストラクチャーの構築です。ここ数年は、Nextel Communications and Allegiance Telecom, Inc. でこれらのインフラストラクチャーの実装に携わっています。Brett氏は、Javaサーブレットを使ってWebアプリケーション開発のための再利用可能なコンポーネント・アーキテクチャーを構築するJava ApacheプロジェクトTurbineの共同設立者の1人です。同氏はまた、オープン・ソースのEJBアプリケーション・サーバーであるEJBossプロジェクトと、オープン・ソースのXML Web公開エンジンであるCocoonにも貢献しています。



2007年 9月 11日

XML をどこかに保存する必要があります

XML は素晴らしいデータ・フォーマットです。何よりもその証拠として、XML の話題のために IBM developerWorks のゾーンが 1 つ専用に用意されています。そして 2007年に XML に関して頻繁に聞かれる話題と言えば、Web サービスや、あるいはXML オブジェクトと Java™ オブジェクトの間での変換、あるいは XML 構成ファイルの読み取り、さらにはリレーショナル・データベースやオブジェクト指向データベースの代わりに XML フォーマットによるデータベース・フォーマットを使う方法などです。

最近あまり聞かれないと思える話題の 1 つが、どのようなメモリー内表現 (DOM、JDOM、その他何でも) を使うにせよ、メモリー内に表現された XML から、どうやって不等号括弧と引用符に満ちた静的なファイルにするかという話題です。正直なところ、XML をファイルに書き出す作業は興奮するようなものではありません。しかしそれは必要なのです。例えば、XML を実際にはファイルに保持することができないプログラミングの世界を考えてみてください。メモリーの中で XML 文書を作成でき、さらにはアプリケーションの別のコンポーネント (さらには別のアプリケーション) に送信できたとしても、その XML を保存することができません。XML を使って構成データを保存でき、そのデータの読み取り用にあらゆる種類のユーティリティーを作成できたとしても、構成データ自体は実際には保存できません。SOAP エンベロープの内容を読み取ることさえできますが、もしアプリケーションをオフラインにするとなった時に、それらの内容をディスクに保存することができません。

当然のことですが、XML を実際に書き出すことは非常に重要です。実際、もしデータが単にメモリー内にあればよく、そのデータの保存方法を気にしなくてよいのであれば、きっとそのプログラミングの世界では、XML がまったく必要なく、XML が今日のようにプログラミング文化の重要な一部であることもないでしょう。

つまり質問は単純です。どのようにして XML をファイルに保持するのでしょう。この質問は、この作業を自分自身で実際に処理するプログラマーを対象にしています。言い換えると、プログラミング作業の中で XML を保持する必要がない人にとっては、この議論は単なる参考情報に過ぎません (ただし、この作業を行うための方法を学ぶ上では適切な出発点になります)。そこで私は、パーシスタンスの処理方法を考えなければならない人のために、非常に一般的で主流となっている 3 つの方法を取り上げることにしました。

  1. DOM や JDOM の API などを使って XML のデータ構造から直接ファイルに書き出す
  2. TrAX (Transformation API for XML) と ID 変換を使って XML を保持する
  3. JAXB などの上位レベル API を使ってパーシスタンスを処理する

API を直接使う

API を使って XML を読み取るのであれば、XML をファイルに書き出すための非常に自明な方法として、その同じ API を使って XML を書き出す方法があります。例えば、JDOM API を使って XML を扱う場合で JDOM の Document オブジェクトがある場合には、単純に次のようにすることができます。

XMLOutputter outputter = new XMLOutputter();
outputter.setFormat(Format.getPrettyFormat());
outputter.output(myDocument, new FileWriter("outputFile.xml"));

DOM Level 3 では、これと同じようなことを、新しい Load and Save API を使って行うことができます。

DOMWriter writer = new org.apache.xml.serialize.XMLSerializer();
writer.setNewLine("\r\n");
writer.setEncoding("UTF-8");
writer.writeNode(new FileOutputStream(new File("outputFile.xml")), myDocument);

この新しい DOM API にはさまざまな使い方があり、あまりベンダー依存ではない使い方もあることに注意してください。上記の例ではコードの中に Xerces 専用のクラスが含まれていますが、他の方法は、これほど緊密に特定のベンダー・クラスに結びつけられていません。ただしそうした方法は、教えるという観点から見るとわかりやすい方法ではありません。そのため私はベンダー専用のコードを使いました。

長所

この方法の利点は、非常に直接的に API とやり取りするため、コントロール可能な範囲が広いことです。改行を設定でき、字下げを操作でき、出力ファイルのほとんどすべての側面をコントロールすることができます。さらに、操作する人とファイルとの間には、ラッパー API もなければ間接化のレイヤーもなく、最小限のものしか存在していないため、XML に近い形での処理 (プログラミング) を行うことができます。JDOM あるいは DOM をよく知っている人にとっては、これらの API は XML を出力するために非常に便利な方法です。

短所

この方法の大きな利点のいくつかは、同時に 2 倍のマイナスにもなります。出力のあらゆる詳細をコントロールできるため、その出力を不適切に構成することによって、すべてを台なしにしてしまう可能性があります。不適切な改行、不正なエンコーディング、I/O エラーなどは、どれもこの方法から生ずる一般的な問題です。さらに、非常に下位レベルで作業するため、ヘルパー・ユーティリティーが多くありません。(JDOM には Format.getPrettyFormat() メソッドと Format.getCompactFormat() メソッドにいくつかのヘルパー・ユーティリティーがありますが、DOM にはほとんど何もありません。) これはつまり、エンコーディングや出力フォーマット、字下げその他、出力に影響するすべてのものを理解しなければならないということです。


フォーマットを変換する

もう 1 つ、よく使われる方法は、TrAX と ID 変換を使う方法です。TrAX は Transformation API for XML であり、現在は JAXP の一部です。そして JAXP は Java プラットフォームのすべてのリリースに含まれています (ただし Micro Edition は除きます)。TrAX を利用すると、XSL スタイルシートを使って XML を変換することができます。そして XML は SAX と DOM を使って処理されることが一般的なため、TrAX は SAX イベントと DOM の Document を入力として使うことができ、また容易にファイルを出力として扱うことができます。さらに TrAX は、これらのフォーマットの間での変換も容易に行うことができます。例えば、DOM で表現された XML 文書を変換し、その出力をファイルに送信することができます。あるいは、ファイルを読み込んで変換し、できあがる文書を DOM の Document の中に置くことができます。

こうしたことの副産物として、文書に対して何もしないスタイルシートを使うことができます。そして単純に 1 つのフォーマットを入力として使い、その文書を他の任意のフォーマットで出力することができます。変換を行わないスタイルシート (要するに入力として受け取るものをエコー出力する以外何もしないスタイルシート) を使う方法は、ID 変換と呼ばれます。つまりファイルから文書を取ってきて ID 変換を適用すると、同じ XML が DOM の Document として得られます。これを逆に行うと、つまり DOM からファイルに対して行うと、実際には XML を保持することになります。これは次のようになります。

Source domSource = new DOMSource(myDOMDocument);
Result fileResult = new StreamResult(new File("outputFile.xml"));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(domSource, fileResult);

この場合の DOM 文書の XML は、結果として outputFile.xml というファイルの中に入ります。

TrAX の長所

TrAX の最大の長所は、非常に簡単に使えることです。また、Java プラットフォームにアクセスできる人であれば誰でも利用することができ、SAX や DOM の知識をあまり必要としません。これは XML プログラミングに関して基本的なスキルしか持っていない開発者にとって、非常に魅力的です。さらに、SAX や DOM になじみのない初級プログラマーでも (10 行か 20 行の機能コードを学ぶだけで) TrAX を使うことができ、そして XML を手軽にファイルとして、さらには DOM の Document や SAX イベントとして保持することができます。

TrAX の短所

TrAX を使うことによる最大の欠点は、ID 変換は容易に行えるものの、出力の詳細を処理することが非常に面倒なことです。TrAX では改行やエンコーディング、空白や字下げなどをすべて構成できますが、DOM あるいは JDOM を直接使おうとすると、思ったほど容易に構成できません。よくあることですが、一般的な作業での TrAX の使いやすさは、(少なくとも、初期状態のままでは) 柔軟性のなさと表裏一体です。

出力に関して JDOM あるいは DOM で行えることは、ほとんどすべて TrAX と ID 変換でも行えることに注意してください。単に、あまり単純ではなく直感的でもない、ということにすぎません。XSLT について、また TrAX の API について少し学ぶ必要がありますが、どちらも実際に行おうとする出力作業とはあまり密接に関係しません。


パーシスタンスのためのデータ・バインディング

XML を静的な形式にするための (特に、ディスク上のどこかに置かれるファイルの形式にするための)、もう 1 つの方法は、JAXB のようなデータ・バインディング API を使う方法です。通常、データ・バインディングはパーシスタンスのための方法とは見なされませんが、実質的にはまさにパーシスタンスのための方法、つまりメモリー内に表現されている XML 文書をファイルに書き出すための方法なのです。

このヒントではスペースの関係でデータ・バインディングとは何かに関する詳細な説明を省略しますが (developerWorks には、この話題に関して既に何本かの記事が公開されています)、下記は JAXB 風のデータ・バインディングを使ってパーシスタンスを実現するためのコードの省略版です。

FileOutputStream stream = new FileOutputStream("outputFile.xml");
Marshaller marshaller = myJaxbContext.createMarshaller();
marshaller.marshal(myJavaObject, stream);

出力ファイルのエンコーディングなど、いくつかのオプションは、どれも Marshaller オブジェクトを使って設定することができます。実際、出力プロパティーに関して、JAXB はこれまで紹介した 2 つの方法と同程度の柔軟な設定をすることができます。

JAXB の長所

JAXB の最大の長所は、非常に使いやすいこと、特に、単純な作業を行う場合に使いやすいことです。そして、いまだに SAX と DOM は (少なくとも通常の Java プログラミングの世界では) やや本格的なものと思われていますが、JAXB は Java 言語を使う人のほぼ全員にとって、ごく普通のものです。これはつまり、JAXB に関して最新の記事やチュートリアルが豊富にあるということです (これは、本サイトのようなサイトで 2007年に公開された記事を調べてみればわかるはずです)。さらに JAXB がサポートされている状況は、DOM あるいは SAX よりも、やや良好です。SAX と DOM は Java SE の一部ですが、JAXB はほぼ完全に Sun Microsystems, Inc. が開発したものです。そのため、サポート状況は少し良いように思えます。

その上、JAXB を使うために XML の知識はほとんど必要ありません。JAXB では、通常の Java オブジェクトを扱うことができ、DOM の Node インターフェースや Text インターフェースなど XML 専用のオブジェクトを扱う必要がありません。そしてこれらのオブジェクトを直接 XML にすることができます。これは、ほとんど何も学ばなくても JAXB を使い始めることができるということです。ほとんどすべての人は、学ばなければならないことが少ない方を好むもので、特にオフィスで上司から怒鳴られている場合はそれが顕著です。

JAXB の短所

JAXB の短所は、XML をあまり知らなくても JAXB を使えることです。これは、先ほど触れたように長所のように思えるかもしれませんが、潜在的な短所としては長所の倍の影響があります。XML の知識が少なければ少ないほど、JAXB をインテリジェントに使うことが難しくなります。使いにくいフォーマットの XML ファイルや、保持するつもりだったオブジェクトの一部しか入っていない XML ファイル、あるいはマーシャルしたオブジェクトと予想外に異なる XML ファイルを作ってしまう、という羽目になりがちです。

こうしたことから、開発者は多くの場合、JAXB をあきらめるか、あるいは XML や、SAX、DOM について大量に学ぶかのいずれかを選択することになります。その時点で多くの開発者は、パーシスタンスには SAX と DOM を使い、JAXB は最も単純な機能、つまり XML オブジェクトと Java オブジェクトの間での変換のための使用にとどめるようになります。


そして、もう 1 つの方法

私はこの解説の中で、最後の 1 つの方法について意図的に触れずにここまできました。その方法とは、XML を、一連のビットやバイト、ストリングとして直接 FileOutputStream あるいは FileWriter に書き出す方法です。これは確かに XML をファイルに書き出すための有効な方法であり、実際これは頻繁に発生します。しかしこの場合には、まだ XML フォーマットになっていないデータから XML を作成する場合と同じように既存の XML データを保持することはできません。この種のコードは通常次のような形式なので、皆さんにもおなじみのはずです。

String xmlString = setupXMLBuffer(
  new StringBuffer("<firstName>")
       .append(customer.firstName)
       .append("</firstName>")
       .append("<lastName>")
       .append(customer.lastName)
       .append("</lastName>")
  // etc...
       .toString()
);
bufferedWriter.write(xmlString);
// other file I/O code

このコードには何も悪いところはありません。ただしこの場合は、XML を保持するのではなく、実際にはデータを保持してそれを XML の中に入れる処理を 1 つのステップで行っているにすぎません。そのため、どのようにデータを保持するか、どの方法がベストか、という問題とは無関係です。データを書き出す動作と、それを XML に入れる動作を分離することはできません。そのため、この記事での議論には当てはまらないのです。


まとめ

XML のパーシスタンスをどう処理すべきなのでしょう。どの場合にも適切な 1 つの正解というものはありません。そうは言っても、皆さんや他の Java および XML 開発者が使用できる方法を議論することには意味があります。皆さんは汎用的な問題に対して、きわめて一貫性のある方法をとろうとしていますか。ある 1 つの形式のパーシスタンスの結果としてディスク上に作成される XML 文書は、他の形式のパーシスタンスを使用した場合よりも読みやすい、または利用しやすい、あるいは他のアプリケーションに送信しやすいでしょうか。

他のヒントの場合と同じように、私が意図したのは、開発者が自分達にとってどの方法が有効であり、どの方法が有効ではないかを議論するように仕向けることです。もし皆さんが、他の開発者にとって有効な方法を知ることができれば、それによって皆さん自身のプログラミングを改善できるはずです。少なくとも、それがこの記事の狙いなのです。そこで、少し時間をとって developerWorks の Java と XML のフォーラム (「参考文献」を参照) に参加し、皆さんがパーシスタンスのためにどんな方法を使っているのかを知らせてください。もしその方法が、ある特定の機能をベースにしているのであれば、それも知らせてください。皆さんと近々オンラインで会えることを楽しみにしています。

参考文献

学ぶために

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Java technology
ArticleID=260595
ArticleTitle=XML と Java 技術: 3 つのタイプの XML パーシスタンス
publish-date=09112007