先日、JAXBを使用して、xmlファイルからJavaインスタンスを取得する処理を書くことがありました。この記事では、インスタンスのもとになるJavaクラスを、xsdファイル(XMLSchema)から自動生成する手順を説明します。
手順
- xsdファイル作成
- Javaクラス生成(xjcコマンド実行)
- xmlファイル作成 & xmlファイルからjavaインスタンス取得
1.xsdファイル作成
xsdファイルには、xmlの定義を記述します。JavaインスタンスにとってのJavaクラスのようなものです。以下でcars.xsdを例に、XMLSchemaについて説明します。
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.example.org/cars" 
xmlns:tns="http://www.example.org/cars" 
elementFormDefault="qualified">
	<element name="cars">
		<complexType>
			<sequence>
				<element ref="tns:car" minOccurs="1" maxOccurs="unbounded" />
			</sequence>
		</complexType>
	</element>
	<element name="car">
		<complexType>
			<sequence>
				<element ref="tns:maker" minOccurs="1" maxOccurs="1" />
				<element ref="tns:model" minOccurs="1" maxOccurs="1" />
			</sequence>
			<attribute name="number" type="string"/>
		</complexType>
	</element>
	<element name="maker" type="string" />
	<element name="model" type="string" />
</schema>
以下のcars.xmlは、上のxsdファイルに基づいて記述されたxmlファイルです。
<?xml version="1.0" encoding="UTF-8"?>
<cars xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.example.org/cars"
xsi:schemalocation="http://www.example.org/cars cars.xsd">
	<car number="0001">
		<maker>HONDA</maker>
		<model>civic</model>
	</car>
	<car number="0002">
		<maker>LOTUS</maker>
		<model>elise</model>
	</car>
</cars>
1.1.schema要素
名前空間を宣言します。
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.example.org/cars" 
xmlns:tns="http://www.example.org/cars" 
elementFormDefault="qualified">
<!-- 略 -->
</schema>
- xmlns属性では、XMLSchema(xmlの定義)であることを宣言しています。
- targetNameSpace属性では、このxsdファイルで記述する、xml定義の名前空間を宣言しています。
- xmlns:tns属性では、tnsというプレフィックスと、このxsdファイルで記述する、xml定義の名前空間を結びつけています。targetNameSpace属性と同じである必要があります。
1.2.element要素~その1~
xmlの要素を定義します。ここでは、cars要素を定義しています。
<!-- 略 -->
<element name="cars">
	<complexType>
		<sequence>
			<element ref="tns:car" minOccurs="1" maxOccurs="unbounded" />
		</sequence>
	</complexType>
</element>
<!-- 略 -->
- name属性では、要素の名前を設定します。
- complexType要素は、定義する要素が、属性や子要素を持つ場合に設定します。
- sequence要素は、定義する要素が親要素を持つ場合に設定します。
- element要素は、要素を定義します。ここでは子要素carを定義しています。
- ref属性は、他の要素への参照を設定します。ここでは、後述 name="car"を設定したelement要素を参照しています。
- minOccur属性は、最小出現回数を設定します。1を設定すると、必須の要素となります。
- maxOccur属性は、最大出現回数を設定します。unboundedを設定すると、何度でも記述できる要素となります。またunboundedとすると、生成された当要素のJavaインスタンスは、親要素のJavaインスタンスにおいてList型で保持されます。
 
1.3.element要素~その2~
複数の子要素と、属性を持つ場合は以下のように記述します。ここでは、car要素を定義しています。
<!-- 略 -->
<element name="car">
	<complexType>
		<sequence>
			<element ref="tns:maker" minOccurs="1" maxOccurs="1" />
			<element ref="tns:model" minOccurs="1" maxOccurs="1" />
		</sequence>
		<attribute name="number" type="string"/>
	</complexType>
</element>
<!-- 略 -->
- attribute要素では、属性を定義します。
- name属性では、属性名を定義します。
- type属性では、型を定義します。
 
1.4.element要素~その3~
属性も子要素も持たない場合は以下のように記述します。
<!-- 略 -->
<element name="maker" type="string" />
<element name="model" type="string" />
<!-- 略 -->
2.Javaクラスの生成(xjcコマンドの実行)
xjcコマンドを実行し、Javaクラスを生成します。macosのターミナルで実行しています。windowsでも同様にxjcコマンドで、Javaクラスを生成します。
$ xjc cars.xsd
以下のように、Javaクラスが生成されます。生成される場所は、xsdファイルのschema要素 targetNameSpace属性で設定したパスです。
$ xjc cars.xsd
スキーマの解析中...
スキーマのコンパイル中...
org/example/cars/Car.java
org/example/cars/Cars.java
org/example/cars/ObjectFactory.java
org/example/cars/package-info.java
3. xmlファイル作成 & xmlファイルからjavaインスタンス取得
3.1.xmlファイル作成
xmlファイルを作成します。以下のサンプルは上にも書きました。このxmlファイルから、JAXBを使用して、Javaインスタンスを取得します。
<?xml version="1.0" encoding="UTF-8"?>
<cars xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.example.org/cars"
xsi:schemalocation="http://www.example.org/cars cars.xsd">
	<car number="0001">
		<maker>HONDA</maker>
		<model>civic</model>
	</car>
	<car number="0002">
		<maker>LOTUS</maker>
		<model>elise</model>
	</car>
</cars>
- ルート要素carsのxmlns属性に、xsdファイルのtargetNameSpace属性に設定した名前空間を設定します。
- xsi:schemalocation属性には、名前空間とxsdファイルのパスをスペース区切りで記述します。
3.2.xmlファイルからJavaインスタンス取得
上のxmlファイルからCarsインスタンスを取得します。
package test;
public class Main {
	public static void main(String[] args) {
		CarManager manager = new CarManager();
		Cars cars = manager.getCars();
		for (Car car : cars.car) {
			System.out.println(car.getModel());
			System.out.println(" number:[" + car.getNumber() + "]");
			System.out.println(" maker:[" + car.getMaker() + "]");
		}
	}
}
package test;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
public class CarManager {
	public Cars getCars() {
		File file = new File("/Users/ukiuki/Documents/workspace/JAXBTest/src/test/cars.xml");
		try {
			JAXBContext context = JAXBContext.newInstance(Cars.class);
			Unmarshaller unmarshaller = context.createUnmarshaller();
			return (Cars) unmarshaller.unmarshal(file);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
以下は、コンソールです。
civic
 number:[0001]
 maker:[HONDA]
elise
 number:[0002]
 maker:[LOTUS]
参考
参考にしました。ありがとうございます。
JAXBによるXMLデータとプログラムの双方向結合
以上です。ありがとうございました。