こんにちは。kkです。
プロジェクトでちょっとXMLを読み込む機会があったので、今回はその中で少しハマった所とその対応を紹介します。
XML→オブジェクトの変換はJAXBを使用します。
https://docs.oracle.com/javase/jp/8/api/javax/xml/bind/JAXB.html
https://ja.wikipedia.org/wiki/Java_Architecture_for_XML_Binding
まずは簡単なXMLの変換
- ReadXmlSample.java
JAXB.unmarshal を使うことにより、XMLからJavaオブジェクトへマッピングしてくれます。
[java]
package jp.co.opentone.kikuchi.sample.xml;
import java.io.StringReader;
import javax.xml.bind.JAXB;
public class ReadXmlSample {
public static void main(String[] args) {
// XMLデータ
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<data>" // データ情報
+ " <dataID>1</dataID>" // データID
+ " <dataName>でーた1</dataName>" // データ名
+ "</data>"
+ "";
SampleData data = JAXB.unmarshal(new StringReader(xml), SampleData.class);
System.out.println(data.toString());
}
}
[/java]- SampleData.java
data をマッピングするクラスです。
[java]
package jp.co.opentone.kikuchi.sample.xml;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "data")
public class SampleData {
@XmlElement(name = "dataID")
private int dataId;
@XmlElement(name = "dataName")
private String dataName;
// 略
}
[/java]出力結果はこちら。
[text] SampleData [dataId=1, dataName=でーた1] [/text]
簡単ですね。
次に、dataが複数ある場合…
- ReadXmlSample.java
[java]
package jp.co.opentone.kikuchi.sample.xml;
import java.io.StringReader;
import javax.xml.bind.JAXB;
public class ReadXmlSample {
public static void main(String[] args) {
// XMLデータ
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<dataList>"
+ " <data>" // データ情報
+ " <dataID>1</dataID>" // データID
+ " <dataName>でーた1</dataName>" // データ名
+ " </data>"
+ " <data>"
+ " <dataID>2</dataID>"
+ " <dataName>でーた2</dataName>"
+ " </data>"
+ " <data>"
+ " <dataID>3</dataID>"
+ " <dataName>でーた3</dataName>"
+ " </data>"
+ "</dataList>"
+ "";
SampleResponse response = JAXB.unmarshal(new StringReader(xml), SampleResponse.class);
for (SampleData data: response.getDataList()) {
System.out.println(data.toString());
}
}
}
[/java]- SampleResponse.java
dataList をマッピングするクラスです。※data の List
[java]
package jp.co.opentone.kikuchi.sample.xml;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
@XmlAccessorType(XmlAccessType.FIELD)
public class SampleResponse {
// ここで指定する要素は、dataList では無く、data
@XmlElement(name = "data")
List<SampleData> dataList;
// 略
}
[/java]※SampleData.java は変更無し
出力結果はこちら。
[text] SampleData [dataId=1, dataName=でーた1] SampleData [dataId=2, dataName=でーた2] SampleData [dataId=3, dataName=でーた3] [/text]
出来てますね。
最後に、一番外側を1つのタグでくくり、その中に複数要素が有り、かつリストになっている場合(日本語だと分かりにくいのでデータ参照)
- ReadXmlSample.java
[java]
package jp.co.opentone.kikuchi.sample.xml;
import java.io.StringReader;
import javax.xml.bind.JAXB;
public class ReadXmlSample {
public static void main(String[] args) {
// XMLデータ
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<response>" // レスポンス情報
+ " <result>" // 結果情報
+ " <status>1</status>" // 処理結果ステータス
+ " <count>3</count>" // 取得件数
+ " </result>"
+ " <dataList>" // データ情報のリスト
+ " <data>" // データ情報
+ " <dataID>1</dataID>" // データID
+ " <dataName>でーた1</dataName>" // データ名
+ " </data>"
+ " <data>"
+ " <dataID>2</dataID>"
+ " <dataName>でーた2</dataName>"
+ " </data>"
+ " <data>"
+ " <dataID>3</dataID>"
+ " <dataName>でーた3</dataName>"
+ " </data>"
+ " </dataList>"
+ "</response>"
+ "";
SampleResponse response = JAXB.unmarshal(new StringReader(xml), SampleResponse.class);
System.out.println(response.getResult().toString());
for (SampleData data: response.getDataList()) {
System.out.println(data.toString());
}
}
}
[/java]- SampleResult.java
result 要素のマッピング用クラスです。
[java]
package jp.co.opentone.kikuchi.sample.xml;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "result")
public class SampleResult {
@XmlElement(name = "status")
private int status;
@XmlElement(name = "count")
private int count;
// 略
}
[/java]- SampleResponse.java
result の追加と、dataList フィールドに対して @XmlElementWrapper アノテーションを付加します。
@XmlElementWrapper に指定する name は、dataList になります。
[java]
package jp.co.opentone.kikuchi.sample.xml;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "response")
public class SampleResponse {
@XmlElement(name = "result")
SampleResult result;
// dataList の名前で @XmlElementWrapper を付加
@XmlElementWrapper(name = "dataList")
@XmlElement(name = "data")
List<SampleData> dataList;
// 略
}
[/java]※SampleData.java は変更無し
出力結果はこちら。
[text] SampleResult [status=1, count=3] SampleData [dataId=1, dataName=でーた1] SampleData [dataId=2, dataName=でーた2] SampleData [dataId=3, dataName=でーた3] [/text]
タグ構成として、
response
└dataList
└data
となっているので、@XmlElementWrapper で dataList を指定しないと正常に読み込めなくなっています。
※今回ちょっとハマった箇所
以上、タグがラップされている状態での対応方法でした。

