先週は,JAXBを用いてXMLのスキーマからJavaのクラス生成ができることを紹介しました。そして,生成したクラスを使用してXMLドキュメントからJavaのオブジェクトを生成させました。

XMLのスキーマとJavaのクラスを対応させることをバインディング,XMLドキュメントからJavaのオブジェクトを生成させることをアンマーシャリングということも紹介しました。

今週はアンマーシャリングの逆,マーシャリングを行ってみます。つまり,JavaオブジェクトからXMLドキュメントを生成します。

先週使用した,複数の名前を表すスキーマを今週も使用しましょう。XML Schemaで表したスキーマを次に示します。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0"
    targetNamespace="http://xml.javainthebox.net" 
    xmlns:tns="http://xml.javainthebox.net"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
  <xs:element name="persons">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="tns:person" 
                    minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
 
  <xs:element name="person">
    <xs:complexType>
      <xs:attribute name="name" type="xs:string"/>
      <xs:attribute name="age" type="xs:int"/>
      <xs:attribute name="sex" type="tns:sex"/>
    </xs:complexType>
  </xs:element>
 
  <xs:simpleType name="sex">
    <xs:restriction base="xs:string">
      <xs:enumeration value="MALE"/>
      <xs:enumeration value="FEMALE"/>
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

スキーマの詳細な解説は行いませんが,何を表しているのかだけ簡単に説明しましょう。

スキーマが四つのパートに別れていることは,すぐにわかるはずです。1番目のバートがスキーマの定義,次がルートタグであるpersonsタグの定義です。personsタグにはpersonタグが複数含まれています。

3番目のパートが,personタグの定義です。personタグにはname,age,sexの三つのアトリビュートが存在します。

最後のパートがsexのアトリビュートに使用できる型の定義です。sexは性別なので,MALEかFEMALEのどちらかの値をとります。

まず,このスキーマからJavaのクラスをxjcコマンドを使って,作成します。

C:\jaxb>xjc persons.xsd
parsing a schema...
compiling a schema...
net\javainthebox\xml\ObjectFactory.java
net\javainthebox\xml\Person.java
net\javainthebox\xml\Persons.java
net\javainthebox\xml\Sex.java
net\javainthebox\xml\package-info.java

ファクトリクラスのObjectFactoryクラスとパッケージの定義を行うpackage-info.java以外はすべてスキーマで定義された型に対応しています。

ここまでが,先週のおさらいです。

今週は,これらのクラスを利用してXMLドキュメントを生成していきましょう。

先週紹介したように,XMLドキュメントからJavaのオブジェクトを生成するアンマーシャリングにはjavax.xml.bind.Unmarshallerインタフェースを使用します。

これと同じように,JavaオブジェクトからXMLドキュメントを生成するマーシャリングにはjavax.xml.bind.Marshallerインタフェースを使用します。

Marshallerはインタフェースなので,オブジェクトを得るにはファクトリが必要です。Unmarshallerインタフェースの場合と同じく,このファクトリクラスはjavax.xml.bind.JAXBContextクラスになります。

サンプルのソース MarshallerSample1.java

このサンプルはpersons.xsdで定義されたXMLドキュメントを読み込み,Personsオブジェクトを生成します。

public class MarshallerSample1 {
    public MarshallerSample1() {
        try {
            // 1. JAXBContextオブジェクトの生成
            // 引数はパッケージもしくはクラス
            JAXBContext context 
                = JAXBContext.newInstance("net.javainthebox.xml");
 
            // 2. Marsallerオブジェクトの取得
            Marshaller marshaller = context.createMarshaller();
 
            // 3. マーシャリングするオブジェクトを準備
            Persons persons = createPersons();
 
            // 4. マーシャリング出力先
            //    出力にはストリームを使用
            FileOutputStream stream 
                = new FileOutputStream("artists2.xml");
 
            // 5. マーシャリング
            marshaller.marshal(persons, stream);
        } catch (FileNotFoundException ex) {
            // 例外処理
            System.err.println("artists2.xml がオープンできません");
        } catch (JAXBException ex) {
            // 例外処理
            System.err.println("マーシャリングに失敗しました");
        }
    }

JAXBContextオブジェクトの生成には,先週も紹介したようにJAXBContextクラスのnewInstanceメソッドを使用します。

青字で示した部分がMarshallerオブジェクトを生成している部分です。Unmarshallerオブジェクトの場合はcreateUnmarshallerメソッド,Marshallerオブジェクトの場合はcreateMarshallerメソッドを使用します。

マーシャリングには,赤字で示したように,Marshallerインタフェースのmarshalメソッドをコールします。第1引数がマーシャリングするオブジェクト,第2引数がマーシャリングする出力先を示します。

ここでは,ストリームを使用しましたが,アンマーシャリングと同様,多用な出力先を選べます。

  • ストリーム/ライター
  • XSLTのリザルト
  • DOMのノード
  • SAXのコンテントハンドラー
  • StAXのXMLStreamWriter/XMLEventWriter

マーシャリングの対象となるオブジェクトを生成しているのがcreatePersonsメソッドです。

    private Persons createPersons() {
        Persons persons = new Persons();

        Person person = new Person();
        person.setName("Paul McCartney");
        person.setAge(66);
        person.setSex(Sex.MALE);
        persons.getPerson().add(person);

        person = new Person();
        person.setName("Mick Jagger");
        person.setAge(65);
        person.setSex(Sex.MALE);
        persons.getPerson().add(person);

        person = new Person();
        person.setName("Mary Hopkins");
        person.setAge(58);
        person.setSex(Sex.FEMALE);
        persons.getPerson().add(person);

        return persons;
    }

xjcで生成したPersonsクラス,Personクラスはごくごく普通のクラスです。newを使用して普通に生成し,セッターでフィールドに値をセットしていくだけです。

ソースができたので,コンパイルして実行してみましょう。xjcで生成されたクラスをコンパイルすることを忘れないでください。

正しく動作していれば,artists2.xmlファイルが生成できているはずです。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><persons xmlns="http://xml.javainthebox.net"><person sex="MALE" age="66" name="Paul McCartney"/><person sex="MALE" age="65" name="Mick Jagger"/><person sex="FEMALE" age="58" name="Mary Hopkins"/></persons>

整形されていないのでちょっと見にくいですが,意図したとおりのXMLファイルが生成されました。