ホーム > X-Plus > XML Square >  デベロッパーズコーナー  >  JavaプログラミングとXML

この記事を送る はてなブックマークに追加する BuzzurlにブックマークBuzzurlにブックマーク Yahoo!ブックマークに登録
テキストリンクコードを取得する

デベロッパーズコーナー:Javaプログラミングを極める「JAXB」-(2)

2004年01月20日作成 

Javaプログラミングを極める
第8回:JAXB

(株)日本ユニテック
太田 純

<この記事はDigital Xpress 2002 Vol.14(4-5月号)に掲載されたものです>

今回は「JAXB(Java Architecture for XML Binding)」を取り上げます。JAXB はXML Schema によるスキーマ定義をJava のクラスにマッピングすることによってアプリケーションの開発効率を向上させるためのツールやAPIをまとめたアーキテクチャです。

以下は、解説記事(前半)の続きです。


JAXB アプリケーションの作成

ここからは、実際にJAXB を用いたXML アプリケーションの作成例を見ていきましょう。以下の手順で作業を進めます。

1. XML Schema で記述したスキーマを作成(または入手)
2. スキーマコンパイラxjc コマンドを実行
3. xjc コマンドによって生成されたクラスを利用するアプリケーションを作成

今回のサンプルとして、リスト1 に挙げたXML Schema 文書schedule.xsd を利用することにします。このスキーマはスケジュールの項目を記述するためのもので、イベントの開始/終了の日時を示すstart 要素とend 要素の要素内容をxsd:dateTime 型に定義して、ISO 8601 で規定された記法による日付および時刻を指定するようにしました。

<?xml version="1.0" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://unitec-denki.utj.co.jp/schema/sche dule" xmlns="http://unitec-denki.utj.co.jp/schema/schedule">
    <xsd:element name="schedule">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="event" maxOccurs="unbounded" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="event">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="start" />
                <xsd:element ref="end" minOccurs="0" />
                <xsd:element ref="location" />
                <xsd:element ref="contactTo" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="start" type="xsd:dateTime" />
    <xsd:element name="end" type="xsd:dateTime" />
    <xsd:element name="location" type="xsd:string" />
    <xsd:element name="contactTo" type="xsd:string" />
</xsd:schema>
【リスト1 : schedule.xsd】

スキーマコンパイラによるクラス生成

JAXB に添付されているスキーマコンパイラはxjc コマンドによって起動します。以下のように実行すると、スキーマ文書からJava クラスを生成できます。

xjc スキーマファイル名

今回のサンプルでは以下のようになります。

xjc schedule.xsd

これを実行すると、スキーマ文書のルート要素schema のtargetNamespace 属性を基にしてパッケージ名が生成されます。今回のサンプルでは、targetNamespace 属性の値を「http://unitec-denki.utj.co.jp/schema/schedule」としているので、生成されるクラスが属するパッケージ名は「jp.co.utj.unitec_den ki.schema.shcedule」となります。もし属性targetNamespace が指定されていなければ、xjc は固定値のパッケージ名であるgenerated を使用します。

今回のサンプルの場合、前記xjc コマンドを実行すると、パッケージを表すディレクトリ階層「jp/co/utj/unitec_denki/schema/schedule」の下に、各要素に対応する処理を行うためのインタフェースやクラスのソースファイル群が生成されます。たとえば、要素schedule に対応してSchedule.java が生成され、要素event に対応してEvent.java が生成されます。

生成されたクラスを使ったアプリケーションの作成

XML データ構造を生成するサンプルプログラムをリスト2に示します。処理の手順は以下のようになっています。

1. クラスjavax.xml.bind.JAXBContext のstatic メソッドnewInstance を使って、JAXBContext オブジェクトを生成(リスト2- ①)。その際、同メソッドの引数には、xjc が生成したクラスのパッケージ名(このサンプルの場合、jp.co.utj.unitec_denki.schema.schedule)を指定します。

2. xjc が生成したクラスObjectFactory のメソッドを使って、各XML 要素に対応するオブジェクトを生成。たとえば、要素schedule を表すオブジェクトであれば、メソッドcreateSchedule によって生成できます(リスト2- ②)。

3. 要素を表す各インタフェースのメソッドを使用して、子要素や要素の内容となるデータを設定。

子要素が複数回出現する場合には、子要素の集合を取得するメソッド(この例の場合、getEvent)によってjava.util.List オブジェクトを取得し、このリストに子要素を追加していけばよいようになっています(リスト2- ③)。

xjc が生成したクラスには、子要素を追加するためのメソッドや、要素の内容を設定するためのメソッドが作成されています。子要素や子要素の内容を追加するメソッドの名前は、「set+要素を表すインタフェース名」の形式になっています。たとえば、setStart(リスト2- ④)は引数にjava.util.Calendar オブジェクトを取り、子要素start を追加すると同時に要素内容に日時を示す文字列を設定します。*1

XML データ構造の妥当性検証

作成したXML データ構造が、スキーマに適合する妥当なデータであるかどうかを調べるには、プログラム中で以下の処理を行います。*2

