Pocket

こんにちは。kikuchiです。

プロジェクトでちょっと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オブジェクトへマッピングしてくれます。

    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());
        }
    }
    
  • SampleData.java
  • data をマッピングするクラスです。

    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;
    
        // 略
    }
    

    出力結果はこちら。

    SampleData [dataId=1, dataName=でーた1]
    

    簡単ですね。

    次に、dataが複数ある場合…

  • ReadXmlSample.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());
            }
        }
    }
    
  • SampleResponse.java
  • dataList をマッピングするクラスです。※data の List

    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;
    
        // 略
    }
    

    ※SampleData.java は変更無し

    出力結果はこちら。

    SampleData [dataId=1, dataName=でーた1]
    SampleData [dataId=2, dataName=でーた2]
    SampleData [dataId=3, dataName=でーた3]
    

    出来てますね。

    最後に、一番外側を1つのタグでくくり、その中に複数要素が有り、かつリストになっている場合(日本語だと分かりにくいのでデータ参照)

  • ReadXmlSample.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());
            }
        }
    }
    
  • SampleResult.java
  • result 要素のマッピング用クラスです。

    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;
    
        // 略
    }
    
  • SampleResponse.java
  • result の追加と、dataList フィールドに対して @XmlElementWrapper アノテーションを付加します。
    @XmlElementWrapper に指定する name は、dataList になります。

    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;
    
        // 略
    }
    

    ※SampleData.java は変更無し

    出力結果はこちら。

    SampleResult [status=1, count=3]
    SampleData [dataId=1, dataName=でーた1]
    SampleData [dataId=2, dataName=でーた2]
    SampleData [dataId=3, dataName=でーた3]
    

    タグ構成として、
    response
    └dataList
     └data
    となっているので、@XmlElementWrapper で dataList を指定しないと正常に読み込めなくなっています。
    ※今回ちょっとハマった箇所

    以上、タグがラップされている状態での対応方法でした。