สร้าง XML file จาก Object ใน Java

สร้าง XML file จาก Object ใน Java

สำหรับส่วนที่สั่งให้ทำงาน เช่น ใน main method

// 1. สร้าง Object ที่ต้องการแปลง
Student student = new Student(65001, "สมศักดิ์ เรียนดี", "วิศวกรรมคอมพิวเตอร์");

// 2. สร้าง JAXB Context และ Marshaller
JAXBContext context = JAXBContext.newInstance(Student.class);
Marshaller marshaller = context.createMarshaller();

// 3. ตั้งค่าให้ XML ที่สร้างออกมาสวยงาม (มีการย่อหน้า)
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

// 4. ทำการ Marshalling (แปลง Object เป็น XML)
// แสดงผลลัพธ์ออกทางหน้าจอ
System.out.println("--- XML Output ---");
marshaller.marshal(student, System.out);

// หรือบันทึกเป็นไฟล์
marshaller.marshal(student, new File("student.xml"));
System.out.println("\nไฟล์ student.xml ถูกสร้างเรียบร้อยแล้ว");

แต่ตัว class เราต้องมีการเตรียมการก่อน จะได้รู้ว่า ค่าไหนเป็น tag อะไร ใน xml file

Tag ที่น่าจะใช้บ่อยๆ

  • @XmlRootElement
  • @XmlElement
  • @XmlAttribute
  • @XmlAccessorType
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;

/**
 *
 * @author Thada
 */
@XmlRootElement(name = "student") // บอกว่า Root element ของ XML คือ <student>
public class Student {
    private int id;
    private String name;
    private String major;

    // Constructors
    public Student() {}

    public Student(int id, String name, String major) {
        this.id = id;
        this.name = name;
        this.major = major;
    }

    // Getters and Setters
    @XmlElement(name = "student_id") // กำหนดชื่อ tag สำหรับ field นี้
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }

    @XmlElement(name = "full_name")
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @XmlElement(name = "faculty")
    public String getMajor() { return major; }
    public void setMajor(String major) { this.major = major; }
}

Library ที่จำเป็นต้องใช้คือ JAXB ซึ่งหลังๆมานี้ไม่ได้เป็นส่วนหนึ่งใน Java Standard SDK แล้ว

// https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api
implementation("javax.xml.bind:jaxb-api:2.3.1")
// https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl
implementation("com.sun.xml.bind:jaxb-impl:4.0.5")

@XmlAccessorType(XmlAccessType.FIELD)

Annotation นี้ใช้กำหนดว่า JAXB ควรจะเข้าถึงข้อมูลส่วนไหนในคลาสเพื่อนำไปสร้างเป็น XML Element โดย XmlAccessType.FIELD เป็นการสั่งให้ JAXB เข้าถึง “Field” หรือตัวแปรทั้งหมดในคลาสโดยตรง ไม่ว่าตัวแปรนั้นจะเป็น public, private, หรือ protected ก็ตาม

  • @XmlAccessorType: Annotation สำหรับกำหนดรูปแบบการเข้าถึงข้อมูล
  • XmlAccessType.FIELD: ระบุให้ JAXB สนใจที่ Field (ตัวแปร) ของคลาสโดยตรง โดยไม่ต้องผ่าน method getter หรือ setter

พูดง่ายๆ คือ @XmlAccessorType เป็นตัวกำหนด “กฎ” ว่า JAXB จะมองหาสิ่งที่จะแปลงเป็น XML จากที่ไหน (Field, Getter/Setter, ฯลฯ) ส่วน @XmlElement ใช้สำหรับ “ปรับแต่ง” หรือ “ชี้เป้า” เป็นพิเศษ

เมื่อใช้ @XmlAccessorType(XmlAccessType.FIELD)

  • ไม่จำเป็นต้องใส่ @XmlElement ที่ getter เลย JAXB จะอ่านค่าจากตัวแปร private หรือ public โดยอัตโนมัติ
  • ถ้าจะใส่ @XmlElement ก็ต่อเมื่อต้องการปรับแต่งบางอย่างที่ Field นั้นๆ เช่น เปลี่ยนชื่อ Tag ใน XML

