JAXB

JAXB 介绍

JAXB(Java Architecture for XML Binding)是Java API的一部分,它提供了一种将Java类映射到XML结构的方式,也可以将XML结构转换为Java类的实例。它是一种简化Java与XML交互的方式,可以通过注释或外部XML映射文件将Java类与XML元素映射起来。

JAXB包含了两个主要的类:UnmarshallerMarshallerUnmarshaller可以将XML文档转换为Java对象,而Marshaller则可以将Java对象转换为XML文档。而XJC是JAXB的一个辅助工具,用于根据XML Schema生成Java类。它会自动解析XML Schema中定义的元素和属性,并将它们转换为Java类和字段。使用XJC可以减少手动编写Java类的工作量,同时保证生成的Java类与XML Schema定义的数据模型一致。

JAXB可以与其他XML处理技术,如DOM、SAX和StAX一起使用。使用JAXB可以轻松地实现Java与XML的转换,使Java开发人员更加专注于业务逻辑的实现。

xjc 介绍

xjc 是 JAXB 工具集中的一个命令行工具,可以根据 XML Schema 文件自动生成 Java 类。jdk 11以下都自带xjc, 位置: %JAVA_HOME%\bin\xjc.exe;

下面是使用 xjc 工具生成 Java 类的步骤:

示例一和示例二的区别

  1. xsd的定义结构不同,示例二采用类似匿名类的形式进行编写。
  2. 如果生成的ObjectFactory.java中包含@XmlElementDecl , 则使用ObjectFactory.java进行解析,如示例一;不包含则使用对应的类来解析,如示例二
  3. 示例一:需要手动给PersonType.java中增加@XmlRootElement,才能将java对象解析成xml

XML与java对象之间的转换(示例一)

1. 编写 XML Schema 文件

使用任何文本编辑器编写 XML Schema 文件。下面是一个示例 XML Schema 文件:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="person" type="personType"/>
    <xs:complexType name="personType">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="age" type="xs:int"/>
            <xs:element name="address" type="addressType"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="addressType">
        <xs:sequence>
            <xs:element name="city" type="xs:string"/>
            <xs:element name="country" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

对应的person.xml文件是:

<?xml version="1.0" encoding="utf-8" ?>
<person>
    <name>zhangsan</name>
    <age>13</age>
    <address>
        <city>china</city>
        <country>beijing</country>
    </address>
</person>
2. 运行 xjc 工具
# -d 参数指定生成的 Java 类的输出目录,-p 参数指定生成的 Java 类的包名
# 该命令会自动生成一个名为 PersonType.java 的 Java 类和名为addressType.java的Java类,以及一个名为 ObjectFactory.java 的工厂类,用于创建 JAXBContext 对象
# xjc schema.xsd -d src -p com.example.person
xjc resource/xsd/person.xsd -p test_person.gensrc
3.生成java类

@XmlAccessorType 注解用于指定 JAXB 应该使用属性访问器而非字段访问器,

@XmlType 注解用于指定类的名称和属性顺序

@XmlRootElement 注解用于指定类在 XML 文档中的根元素名称

//  Persion.java
// 此文件是由 JavaTM Architecture for XML Binding (JAXB) 引用实现 v2.2.8-b130911.1802 生成的
// 请访问 <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// 在重新编译源模式时, 对此文件的所有修改都将丢失。
// 生成时间: 2023.03.29 时间 11:42:15 AM CST 
//

package test_person.gensrc;

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


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "personType", propOrder = {
    "name",
    "age",
    "address"
})
public class PersonType {

    @XmlElement(required = true)
    protected String name;
    protected int age;
    @XmlElement(required = true)
    protected AddressType address;

    // 此处省略 get 和 set方法
}
// AddressType.java
// 此文件是由 JavaTM Architecture for XML Binding (JAXB) 引用实现 v2.2.8-b130911.1802 生成的
// 请访问 <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// 在重新编译源模式时, 对此文件的所有修改都将丢失。
// 生成时间: 2023.03.29 时间 11:42:15 AM CST 
//

package test_person.gensrc;

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


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "addressType", propOrder = {
    "city",
    "country"
})
public class AddressType {

    @XmlElement(required = true)
    protected String city;
    @XmlElement(required = true)
    protected String country;

	// get 和 set方法省略

}
// ObjeceMapper.java  --用于创建 JAXBContext 对象
// 此文件是由 JavaTM Architecture for XML Binding (JAXB) 引用实现 v2.2.8-b130911.1802 生成的
// 请访问 <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// 在重新编译源模式时, 对此文件的所有修改都将丢失。
// 生成时间: 2023.03.29 时间 11:42:15 AM CST 
//

package test_person.gensrc;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

@XmlRegistry
public class ObjectFactory {

    private final static QName _Person_QNAME = new QName("", "person");

    public ObjectFactory() {
    }

    public PersonType createPersonType() {
        return new PersonType();
    }

    public AddressType createAddressType() {
        return new AddressType();
    }

    @XmlElementDecl(namespace = "", name = "person")
    public JAXBElement<PersonType> createPerson(PersonType value) {
        return new JAXBElement<PersonType>(_Person_QNAME, PersonType.class, null, value);
    }

}
4.XML与java对象之间的转换code
package TestXjc.com.example.persion;

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

