Unmarshalling nested list of xml items using JAXB

依然范特西╮ 提交于 2019-11-30 16:00:19

You will need to define a custom XmlAdapter. The complicated part in your case is that you want to map one XML element into multiple Java Element objects. This means that, in Java., your XmlAdapter needs to be configured for collection of Element objects. Assuming your example XML fragment is part of a document:

<document>
   <elements> 
      <element>
          ....
      </element>
   <elements>
</document>    

Then you will need to configure the XmlAdapter for the List<Element> field in the Java Document class:

class Document {
     @XmlJavaTypeAdapter(CustomAdapter.class)
     List<Element> elements;
}

Then you your CustomAdapter class can receive a list of Element objects (corresponding to the actual XML structure with the nested items) and produce a list of Element with the structure you want.

For an example, check JAXB XmlAdapter – Customized Marshaling and Unmarshaling

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

Because the elements tag is root element you can't use @XmlElementWrapper, but items is not root, so you can use that there, thus you don't have to implement the Items class. Ignore the toString implementation, it's just to print the objects in a meaningful way.

Object to 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 to 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}]
]
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!