1. クラスJAXBContext のメソッドcreateValidator でValidator オブジェクトを取得(リスト2- ⑤)。
2. Validator オブジェクトのメソッドvalidateRoot を呼び出す(リスト2- ⑥)。引数には、検証対象のルートとなるオブジェクト(本サンプルではSchedule オブジェクト)を渡す。

メソッドvalidateRoot は、プログラム中の任意の個所で呼び出すことができます。また、Validator オブジェクトのメソッドvalidate を使えば、XML データ全体ではなく一部だけを検証の対象とすることもできます。

XML 文書の生成

マーシャリングフレームワークの機能により、XML データ構造(Java オブジェクト)をXML 文書ファイルとして出力するには、インタフェースjavax.xml.bind.Marshallerを利用して、以下のような処理を行います。

1. JAXBContext オブジェクトのメソッドcreateMarshaller により、Marshaller オブジェクトを取得(リスト2- ⑦)

2. Marshaller オブジェクトのメソッドmarshal を呼び出す(リスト2- ⑨)

marshal メソッドの第1 引数には出力したいXML データ構造(この場合はSchedule オブジェクト)を、第2引数には出力先を指定します。出力先としては、java.io.OutputStream オブジェクトやjava.io.Writer オブジェクトのほか、他のXML 処理系で扱えるように、DOMやSAX のオブジェクトを指定することもできます。

インタフェースMarshaller には、出力方法を変更するためにメソッドsetProperty が用意されています。リスト2-⑧ のように、フィールドJAXB_FORMATTED_OUTPUT にプロパティ値Boolean.TRUE を設定すれば、人間の目で読みやすいように改行を挿入した形で出力されるようになります。

ここまでで説明した処理によって生成されたXML データをリスト3 に示しました。JAXB 1.0 のリファレンス・インプリメンテーションでは、日本語の文字列はすべて文字参照のかたち(つまり、Unicodeの文字コードを使って)で出力されています。XML に対応したWeb ブラウザでリスト3 のXML データを開けば、正しい出力結果が得られたことを確認できます(図4)。


図4:リスト3をInternetExplorerで表示した結果】

今回はJAXB の概要や使い方を説明しました。JAXB を利用すると、XML を意識したプログラミングではなく、データそのものの「意味」に注目したプログラミングが行えます。また、要素名の間違いなどの単純なミスを防ぐことができることに加え、要素の構造やデータ型を検証するためのコードが自動生成されるというメリットもあります。

作業効率の向上や、高速なXML アプリケーションを実現するために、ぜひJAXB の利用を検討してみてください。

import javax.xml.bind.*;
import java.io.*;
import java.util.List;
import java.util.Calendar;

// スキーマコンパイラが生成したクラスのインポート
import jp.co.utj.unitec_denki.schema.schedule.*;

public class JAXBSample1 {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {

            JAXBContext jc = JAXBContext.newInstance( "jp.co.utj.unitec_denki.schema.schedule");
            ObjectFactory of = new ObjectFactory();

            Schedule s = of.createSchedule();

            List list = s.getEvent();
            Event e = of.createEvent();
            list.add(e);
            Calendar calStart = Calendar.getInstance();
            calStart.set(2003, Calendar.APRIL, 29, 14, 0, 0);
            calStart.set(Calendar.MILLISECOND, 0);

            e.setStart(calStart);
            e.setLocation("SA 東雲");
            e.setContactTo("TOKYO-FM");
            // 作成したデータの妥当性を検証

            Validator v = jc.createValidator();

            boolean valid = v.validateRoot(s);
            System.err.println(" 検証OK");

            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,Boolean.TRUE);
            fos = new FileOutputStream("schedule.xml");
            // ファイルへ書き出し

            Marshaller m = jc.createMarshaller();

            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,Boolean.TRUE);
            fos = new FileOutputStream("schedule.xml");

            m.marshal(s, fos);
        } catch(JAXBException e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fos != null)
                fos.close();
            } catch(IOException e) {
            }
        }
    }
}
【リスト2 : JAXBSample1.java】

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:schedule xmlns:ns1="http://unitec-denki.utj.co.jp/schema/schedule">
<ns1:event>
<ns1:start>2003-04-29T14:00:00.000+09:00</ns1:start>
<ns1:location>SA&#26481;&#38642;</ns1:location>
<ns1:contactTo>TOKYO-FM</ns1:contactTo>
</ns1:event>
</ns1:schedule>
【リスト3 : 出力結果(schedule.xml)】

※1 余談ですが、インタフェースCalendar のメソッドで月を扱う場合は数値ではなくCalendar.APRIL などのフィールド名で指定することをお勧めします。月を表す数値は0 から始まる(0 は1月を表す)ため、4月のつもりで「4」を指定すると5月になってしまうからです。
※2 本稿では扱いませんが、インタフェースjavax.xml.bind.ValidationEventHandlerをimplements するクラスを作成することにより、妥当性検証時にエラーが発生した場合の動作をカスタマイズすることもできます。

<<本記事の前半へ
>>次の連載記事へ



関連サービス

IT技術およびIT製品の可用性調査・検証業務



この記事と関連の高い記事

関連キーワード:JAXB


関連キーワード:Java


関連キーワード:プログラミング




ページトップへ戻る