NimChimpsky
NimChimpsky

Reputation: 47280

Marshalling XML file to Java pojo/domain object

I have an old Access database that is basically one flat file. I want to migrate the data to my new whizzy, object oriented, hibernate based wonder-app.

The data is available as an XML file, and I want to map to three separate java pojos. I planned on using JAXB to do this, specifically using @xmlelement annotation. However the structure of the XML file is not optimal, in my pojos I have split up the data into three different objects.

Will JAXB help with this ? Do I need to simply create java pojo based on existing schema/xml file (that is not oo) using jaxb. Then create apdater classes/layer to put the data into my three pojos ? Or can I map straight from the xml file to 3 pojos with correct config/annotation ?

Upvotes: 1

Views: 3205

Answers (3)

bdoughan
bdoughan

Reputation: 148977

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

Assuming your XML document looks something like the following:

<?xml version="1.0" encoding="UTF-8"?>
<rows>
    <row>
        <col1>a1</col1>
        <col2>b1</col2>
        <col3>c1</col3>
    </row>
    <row>
        <col1>a1</col1>
        <col2>b2</col2>
        <col3>c2</col3>
    </row>
</rows>

You could leverage MOXy's @XmlPath annotation and do something like. EclipseLink also includes a JPA implementation:

Rows

You will need to create a Root object to hold everything:

package forum8577359;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Rows {

    @XmlElement(name="row")
    private List<A> rows;

}

A

Since the contents for the A, B, and C objects are all at the same level you can use MOXy's @XmlPath annotation and specify the "." XPath. This tells MOXy that the object, and the object it is referencing occur at the same level:

package forum8577359;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
public class A {

    private String col1;

    @XmlPath(".")
    private B b;

}

B

Again we use @XmlPath(".") to map the relationship between B and C:

package forum8577359;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
public class B {

    private String col2;

    @XmlPath(".")
    private C c;

}

C

package forum8577359;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class C {

    private String col3;

}

Demo

The following demo code can be used to run this example:

package forum8577359;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Rows.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum8577359/input.xml");
        Rows rows = (Rows) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(rows, System.out);
    }

}

jaxb.properties

To specify MOXy as your JAXB provider you need to include a jaxb.properties file in the same package as your domain classes with the following entry:

javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory

For More Information

Upvotes: 4

AlexR
AlexR

Reputation: 115328

Typically JAXB helps. Even if you are writing classes and annotations manually I think it takes less time than parsing using DOM API.

Moreover you can generate value objects automatically using JAXB. I think this is the approach you should try. First you should generate XSD file from your XML (unless you already have one). Then you should generated value objects based on the XSD. Then just parse the file. 2 code lines and you are done.

Upvotes: 1

smp7d
smp7d

Reputation: 5032

Without knowing the specifics of your issues...it should be possible, but it sounds like this may be a case where you would want to write a schema, use xjc to generate binding objects, unmarshal to the generated binding objects, and then translate to your domain objects in java (or use the generated objects directly if applicable).

Upvotes: 1

Related Questions