網頁

2021/4/20

Java JAXB 讀取xml檔為物件範例 read xml file to object example

Java使用JAXB(Java Architecture for XML Binding)將xml檔內容解析(unmarshal)為Java物件範例如下。

例如employee.xml位在Maven專案的src/main/resources,內容如下。

employee.xml

<?xml version="1.0" encoding="UTF-8" ?>
<employee>
    <id>100</id>
    <name>John</name>
    <email>john@abc.com</email>
    <age>29</age>
    <onBoardDate>2021-04-19</onBoardDate>
    <department>
        <id>22</id>
        <name>Marketing</name>
        <manager>
            <id>52</id>
            <name>Mary</name>
            <email>mary@abc.com</email>
        </manager>
    </department>
    <exts>
        <ext>201</ext>
        <ext>202</ext>
    </exts>
</employee>

在要轉成的Java物件Employee類別上使用JAXB的annotation來標示對應的xml元素如下。

  • @XmlRootElement標註在類別,代表xml的根元素,也就是上面的<employee>
  • @XmlElement標註在類別欄位,代表xml元素,也就是上面的<id><name><email><age><onBoardDate><department>等。
  • @XmlType標註在類別,用來指定輸出順序。
  • @XmlAccessorType標註在類別,用來決定欄位是否綁定對應的xml元素,若無設定此注釋則預設為XmlAccessType.PUBLIC_MEMBER
  • @XmlElementWrapper標註集合欄位。代表集合xml元素的外包元素,也就是上面的<exts>

Employee

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Arrays;
import java.util.Date;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = {"id", "name", "email", "age", "onBoardDate", "department", "exts"})
@XmlRootElement(name = "employee")
public class Employee {

    private int id;
    private String name;
    private String email;
    private int age;

    @XmlJavaTypeAdapter(DateAdapter.class)
    private Date onBoardDate;

    private Department department;

    @XmlElementWrapper(name = "exts")
    @XmlElement(name = "ext")
    private String[] exts;

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                ", onBoardDate=" + onBoardDate +
                ", department=" + department +
                ", exts=" + Arrays.toString(exts) +
                '}';
    }
    // getters and setters
}

xml內層元素的對應類別。可獨立為一個類別或以公開靜態巢狀類別(public static nested class)的型式存在Employee

Department

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = {"id", "name", "manager"})
public class Department {

    private int id;
    private String name;
    private Manager manager;

    @Override
    public String toString() {
        return "Department{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", manager=" + manager +
                '}';
    }
    // getters and setters
}

Manager

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = {"id", "name", "email"})
public class Manager {

    private int id;
    private String name;
    private String email;

    @Override
    public String toString() {
        return "Manager{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
    // getters and setters
}

讀取的值皆為字串,如果要轉成特定型態如日期Date,則可自訂一個實作XmlAdapter的類別做為@XmlJavaTypeAdapter的參數並掛在要轉換的欄位上進行轉換。例如下面的DateAdapter

DateAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateAdapter extends XmlAdapter<String, Date> {

    private static final String PATTERN = "yyyy-MM-dd";

    @Override
    public Date unmarshal(String v) throws Exception {
        return new SimpleDateFormat(PATTERN).parse(v);
    }

    @Override
    public String marshal(Date v) {
        return new SimpleDateFormat(PATTERN).format(v);
    }
}

轉換方式如下。

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;

public class Main {

    private static final String XML_PATH = "src/main/resources/employee.xml";

    public static void main(String[] arges) throws JAXBException {

        JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        Employee employee = (Employee) unmarshaller.unmarshal(new File(XML_PATH));

        System.out.println(employee);

    }

}

印出結果

Employee{id=100, name='John', email='john@abc.com', age=29, onBoardDate=Mon Apr 19 00:00:00 CST 2021, department=Department{id=22, name='Marketing', manager=Manager{id=52, name='Mary', email='mary@abc.com'}}, exts=[201, 202]}

轉換的物件內容如下

Employee{
    id=100, 
    name='John', 
    email='john@abc.com', 
    age=29, 
    onBoardDate=Mon Apr 19 00:00:00 CST 2021, 
    department=Department{
        id=22, 
        name='Marketing', 
        manager=Manager{
            id=52, 
            name='Mary', 
            email='mary@abc.com'
        }}, 
    exts=[201, 202]
}


沒有留言:

張貼留言