S-JIS[2017-06-10/2018-10-01] 変更履歴

Java XML JAXB

JavaXMLを操作するJAXBについて。


概要

JAXBはJava Architecture for XML Bindingの略で、XMLのデータとJavaのクラスを紐付ける(バインディングする・デシリアライズする)ことが出来る。
JAXBはJava6(JDK1.6)からJavaの標準APIの仲間入りをしたらしい。(なので特別なライブラリーを入れなくても使用できる)

Java11でJAXBは標準APIから削除された。[2018-10-01]


XMLファイルを読み込む例

以下のようなXMLファイルを読み込む例。

example.xml:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<record><column1>aaa</column1><column2>111</column2></record>
<record><column1>bbb</column1><column2>222</column2></record>
</root>

まず、読み込んだXMLデータを保持するクラス(JavaBeans)を用意する。

ExampleBean.java:

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "root")
public class ExampleBean {

	private List<RecordBean> recordList;
	@XmlElement(name = "record")
	public List<RecordBean> getRecordList() {
		return recordList;
	}

	public void setRecordList(List<RecordBean> recordList) {
		this.recordList = recordList;
	}
	@Override
	public String toString() {
		if (recordList == null) {
			return "null[]";
		}
		return recordList.toString();
	}
}

XMLデータのルート要素名を@XmlRootElementで指定する。

今回の例ではルート要素内にrecordタグが複数入っているので、ひとつのrecordタグのデータを表すRecordBeanクラスを用意し、
ExampleBeanではRecordBeanのリストを保持する。
@XmlElementをゲッターメソッドに付けてタグ名を指定する。(セッターメソッドに付けても大丈夫そうだったけど)

RecordBean.java:

public class RecordBean {

	private String column1;
	private String column2;
	public String getColumn1() {
		return column1;
	}

	public void setColumn1(String column1) {
		this.column1 = column1;
	}
	public String getColumn2() {
		return column2;
	}

	public void setColumn2(String column2) {
		this.column2 = column2;
	}
	@Override
	public String toString() {
		return String.format("(%s,%s)", column1, column2);
	}
}

RecordBeanクラスは、recordタグひとつ分のデータを保持するJavaBean。
column1,column2といったタグ名とJavaBeanのプロパティー名が一致していれば、特にアノテーションを付ける必要は無い。


XmlJaxbExample.java:

import java.io.IOException;
import java.io.InputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class XmlJaxbExample {

	public static void main(String... args) throws IOException {
		new XmlJaxbExample().read("example.xml");
	}
	public void read(String fileName) throws IOException {
		ExampleBean example;
		try (InputStream is = getClass().getResourceAsStream(fileName)) {
			JAXBContext context = JAXBContext.newInstance(ExampleBean.class);
			Unmarshaller unmarshaller = context.createUnmarshaller();
			example = (ExampleBean) unmarshaller.unmarshal(is);
		} catch (JAXBException e) {
			throw new IOException(e);
		}

		System.out.println(example);
	}
}

まず、JAXBContextのnewInstanceメソッドを呼び出してJAXBContextインスタンスを生成する。
このときにXMLのスキーマ情報を渡す必要があるようだが、今回は変換先のJavaBeanクラスを指定している。

そしてJAXBContextからUnmarshallerを生成し、unmarshalメソッドを呼び出す。
するとXMLファイルを読み込んでJavaのインスタンスに変換してくれる。
(unmarshalメソッドの戻り型はObjectなので、自分でキャストする必要がある)

InputStreamはunmarshalメソッド内でクローズされるようだが、念のためにtry-with-resources構文でInputStreamをクローズしている。


JAXBクラスを使うと、もっとシンプルに書ける。
(JAXBContextやUnmarshallerの生成が内部で自動的に行われる)

import javax.xml.bind.DataBindingException;
import javax.xml.bind.JAXB;
	public void read2(String fileName) throws IOException {
		ExampleBean example;
		try (InputStream is = getClass().getResourceAsStream(fileName)) {
			example = JAXB.unmarshal(is, ExampleBean.class);
		} catch (DataBindingException e) {
			throw new IOException(e);
		}

		System.out.println(example);
	}

XMLファイルを出力する例

以下のようなXMLファイルを出力する例。

example.xml:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <record>
        <column1>aaa</column1>
        <column2>111</column2>
    </record>
    <record>
        <column1>bbb</column1>
        <column2>222</column2>
    </record>
</root>

XmlJaxbExample.java:

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class XmlJaxbExample {

	public static void main(String... args) throws IOException {
		List<RecordBean> list = new ArrayList<>();
		list.add(new RecordBean("aaa", "111"));	// RecordBeanにコンストラクターを追加した
		list.add(new RecordBean("bbb", "222"));
		ExampleBean example = new ExampleBean();
		example.setRecordList(list);

		new XmlJaxbExample().write("D:/temp/example.xml", example);
	}
	public void write(String fileName, ExampleBean example) throws IOException {
		try (FileOutputStream os = new FileOutputStream(fileName)) {
			JAXBContext context = JAXBContext.newInstance(example.getClass());
			Marshaller marshaller = context.createMarshaller();
			marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 整形して出力する

			marshaller.marshal(example, os);
		} catch (JAXBException e) {
			throw new IOException(e);
		}
	}
}

JAXBContextインスタンスの生成方法はXML読み込みの例と同じ。

JAXBContextからMarshallerを生成してmarshalメソッドを呼び出すと、XMLファイルが出力される。
このとき、JAXB_FORMATTED_OUTPUTをtrueにしないと、出力されたデータは一切改行されず(当然インデントも入らず)、1行のみのXMLファイルになる。

marshalメソッド内では出力先のリソース(OutputStream)をクローズしないので、自分で(try-with-resources構文で)OutputStreamをクローズする必要がある。


JAXBクラスを使うと、もっとシンプルに書ける。
(JAXBContextやMarshallerの生成が内部で自動的に行われる)

import java.io.File;

import javax.xml.bind.DataBindingException;
import javax.xml.bind.JAXB;
	public void write2(String fileName, ExampleBean example) throws IOException {
		try (FileOutputStream os = new FileOutputStream(fileName)) {
			JAXB.marshal(example, os);
		} catch (DataBindingException e) {
			throw new IOException(e);
		}
	}
	public void write3(String fileName, ExampleBean example) throws IOException {
		try {
			JAXB.marshal(example, new File(fileName));
		} catch (DataBindingException e) {
			throw new IOException(e);
		}
	}

この場合、JAXB_FORMATTED_OUTPUTはtrueになっている。


XMLへ戻る / 新機能へ戻る / Java目次へ戻る
メールの送信先:ひしだま