เมื่อไม่มี @XmlAccessorType ถูกกำหนดไว้ JAXB จะทำงานในโหมด PUBLIC_MEMBER โดยอัตโนมัติ ซึ่งมีกฎดังนี้:

  • JAXB จะสแกนหา public getter/setter ทุกคู่ และ public field ทั้งหมด เพื่อนำไปสร้างเป็น XML
  • มันจะไม่สนใจ private field โดยสิ้นเชิง (ตราบใดที่ไม่มี public getter/setter ที่สอดคล้องกัน)

เปรียบเสมือน JAXB มองคลาสของคุณผ่าน “Interface สาธารณะ” ซึ่งก็คือ public method และ public field นั่นเอง

การใส่ @XmlElement ที่ public getter เป็นวิธีที่สอดคล้องกับโหมดการทำงานเริ่มต้นนี้มากที่สุด

  • ความสอดคล้อง: คุณกำลังติดป้ายกำกับ (Annotation) ในตำแหน่งเดียวกับที่ JAXB กำลังมองหาข้อมูลอยู่แล้ว ทำให้โค้ดเข้าใจง่ายและตรงไปตรงมา
  • รองรับ Logic ใน Getter: หาก getter ของคุณมีตรรกะบางอย่าง (เช่น การจัดรูปแบบข้อความ) การใส่ Annotation ที่ getter จะรับประกันว่าผลลัพธ์ที่ผ่านตรรกะแล้วเท่านั้นที่จะถูกนำไปใส่ใน XML

ถ้าให้ง่าย ก็ใช้ @XmlAccessorType เป็น FIELD ไปก่อน

ตรงไหนอยากให้พิเศษก็ค่อยแทรก @XmlElement เป็นตัวๆไป

@XmlAttribute 🏷️

Annotation นี้จะสั่งให้ JAXB แปลง field ของ Java ให้กลายเป็น attribute ของ tag แม่ (parent element) แทนที่จะสร้างเป็น tag ลูก (child element) ที่ซ้อนอยู่ข้างใน

@XmlRootElement(name = "book")
@XmlAccessorType(XmlAccessType.FIELD)
public class Book {

    // ใช้ @XmlAttribute เพื่อกำหนดให้ "id" เป็น attribute ของ <book>
    @XmlAttribute
    private long id;

    // ใช้ @XmlElement (หรือปล่อยว่าง) เพื่อให้ "title" เป็น element ลูก
    @XmlElement
    private String title;

    // Constructors, Getters, Setters...
}
<book id="123">
    <title>JAXB for Beginners</title>
</book>

@XmlSeeAlso({Drill.class})

ใช้เพื่อแจ้งให้ JAXB ทราบล่วงหน้าเกี่ยวกับคลาสย่อย (subclass) ที่อาจเกิดขึ้นเมื่อทำงานกับคลาสแม่ (superclass) ที่มีความสัมพันธ์แบบ Inheritance (การสืบทอดคุณสมบัติ)

พูดง่ายๆ คือ มันเป็นการบอก JAXB ว่า “เวลาคุณเจอคลาสแม่นี้ ให้เตรียมรู้จักคลาสลูกชื่อ Drill ไว้ด้วยนะ เพราะมันอาจจะถูกใช้งาน

// คลาสแม่ (Superclass)
@XmlAccessorType(XmlAccessType.FIELD)
public abstract class Tool {
    private String name;
}

// คลาสลูก (Subclass)
public class Drill extends Tool {
    private int rpm;
}

// คลาสที่เก็บรายการ Tool
@XmlRootElement
public class ToolBox {
    private List<Tool> tools;
}

แล้วเราพยายามแปลง (Marshal) ToolBox ที่มี Drill อยู่ข้างใน โปรแกรมจะเกิด Error 💥 เพราะตอนที่ JAXB สร้าง Context จากคลาส ToolBox มันจะเห็นแค่ Tool แต่ไม่รู้จัก Drill

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *