Java StAX API provides two XML processing API – cursor based and iterator based. Earlier we saw examples of iterator based API to read XML file and write XML file. Here we will learn how to use cursor based API to read XML file.
When we use StAX XML Parser, we need to create XMLInputFactory
to read XML file. Then we can chose cursor based API by creating XMLStreamReader
object to read file. XMLStreamReader next() method is used to get the next parsing event and it returns the int value depending on the event type. Common event types are Start Document, Start Element, Characters, End Element and End Document. XMLStreamConstants
contains int constants that can be used to process events based on it’s type.
For this tutorial, we have below xml file that is list of Employee element.
<?xml version="1.0" encoding="UTF-8"?>
<Employees>
<Employee id="1">
<age>29</age>
<name>Pankaj</name>
<gender>Male</gender>
<role>Java Developer</role>
</Employee>
<Employee id="2">
<age>35</age>
<name>Lisa</name>
<gender>Female</gender>
<role>CEO</role>
</Employee>
<Employee id="3">
<age>40</age>
<name>Tom</name>
<gender>Male</gender>
<role>Manager</role>
</Employee>
<Employee id="4">
<age>25</age>
<name>Meghna</name>
<gender>Female</gender>
<role>Manager</role>
</Employee>
</Employees>
We have Employee class to represent the Employee element.
package com.journaldev.xml;
public class Employee {
private int id;
private String name;
private String gender;
private int age;
private String role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public String toString() {
return "Employee:: ID="+this.id+" Name=" + this.name + " Age=" + this.age + " Gender=" + this.gender +
" Role=" + this.role;
}
}
Here is the class where we are using StAX XMLStreamReader
to read the xml file to list of Employee object.
package com.journaldev.xml.stax;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import com.journaldev.xml.Employee;
public class StaxXMLStreamReader {
private static boolean bName;
private static boolean bAge;
private static boolean bGender;
private static boolean bRole;
public static void main(String[] args) {
String fileName = "/Users/pankaj/employees.xml";
List<Employee> empList = parseXML(fileName);
for(Employee emp : empList){
System.out.println(emp.toString());
}
}
private static List<Employee> parseXML(String fileName) {
List<Employee> empList = new ArrayList<>();
Employee emp = null;
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new FileInputStream(fileName));
int event = xmlStreamReader.getEventType();
while(true){
switch(event) {
case XMLStreamConstants.START_ELEMENT:
if(xmlStreamReader.getLocalName().equals("Employee")){
emp = new Employee();
emp.setId(Integer.parseInt(xmlStreamReader.getAttributeValue(0)));
}else if(xmlStreamReader.getLocalName().equals("name")){
bName=true;
}else if(xmlStreamReader.getLocalName().equals("age")){
bAge=true;
}else if(xmlStreamReader.getLocalName().equals("role")){
bRole=true;
}else if(xmlStreamReader.getLocalName().equals("gender")){
bGender=true;
}
break;
case XMLStreamConstants.CHARACTERS:
if(bName){
emp.setName(xmlStreamReader.getText());
bName=false;
}else if(bAge){
emp.setAge(Integer.parseInt(xmlStreamReader.getText()));
bAge=false;
}else if(bGender){
emp.setGender(xmlStreamReader.getText());
bGender=false;
}else if(bRole){
emp.setRole(xmlStreamReader.getText());
bRole=false;
}
break;
case XMLStreamConstants.END_ELEMENT:
if(xmlStreamReader.getLocalName().equals("Employee")){
empList.add(emp);
}
break;
}
if (!xmlStreamReader.hasNext())
break;
event = xmlStreamReader.next();
}
} catch (FileNotFoundException | XMLStreamException e) {
e.printStackTrace();
}
return empList;
}
}
When we execute above program, we get following output in console.
Employee:: ID=1 Name=Pankaj Age=29 Gender=Male Role=Java Developer
Employee:: ID=2 Name=Lisa Age=35 Gender=Female Role=CEO
Employee:: ID=3 Name=Tom Age=40 Gender=Male Role=Manager
Employee:: ID=4 Name=Meghna Age=25 Gender=Female Role=Manager
Is there a more efficient way other than if else if to implement the logic inside your parseXML()
Simple and superb, thanks Pankaj for the nice example.
This was excellent. I was struggling for days but this is a very elegant way to handle reading xml into an object. Good work.
Thanks for the post,it is very helpful.
I want to retrieve complete xml file text as csv file which contains documents,sub documents,etc..
I tried your code for my xml it is retrieving only the last stream text.
Can you please help me on this.
Thanks,
Aijas
It? actually a nice and useful piece of information. I? glad that you shared this useful information with us. Please keep us informed like this. Thanks for sharing.