JAXB その2

先週は,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ファイルが生成されました。

Marshallerのプロパティ

前のサンプルではアルファベットしか使用していなかったので,日本語も使ってみました。そのために,サンプルをストリームからライターに変更しました。

            // 4. マーシャリング出力先
            //    出力にはライターをデフォルトエンコーディングで使用
            FileWriter writer 
                = new FileWriter("artists2.xml");
 
            // 5. マーシャリング
            marshaller.marshal(persons, writer);

もちろん,マーシャリングの対象となるオブジェクトには日本語を含むようにしました。

これで,実行してみると...

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persons xmlns="http://xml.javainthebox.net">
  <person sex="MALE" age="66" name="�|�[�� �}�b�J�[�g�j�["/>
  <person sex="MALE" age="65" name="�~�b�N �W���K�["/>
  <person sex="FEMALE" age="58" name="���A���[ �z�v�L���X"/>
</persons>

なお,ここではわかりやすいように,出力結果を整形しました。

出力結果は文字化けを起こしてしまいました。ファイルはWindowsのデフォルトエンコーディングであるShift_JISが使われています(正確にはwindows-31jです)。しかし,XML定義部分のエンコーディングがUTF-8と表記されているため,UTF-8で解釈してしまったようです。

「これはバグか?」と思ったのですが,どうやら仕様のようです。MarshallerインタフェースのJavadocにちゃんと表記されています。

しかし,これではちょっと困ってしまいます。

このような場合,Marshallerインタフェースに対するプロパティを使用します。

Marshallerインタフェースで使用できるプロパティを表1に示しました。

<td #eeffff;padding:="" 5px;padding-left:="" 10px;padding-right:="" 10px;vertical-align:="" top;text-align:="" left;\"="" style="padding: 0px; margin: 0px; line-height: 1;">DOM/SAX/StAX/XSLTがマーシャリングの出力先の場合,START_DOCUMENT/END_DOCUMENTに相当するイベントを発生させるかの有無。デフォルトはBoolean.FALSE
表1 Marshallerインタフェースがサポートするプロパティ
プロパティ名 プロパティの型 説明
Stringjaxb.formatted.outputXMLドキュメントの整形の有無。Boolean.TRUEで整形する。デフォルトはBoolean.FALSE
Stringjaxb.noNamespace
SchemaLocation
XMLドキュメントのxsi:noNamespaceSchemaLocationアトリビュートの指定
Boolean

ここでは,jaxb.encodingプロパティとjaxb.formatted.outputプロパティを指定してみましょう。

サンプルのソースMarshallerSample2.java

MarshallerSample2クラスはプロパティの指定以外の部分はほぼ同じなので,ここでは省略します。

            // 4. マーシャリング出力先
            //    出力にはライタを使用
            FileWriter writer = new FileWriter("artists2.xml");
 
            // 5. marshaller に対するプロパティ設定
            // 出力エンコード
            marshaller.setProperty("jaxb.encoding", 
                                   Charset.defaultCharset().name());
            // 整形
            marshaller.setProperty("jaxb.formatted.output", true);
 
            // 6. マーシャリング
            marshaller.marshal(persons, writer);

Marshallerオブジェクトに対するプロパティの設定にはsetPropertyメソッドを使用します。

ここでは,上述したように2種類のプロパティを指定しています。

まず,jaxb.encodingを使って,出力エンコーディングを指定します。ライターはデフォルトエンコーディングを使用しているので,ここでもデフォルトエンコーディングを指定しました。

そして,jaxb.formatted.outputにtrueを指定して,整形するようにします。

さて,これで実行してみましょう。

<?xml version="1.0" encoding="windows-31j" standalone="yes"?>
<persons xmlns="http://xml.javainthebox.net">
  <person sex="MALE" age="66" name="ポール マッカートニー"/>
  <person sex="MALE" age="65" name="ミック ジャガー"/>
  <person sex="FEMALE" age="58" name="メアリー ホプキンス"/>
</persons>

encodingがwindows-31jになっていることがわかります。もちろん,文字化けはありません。

そして,読みやすいように整形されて出力されています。

このようにアンマーシャリング時に適切なプロパティを指定することで,XMLドキュメントを意図した通りに生成することができるのです。

先週,今週はアンマーシャリング/マーシャリングの対象がファイルでした。来週はファイル以外に対してJAXBを適用してみます。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值