While JSON has become a popular choice for asynchronous communication, XML is still used by large number of companies for data exchange in SOAP web services. As a Spring Boot developer, you might come across a requirement to parse the XML response of a web service in your career. It is not uncommon.

In this tutorial, we will learn how to parse an XML response of a web service using DOM XML parser in Spring Boot. DOM XML parser loads the entire data into memory and parses it into an XML document. The parsed XML document can be used to traverse different elements and nodes in any order.

DOM XML parser is relatively slow and is only good for parsing small XML document as it loads complete XML document into memory. This makes it a bad choice for parsing large XML documents. For large XML files, you should use SAX parser. I will explain how SAX parser works and how it is better than DOM parser in future.

Dependencies

DOM XML parser is a part of standard Java extensions (javax) and does not require any 3rd party dependency. We only need spring-boot-starter dependency for Spring Boot project. Here is how our build.gradle file looks like:

build.gradle

plugins {
	id 'org.springframework.boot' version '2.1.3.RELEASE'
	id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.attacomsian.xml'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
}

XML Response

For this tutorial, we will use a fake API that returns an XML response. Here is how our XML response looks like:

<?xml version="1.0" encoding="UTF-8" ?>
<course>
  <id>1</id>
  <title>Introduction to Spring Boot &amp; Thymeleaf</title>
  <price>49.99</price>
  <created>2019-03-15</created>
  <student>
    <id>1</id>
    <first_name>George</first_name>
    <last_name>Bluth</last_name>
    <avatar>https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg</avatar>
  </student>
  <student>
    <id>2</id>
    <first_name>Janet</first_name>
    <last_name>Weaver</last_name>
    <avatar>https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg</avatar>
  </student>
  <student>
    <id>3</id>
    <first_name>Emma</first_name>
    <last_name>Wong</last_name>
    <avatar>https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg</avatar>
  </student>
</course>

We will parse the above XML response to create a Course object that will also contains a list of Student.

Spring Classes

Following are the two model classes (Course & Student) we need for this example:

Student.java

package com.attacomsian.xml.models;

public class Student {

    private int id;
    private String firstName;
    private String lastName;
    private String avatar;

    public Student(int id, String firstName, String lastName, String avatar) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.avatar = avatar;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getAvatar() {
        return avatar;
    }

    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", avatar='" + avatar + '\'' +
                '}';
    }
}

Course.java

package com.attacomsian.xml.models;

import java.util.Date;
import java.util.List;

public class Course {

    private int id;
    private String title;
    private double price;
    private Date created;
    private List<Student> students;

    public Course(int id, String title, double price, Date created) {
        this.id = id;
        this.title = title;
        this.price = price;
        this.created = created;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public List<Student> getStudents() {
        return students;
    }

    public void setStudents(List<Student> students) {
        this.students = students;
    }

    @Override
    public String toString() {
        return "Course{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", price=" + price +
                ", created=" + created +
                ", students=" + students +
                '}';
    }
}

Notice that we have overridden toString() method in both classes to print the details.

DOM XML Parser

We will create a Spring service named XMLService for calling our fake API. This service uses Java DOM parser to read the XML from a remote URL and parse it into a Coures object.

XMLService.java

package com.attacomsian.xml.services;

import com.attacomsian.xml.models.Course;
import com.attacomsian.xml.models.Student;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

@Service
public class XMLService {

    private final Logger logger = LoggerFactory.getLogger(XMLService.class);


    public Course parseCourse() {

        Course course = null;

        try {
            // fake end point that returns XML response
            String URL = "http://www.mocky.io/v2/5c8bdd5c360000cd198f831e";

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(URL);

            // normalize XML response
            doc.getDocumentElement().normalize();

            //read course details first
            course = new Course(Integer.parseInt(doc.getElementsByTagName("id").item(0).getTextContent()),
                    doc.getElementsByTagName("title").item(0).getTextContent(),
                    Double.parseDouble(doc.getElementsByTagName("price").item(0).getTextContent()),
                    new SimpleDateFormat("yyyy-MM-dd").parse(doc.getElementsByTagName("created").item(0).getTextContent())
                    );

            //read students list
            NodeList nodeList = doc.getElementsByTagName("student");

            //create an empty list for students
            List<Student> students = new ArrayList<>();

            //loop all available student nodes
            for (int i = 0; i < nodeList.getLength(); i++) {

                Node node = nodeList.item(i);

                if(node.getNodeType() == Node.ELEMENT_NODE) {
                    Element elem = (Element) node;
                    Student student = new Student(
                            Integer.parseInt(elem.getElementsByTagName("id").item(0).getTextContent()),
                            elem.getElementsByTagName("first_name").item(0).getTextContent(),
                            elem.getElementsByTagName("last_name").item(0).getTextContent(),
                            elem.getElementsByTagName("avatar").item(0).getTextContent()
                    );
                    students.add(student);
                }
            }

            //set students in course
            course.setStudents(students);

        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }

        return course;
    }
}

In parseCourse() method above, we build an instance of DocumentBuilder by using DocumentBuilderFactory. This instance parse() method is then used to send an HTTP request to our fake API to get the XML and parse it into a Document object. After that, we traverse this document elements and nodes to create a Course object.

Executing Application

Now let's create the main application class that implements CommandLineRunner interface to run the Spring Boot project as a console application.

XmlParserApplication.java

package com.attacomsian.xml;

import com.attacomsian.xml.models.Course;
import com.attacomsian.xml.services.XMLService;
import org.springframework.boot.Banner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class XmlParserApplication implements CommandLineRunner {

	private XMLService xmlService;

	public XmlParserApplication(XMLService xmlService) {
		this.xmlService = xmlService;
	}

	public static void main(String[] args) {
		SpringApplication app = new SpringApplication(XmlParserApplication.class);
		// disable spring banner
		app.setBannerMode(Banner.Mode.OFF);
		app.run(args);

	}

	@Override
	public void run(String... args) throws Exception {

		// load course from XMLService
		Course course = xmlService.parseCourse();

		// print course details
		System.out.println(course);
	}
}

We you execute the Spring Boot application, you will see the following output printed on the terminal:

Course{id=1, title='Introduction to Spring Boot & Thymeleaf', price=49.99, created=Fri Mar 15 00:00:00 PKT 2019, students=[Student{id=1, firstName='George', lastName='Bluth', avatar='https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg'}, Student{id=2, firstName='Janet', lastName='Weaver', avatar='https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg'}, Student{id=3, firstName='Emma', lastName='Wong', avatar='https://s3.amazonaws.com/uifaces/faces/twitter/olegpogodaev/128.jpg'}]}

Source code: Download the complete source code from GitHub available under MIT license.

Conclusion

In this article, I explain how to use DOM XML parser to parse an XML response in Spring Boot. This XML response can be returned by a SOAP web service or a remote XML file.

If you have any question, please feel free to send me a tweet anytime. I would appreciate if you share this tutorial with your friends and followers. You may want to join my weekly newsletter below to receive a curated list of top Spring Boot tutorials and jobs from my blog and around the internet.

Happy Learning Spring Boot πŸ™Œ

πŸ™‹β€β™‚οΈ Like this article? Follow @attacomsian on Twitter. You can also follow me on LinkedIn and DEV.


Need help to start a new Spring Boot or MEAN stack project? I am available for contract work. Hire me to accomplish your business goals with engineering and design. Let’s talk about your project: hi@attacomsian.com.