Jackson XML Parsing

Posted by ChenRiang on May 15, 2021

Recently, I have a task to parse XML document and found this awesome library called Jackson. Although it is famous in handling JSON parsing, their XML parsing implementation is pretty good and clean too.

Maven Dependency

1
2
3
4
5
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.12.3</version>
</dependency>

Refer here for latest version.

Jackson XML basic

To use Jackson XML library, we need to initialize a XmlMapper object.

1
XmlMapper xmlMapper = new XmlMapper();

Jackson will require us to write a POJO class map with the incoming XML document that we’re going to parse.

Reading XML

1
MyPOJO myPojo = xmlMapper.readValue(xmlString, MyPOJO.class);

Writing XML

1
2
3
ByteArrayOutputStream bs = new ByteArrayOutputStream();
xmlMapper.writeValue(bs, myPojo);
String xmlString = bs.toString();

Use writerWithDefaultPrettyPrinter() method to enable pretty print for XML mapper.

1
xmlMapper.writerWithDefaultPrettyPrinter().writeValue(bs, myPojo);

Mapping root element

To map a root element (e.g. student) we can use the annotation @JacksonXmlRootElement on the root level object that use in serialization.

1
2
3
<student>
    <name>Adam</name>
</student>
1
2
3
4
5
@Data  //lombok
@JacksonXmlRootElement(localName = "student")
public class Student {
    private String name;
}

Mapping XML property

1
2
3
4
<student id="id001" _isClassRep="true" _isActive="true" >
    <name>Adam</name>
    <phone>012540701</phone>
</student>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data  //lombok
@JacksonXmlRootElement(localName = "student")
@JsonPropertyOrder({"id", "_isClassRep", "_isActive", "name", "phone"})
class Student {
    @JacksonXmlProperty(isAttribute = true, localName = "map")
    private String id;
    @JacksonXmlProperty(isAttribute = true, localName = "_isActive")
    private boolean isActive;
    @JacksonXmlProperty(isAttribute = true, localName = "_isClassRep")
    private boolean isClassRep;
    private String phone;
    private String name;

}
  • Use @JsonPropertyOrder to specify the ordering when deserialize to XML string, else jackson will follow the variable ordering in POJO class.
  • Specify isAttribute(default=false) in @JacksonXmlProperty to control if the target property is XML attribute / element.
  • Specify localName in @JacksonXmlProperty to have custom the element/attribute name that different with variable in POJO class.

Mapping XML collection

When dealing with array value jackson will add an extra element which contain all the value.

POJO:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Data  //lombok
@JacksonXmlRootElement(localName = "student")
@JsonPropertyOrder({"id", "_isClassRep", "_isActive", "name", "phone"})
class Student {
    @JacksonXmlProperty(isAttribute = true, localName = "map")
    private String id;
    @JacksonXmlProperty(isAttribute = true, localName = "_isActive")
    private boolean isActive;
    @JacksonXmlProperty(isAttribute = true, localName = "_isClassRep")
    private boolean isClassRep;
    private String phone;
    private String name;
    @JacksonXmlProperty(localName = "subject")
    private List<String> subjects;
}
1
2
3
4
5
6
7
8
9
<student map="id001" _isClassRep="false" _isActive="true">
  <name>Adam</name>
  <phone>015248</phone>
  <subject>
    <subject>english</subject>
    <subject>history</subject>
    <subject>mathematics</subject>
  </subject>
</student>

To rename the container element we can simply add @JacksonXmlElementWrapper(localName = "subjects"):

1
2
3
@JacksonXmlElementWrapper(localName = "subjects")
@JacksonXmlProperty(localName = "subject")
private List<String> subjects;

XML Output:

1
2
3
4
5
6
7
8
9
<student map="id001" _isClassRep="false" _isActive="true">
  <name>Adam</name>
  <phone>015248</phone>
  <subjects>
    <subject>english</subject>
    <subject>history</subject>
    <subject>mathematics</subject>
  </subjects>
</student>

To remove the container element we can simply add @JacksonXmlElementWrapper(useWrapping = false)

1
2
3
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "subject")
private List<String> subjects;

XML Output:

1
2
3
4
5
6
7
<student map="id001" _isClassRep="false" _isActive="true">
  <name>Adam</name>
  <phone>015248</phone>
  <subject>english</subject>
  <subject>history</subject>
  <subject>mathematics</subject>
</student>

Conclusion

Although XML is not really favor by modern development comparing to JSON. However, it’s readable pleasant structure is definitely a plus point when you have a complex nested data structure. With the help of the library (like Jackson) that made parsing XML relatively simple, I believe XML will no obsolete in the future.