こんにちは。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 を指定しないと正常に読み込めなくなっています。
※今回ちょっとハマった箇所
以上、タグがラップされている状態での対応方法でした。