public class Test {
    public static void main(String[] args) throws Exception {
        // 通过ObjectFactory来解析xml文件
        JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        File xmlFile = new File("/home/cienet/IdeaProjects/myTest/src/TestXjc/person.xml");
        JAXBElement<?> jaxbElement = (JAXBElement<?>) unmarshaller.unmarshal(xmlFile);
        PersonType personType = (PersonType) jaxbElement.getValue();
        //AddressType addressType = (AddressType) jaxbElement.getValue(); 会发生报错
        System.out.println(personType.age);
        
        // 将java对象转换为xml文件
        // 需要手动给PersonType.java中增加@XmlRootElement,才能将java对象解析成xml
        PersonType personType = new PersonType();
        personType.setAge(88);

        JAXBContext jaxbContext = JAXBContext.newInstance(PersonType.class);
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 格式化输出
        try (FileOutputStream fileStream = new FileOutputStream("C:\\Users\\mats\\IdeaProjects\\xmlParse\\src\\resource\\xml\\person_new.xml")) {
            marshaller.marshal(personType, fileStream);
        }
        

    }
}

XML与java对象之间的转换(示例二)

1. 编写 XML Schema 文件

使用任何文本编辑器编写 XML Schema 文件。下面是一个示例 XML Schema 文件:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="ServerConfig">
        <xs:complexType>
            <xs:all>
                <xs:element name="ServerInfo">
                    <xs:complexType>
                        <xs:attribute name="serverId" type="xs:string"/>
                        <xs:attribute name="protocol" type="xs:string"/>
                        <xs:attribute name="port" type="xs:int"/>
                    </xs:complexType>
                </xs:element>
                <xs:element name="BadiduInfo">
                    <xs:complexType>
                        <xs:attribute name="url" type="xs:string" />
                    </xs:complexType>
                </xs:element>
            </xs:all>
        </xs:complexType>
    </xs:element>
</xs:schema>

对应的server_config.xml文件是:

<?xml version="1.0" encoding="utf-8" ?>
<ServerConfig>
    <ServerInfo serverId="1" protocol="http" port="80" />
    <BadiduInfo url="https://www.baidu.com" />
</ServerConfig>
2. 运行 xjc 工具
# -d 参数指定生成的 Java 类的输出目录,-p 参数指定生成的 Java 类的包名
# 该命令会自动生成一个名为 PersonType.java 的 Java 类和名为addressType.java的Java类,以及一个名为 ObjectFactory.java 的工厂类,用于创建 JAXBContext 对象
# xjc schema.xsd -d src -p com.example.person
xjc resource/xsd/server_config.xsd -p test_serverConfig.gnsrc
3.生成java类

@XmlAccessorType 注解用于指定 JAXB 应该使用属性访问器而非字段访问器,

@XmlType 注解用于指定类的名称和属性顺序

@XmlRootElement 注解用于指定类在 XML 文档中的根元素名称

// ServerConfig.java
// 此文件是由 JavaTM Architecture for XML Binding (JAXB) 引用实现 v2.2.8-b130911.1802 生成的
// 请访问 <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// 在重新编译源模式时, 对此文件的所有修改都将丢失。
// 生成时间: 2023.03.29 时间 11:42:15 AM CST 
//

package test_serverConfig.gnsrc;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {

})
@XmlRootElement(name = "ServerConfig")
public class ServerConfig {

    @XmlElement(name = "ServerInfo", required = true)
    protected ServerConfig.ServerInfo serverInfo;
    @XmlElement(name = "BadiduInfo", required = true)
    protected ServerConfig.BadiduInfo badiduInfo;


	// 此处省略get和set方法

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "")
    public static class BadiduInfo {

        @XmlAttribute(name = "url")
        protected String url;

		// 此处省略get和set方法
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "")
    public static class ServerInfo {

        @XmlAttribute(name = "serverId")
        protected String serverId;
        @XmlAttribute(name = "protocol")
        protected String protocol;
        @XmlAttribute(name = "port")
        protected Integer port;

		// 此处省略get和set方法

    }

}
// ObjeceMapper.java  
// 此文件是由 JavaTM Architecture for XML Binding (JAXB) 引用实现 v2.2.8-b130911.1802 生成的
// 请访问 <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// 在重新编译源模式时, 对此文件的所有修改都将丢失。
// 生成时间: 2023.03.29 时间 11:42:15 AM CST 
//

package test_serverConfig.gensrc;

import javax.xml.bind.annotation.XmlRegistry;

@XmlRegistry
public class ObjectFactory {

    public ObjectFactory() {
    }

    public ServerConfig createServerConfig() {
        return new ServerConfig();
    }

    public ServerConfig.ServerInfo createServerConfigServerInfo() {
        return new ServerConfig.ServerInfo();
    }

    public ServerConfig.BadiduInfo createServerConfigBadiduInfo() {
        return new ServerConfig.BadiduInfo();
    }

}
4.XML与java对象之间的转换code
package test_serverConfig;

import test_serverConfig.gensrc.ServerConfig;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.io.File;

public class Test {
    public static void main(String[] args) throws Exception {
        // xml转换为java
        // 通过ServerConfig来解析xml文件
        JAXBContext jaxbContext = JAXBContext.newInstance(ServerConfig.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        File xmlFile = new File("C:\\Users\\mats\\IdeaProjects\\xmlParse\\src\\resource\\xml\\server_config.xml");
        ServerConfig serverConfig= (ServerConfig) unmarshaller.unmarshal(xmlFile);
        System.out.println(serverConfig.getServerInfo().getServerId());
        
        // java转换为xml
        ServerConfig.BadiduInfo badiduInfo=new ServerConfig.BadiduInfo();
        badiduInfo.setUrl("www.baidu.com");
        serverConfig.setBadiduInfo(badiduInfo);

        jaxbContext = JAXBContext.newInstance(ServerConfig.class);
        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // 格式化输出
        try (FileOutputStream fileStream = new FileOutputStream("C:\\Users\\mats\\IdeaProjects\\xmlParse\\src\\resource\\xml\\server_config_new.xml")) {
            marshaller.marshal(serverConfig, fileStream);
        }
    }
}