XML parsing in Java (JAXB mode)

JAXB

Introduction to JAXB

? JAXB (Java Architecture for XML Binding) is part of the Java API, which provides a way to map Java classes to XML structures, and can also convert XML structures into instances of Java classes. It is a way to simplify the interaction between Java and XML, and Java classes can be mapped to XML elements through annotations or external XML mapping files.

? JAXB includes two main classes: Unmarshaller and Marshaller. Unmarshaller can convert XML documents to Java objects, and Marshaller can convert Java objects to XML documents. And XJC is an auxiliary tool of JAXB, which is used to generate Java classes according to XML Schema. It automatically parses elements and attributes defined in XML Schema and converts them to Java classes and fields. Using XJC can reduce the workload of manually writing Java classes, and at the same time ensure that the generated Java classes are consistent with the data model defined by XML Schema.

JAXB can be used with other XML processing technologies such as DOM, SAX and StAX. Using JAXB can easily realize the conversion between Java and XML, so that Java developers can focus more on the realization of business logic.

Introduction to xjc

xjc is a command-line tool in the JAXB toolset that automatically generates Java classes from XML Schema files. jdk 11 and below all come with xjc, location: %JAVA_HOME%\bin\xjc.exe;

Here are the steps to generate Java classes using the xjc tool:

The difference between example 1 and example 2

  1. The definition structure of xsd is different. Example 2 is written in a form similar to an anonymous class.

  2. If the generated ObjectFactory.java contains @XmlElementDecl, use ObjectFactory.java for parsing, as in example 1; if not, use the corresponding class for parsing, as in example 2

  3. Example 1: You need to manually add @XmlRootElement to PersonType.java to parse java objects into xml

Conversion between XML and java objects (Example 1)

1. Write XML Schema file

? Write the XML Schema file using any text editor. Here is a sample XML Schema file:

<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>

? The corresponding person.xml file is:

<?xml version="1.0" encoding="utf-8" ?>
<person>
    <name>zhangsan</name>
    <age>13</age>
    <address>
        <city>china</city>
        <country>beijing</country>
    </address>
</person>
2. Run the xjc tool
# The -d parameter specifies the output directory of the generated Java class, and the -p parameter specifies the package name of the generated Java class
# This command will automatically generate a Java class named PersonType.java, a Java class named addressType.java, and a factory class named ObjectFactory.java for creating JAXBContext objects
# xjc schema.xsd -d src -p com.example.person
xjc resource/xsd/person.xsd -p test_person.gensrc
3. Generate java classes

The @XmlAccessorType annotation is used to specify that JAXB should use property accessors instead of field accessors,

The @XmlType annotation is used to specify the name of the class and the order of attributes

The @XmlRootElement annotation is used to specify the root element name of the class in the XML document

// Persion.java
// This file was generated by the JavaTM Architecture for XML Binding (JAXB) reference implementation v2.2.8-b130911.1802
// Visit <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// All modifications to this file will be lost when recompiling the source schema.
// Generation time: 2023.03.29 time 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;

    // The get and set methods are omitted here
}


//AddressType.java
// This file was generated by the JavaTM Architecture for XML Binding (JAXB) reference implementation v2.2.8-b130911.1802
// Visit <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// All modifications to this file will be lost when recompiling the source schema.
// Generation time: 2023.03.29 time 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 and set methods omitted

}


// ObjectMapper.java -- used to create JAXBContext object
// This file was generated by the JavaTM Architecture for XML Binding (JAXB) reference implementation v2.2.8-b130911.1802
// Visit <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// All modifications to this file will be lost when recompiling the source schema.
// Generation time: 2023.03.29 time 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. Conversion code between XML and java objects
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 {<!-- -->
        // Parse the xml file through ObjectFactory
        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(); An error will occur
        System.out.println(personType.age);
        
        // convert java object to xml file
        // You need to manually add @XmlRootElement to PersonType.java to parse the java object into 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); // formatted output
        try (FileOutputStream fileStream = new FileOutputStream("C:\Users\mats\IdeaProjects\xmlParse\src\resource\xml\\ \person_new.xml")) {<!-- -->
            marshaller.marshal(personType, fileStream);
        }
        

    }
}

Conversion between XML and java objects (example 2)

1. Write XML Schema file

? Write the XML Schema file using any text editor. Here is a sample XML Schema file:

<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>

? The corresponding server_config.xml file is:

<?xml version="1.0" encoding="utf-8" ?>
<ServerConfig>
    <ServerInfo serverId="1" protocol="http" port="80" />
    <BadiduInfo url="https://www.baidu.com" />
</ServerConfig>

2. Run the xjc tool
# The -d parameter specifies the output directory of the generated Java class, and the -p parameter specifies the package name of the generated Java class
# This command will automatically generate a Java class named PersonType.java, a Java class named addressType.java, and a factory class named ObjectFactory.java for creating JAXBContext objects
# xjc schema.xsd -d src -p com.example.person
xjc resource/xsd/server_config.xsd -p test_serverConfig.gnsrc
3. Generate java classes

The @XmlAccessorType annotation is used to specify that JAXB should use property accessors instead of field accessors,

The @XmlType annotation is used to specify the name of the class and the order of attributes

The @XmlRootElement annotation is used to specify the root element name of the class in the XML document

// ServerConfig.java
// This file was generated by the JavaTM Architecture for XML Binding (JAXB) reference implementation v2.2.8-b130911.1802
// Visit <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// All modifications to this file will be lost when recompiling the source schema.
// Generation time: 2023.03.29 time 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;


// The get and set methods are omitted here

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

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

// The get and set methods are omitted here
    }

    @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;

// The get and set methods are omitted here

    }

}

// ObjectMapper.java
// This file was generated by the JavaTM Architecture for XML Binding (JAXB) reference implementation v2.2.8-b130911.1802
// Visit <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
// All modifications to this file will be lost when recompiling the source schema.
// Generation time: 2023.03.29 time 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. Conversion code between XML and java objects
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 {<!-- -->
        // convert xml to java
        // Parse the xml file through ServerConfig
        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());
        
        // convert java to 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); // formatted output
        try (FileOutputStream fileStream = new FileOutputStream("C:\Users\mats\IdeaProjects\xmlParse\src\resource\xml\\ \server_config_new.xml")) {<!-- -->
            marshaller.marshal(serverConfig, fileStream);
        }
    }
}

?
?