Unmarshalling nested list of xml elements using JAXB
I have an xml construct like this which I need to convert to java objects using JAXB:
<elements>
<elemet>
<type></type>
<property1></property1>
<property2></property2>
<items>
<item>
<id></id>
<name></name>
</item>
...
<item>
<id></id>
<name></name>
</item>
</items>
</element>
</elements>
I have to convert this construct not to an element with a nested list of elements, but to several elements, one for each element. Here's an example of an Element class:
class Element {
Integer type;
String property1;
String property2;
Integer itemId;
String itemName;
}
I want to get a list of them after unmarshalling. The values โโof type, property1 and property2 must be the same for all elements of the list. Is there a way to solve this with JAXB?
source to share
You will need to define a custom XmlAdapter . The tricky part of your case is that you want to map one XML element
to multiple Java objects element
. This means that in Java. Yours XmlAdapter
must be configured to collect objects element
. Assuming your example XML snippet is part of a document:
<document>
<elements>
<element>
....
</element>
<elements>
</document>
Then you will need to configure XmlAdapter
for the field List<Element>
in the Java class Document
:
class Document {
@XmlJavaTypeAdapter(CustomAdapter.class)
List<Element> elements;
}
Then your class CustomAdapter
can get a list of Element objects (corresponding to the actual XML structure with nested elements) and create a list of elements with the structure you want.
Check out JAXB XmlAdapter as an example - set up marshaling and cancel printing
source to share
Main.java
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Main {
public static void main(String[] args) {
List<Element> elementList = new ArrayList<Element>();
List<Item> itemList = new ArrayList<Item>();
Element element1 = new Element();
Element element2 = new Element();
Item item1 = new Item();
Item item2 = new Item();
Elements elements = new Elements();
item1.setId(1);
item1.setName("Test1");
item2.setId(2);
item2.setName("Test2");
itemList.add(item1);
itemList.add(item2);
element1.setProperty1("prop1");
element1.setProperty2("prop2");
element1.setType(2);
element1.setItems(itemList);
element2.setProperty1("prop11");
element2.setProperty2("prop22");
element2.setType(22);
element2.setItems(itemList);
elementList.add(element1);
elementList.add(element2);
elements.setElements(elementList);
try {
System.out.println("------- Object to XML -----------\n");
JAXBContext jaxbContext = JAXBContext.newInstance(Elements.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(elements, System.out);
System.out.println("\n------- XML to Object -----------\n");
String xml = "<elements><element><items><item><id>1</id><name>Test1</name></item><item><id>2</id><name>Test2</name></item></items><property1>prop1</property1><property2>prop2</property2><type>2</type></element><element><items><item><id>1</id><name>Test1</name></item><item><id>2</id><name>Test2</name></item></items><property1>prop11</property1><property2>prop22</property2><type>22</type></element></elements>";
StringReader reader = new StringReader(xml);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Elements elementsOut = (Elements) jaxbUnmarshaller.unmarshal(reader);
System.out.println(elementsOut);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Elements.java
import java.lang.reflect.Field;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="elements")
public class Elements {
List<Element> elements;
@XmlElement(name="element")
public List<Element> getElements() {
return elements;
}
public void setElements(List<Element> elements) {
this.elements = elements;
}
@Override
public String toString() {
Field[] fields = this.getClass().getDeclaredFields();
String res = "";
try {
for (Field field : fields) {
res += field.getName() + " :\n" + field.get(this);
}
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
}
Element.java
import java.lang.reflect.Field;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
public class Element {
Integer type;
String property1;
String property2;
List<Item> items;
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public String getProperty1() {
return property1;
}
public void setProperty1(String property1) {
this.property1 = property1;
}
public String getProperty2() {
return property2;
}
public void setProperty2(String property2) {
this.property2 = property2;
}
@XmlElementWrapper(name="items")
@XmlElement(name = "item")
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
@Override
public String toString() {
Field[] fields = this.getClass().getDeclaredFields();
String res = "\n";
try {
for (Field field : fields) {
res += field.getName() + " : " + field.get(this) + "\n";
}
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
}
Item.java
import java.lang.reflect.Field;
public class Item {
Integer id;
String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
Field[] fields = this.getClass().getDeclaredFields();
String res = "{";
try {
for (Field field : fields) {
res += field.getName() + " : " + field.get(this);
}
res += "}";
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
}
Since the tag elements
is the root element, you cannot use @XmlElementWrapper
, but is items
not root, so you can use it there, so you don't need to implement the class items
. Ignore the implementation toString
to just light objects.
Object for XML output
------- Object to XML -----------
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<elements>
<element>
<items>
<item>
<id>1</id>
<name>Test1</name>
</item>
<item>
<id>2</id>
<name>Test2</name>
</item>
</items>
<property1>prop1</property1>
<property2>prop2</property2>
<type>2</type>
</element>
<element>
<items>
<item>
<id>1</id>
<name>Test1</name>
</item>
<item>
<id>2</id>
<name>Test2</name>
</item>
</items>
<property1>prop11</property1>
<property2>prop22</property2>
<type>22</type>
</element>
</elements>
XML for object output
------- XML to Object -----------
elements :
[
type : 2
property1 : prop1
property2 : prop2
items : [{id : 1name : Test1}, {id : 2name : Test2}]
,
type : 22
property1 : prop11
property2 : prop22
items : [{id : 1name : Test1}, {id : 2name : Test2}]
]
source to share