XMLSchema(xsdファイル)からJavaクラスを生成する

先日、JAXBを使用して、xmlファイルからJavaインスタンスを取得する処理を書くことがありました。この記事では、インスタンスのもとになるJavaクラスを、xsdファイル(XMLSchema)から自動生成する手順を説明します。

### 手順
1. xsdファイル作成
2. Javaクラス生成(xjcコマンド実行)
3. xmlファイル作成 & xmlファイルからjavaインスタンス取得

# 1.xsdファイル作成
xsdファイルには、xmlの定義を記述します。JavaインスタンスにとってのJavaクラスのようなものです。以下でcars.xsdを例に、XMLSchemaについて説明します。

``` xml:cars.xsd
<?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:cars.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要素
名前空間を宣言します。

``` xml:cars.xsd
<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要素を定義しています。

``` xml:cars.xsd
<!-- 略 -->
<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要素を定義しています。

``` xml:cars.xsd
<!-- 略 -->
<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~
属性も子要素も持たない場合は以下のように記述します。

``` xml:cars.xsd
<!-- 略 -->
<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:cars.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>
```

- ルート要素carsのxmlns属性に、xsdファイルのtargetNameSpace属性に設定した名前空間を設定します。
- xsi:schemalocation属性には、名前空間とxsdファイルのパスをスペース区切りで記述します。

## 3.2.xmlファイルからJavaインスタンス取得
上のxmlファイルからCarsインスタンスを取得します。

``` java:Main.java
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() + "]");
		}
	}
}

```

``` java:CarManager.java
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データとプログラムの双方向結合](http://www.02.246.ne.jp/~torutk/javahow2/jaxb.html)

以上です。ありがとうございました。