Question

I get a flat XML document from a call to a legacy system and I would like to be able to unmarshal it into multiple Java objects (ideally) using annotations.

There is no xsd with the XML and I want to maintain the current structure of my Java classes because they map to the structure of the JSON I am returning from my restful service.

I have seen examples of this problem in reverse using MOXy, but no examples of this problem exactly.

So given ...

    <xml>
        <body>
            <a>A</a>
            <b>B</b>
            <c>C</c>
            <d>D</d>
            <e>E</e>
        </body>
    </xml>

I would like to map these values to

    public class wrapper {

        private Object1 one;
        private Object2 two;
        private Object3 thr;
    }

    public class Object1 {

        private String a;
        private String b;

    }

    public class Object2 {

        private String c;
        private String d;
    }

    public class Object3 {

        private String e;
    }

The obvious, long hand way of doing this is to manually parse through the XML document retrieving text node values and setting them on my java objects, but I am trying to avoid this as the XML is fairly large and I will have to repeat the process for several services.

Any solutions that require a significant amount of manual processing will make it hard for me to justify a departure from the current long hand method.

Thanks in advance

Was it helpful?

Solution

Related MOXy Functionality

MOXy currently supports writing the mapped properties of a child object directly into the parent objects element using @XmlPath(".") (see: http://blog.bdoughan.com/2010/07/xpath-based-mapping.html).

What's Interesting About Your Use Case

What makes it tricky with your use case is that you have an added level of nesting in your example. We don't support this directly today, but I have added an enhancement request (see: http://bugs.eclipse.org/432029). When this is implemented you will be able to do something like:

@XmlRootElement(name="xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class wrapper {

    @XmlPath("body")
    private Object1 one;

    @XmlPath("body")
    private Object2 two;

    @XmlPath("body")
    private Object3 thr;

}

Work Around

With current functionality you could do the following:

Java Model

@XmlRootElement(name="body")
@XmlAccessorType(XmlAccessType.FIELD)
public class wrapper {

    @XmlPath(".")
    private Object1 one;

    @XmlPath(".")
    private Object2 two;

    @XmlPath(".")
    private Object3 thr;

}

Demo

import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        XMLInputFactory xif = XMLInputFactory.newFactory();
        StreamSource source = new StreamSource("input.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(source);
        while(!(xsr.isStartElement() && "body".equals(xsr.getLocalName()))) {
            xsr.next();
        }

        JAXBContext jc = JAXBContext.newInstance(wrapper.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        wrapper result = (wrapper) unmarshaller.unmarshal(xsr);
     }

}

For More Information

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top