Define XML Structure with Xstream - java

I need to convert one POJO into the following XML:
<Root>
<Version>2.0</Version>
<Name>John</Name>
<Age>18</Age>
<UserId>22491</UserId>
<Country>USA</Country>
<AnotherData>
<Records>
<AnotherRecord>
<Field1>XXX</Field1>
<Field2>XX</Field2>
<Field3>CCCCCCCC</Field3>
<Field4>XXX9000</Field4>
<Field5>XXX00345</Field5>
</AnotherRecord>
</Records>
</AnotherData>
</Root>
I know how to convert the fields below the root tag, it's not a problem. But from the AnotherData my problem's starting.
To represent the xml above I need some class like this:
puclic class Root{
public String Version;
public String Name;
public String Age;
public String UserID;
public String Country;
public AnotherData AnotherData;
}
public class AnotherData{
public Records Records;
}
public class Records{
List<AnotherRecord> list;
}
public class AnotherRecord{
public String Field1;
public String Field2;
public String Field3;
public String Field4;
public String Field5;
}
But I don't need of this structure of class, I like implement my classes in a more simple mode, and "force" the tag structure in xml.
My class would be like below, but keeping the structure xml like above.
puclic class Root{
public String Version;
public String Name;
public String Age;
public String UserID;
public String Country;
public AnotherData AnotherData;
List<AnotherRecord> list;
}
public class AnotherRecord{
public String Field1;
public String Field2;
public String Field3;
public String Field4;
public String Field5;
}

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
I do not believe this use case can be handled by XStream. If you are open to using other technologies, below is an example of how it could be done with MOXy. Using the #XmlPath extension.
#XmlPath("AnotherData/Records/AnotherRecord")
List<AnotherRecord> list;
Root
Below is what the fully mapped Root class would look like. JAXB does not require any annotations (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html), but since the XML elements in your document do not match the default naming rules some annotations are required.
package forum11970410;
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="Root")
public class Root{
#XmlElement(name="Version")
public String Version;
#XmlElement(name="Name")
public String Name;
#XmlElement(name="Age")
public String Age;
#XmlElement(name="UserId")
public String UserID;
#XmlElement(name="Country")
public String Country;
#XmlPath("AnotherData/Records/AnotherRecord")
List<AnotherRecord> list;
}
AnotherRecord
package forum11970410;
import javax.xml.bind.annotation.XmlElement;
public class AnotherRecord{
#XmlElement(name="Field1")
public String Field1;
#XmlElement(name="Field2")
public String Field2;
#XmlElement(name="Field3")
public String Field3;
#XmlElement(name="Field4")
public String Field4;
#XmlElement(name="Field5")
public String Field5;
}
jaxb.properties
To specify MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain classes with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
You can use the following demo code to prove that everything works:
package forum11970410;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum11970410/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Version>2.0</Version>
<Name>John</Name>
<Age>18</Age>
<UserId>22491</UserId>
<Country>USA</Country>
<AnotherData>
<Records>
<AnotherRecord>
<Field1>XXX</Field1>
<Field2>XX</Field2>
<Field3>CCCCCCCC</Field3>
<Field4>XXX9000</Field4>
<Field5>XXX00345</Field5>
</AnotherRecord>
</Records>
</AnotherData>
</Root>
For More Information
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2010/10/how-does-jaxb-compare-to-xstream.html

Related

JAXB unmarshal mystery XML

I am using JAXB to unmarshal an XML file.
All I know about the XML file is that it is valid XML.
How then am I supposed to specify a class and/or package to newInstance?
JAXBContext jaxbContext = JAXBContext.newInstance(??????);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object o = (Object) unmarshaller.unmarshal(myFile);
I did not see anything in the docs that address this issue.
You need to tell JaxB what class to unmarshall to so that it can use the annotations in the class to resolve the hierarchy of the xml. You will need to have a class that is also annotated with something like #XmlRootElement. If you want to parse arbitrary xml you will probably need to do something with a DocumentBuilder or xpath.
See this artical for more info.
http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html
I have used something like this to convert arbitrary xml to a class. The any field will actually be a list of org.w3c.dom.Element in which you can get information from.
http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/Element.html
#XmlRootElement
class Wrapper {
/**
* Everything else
*/
#Transient
#XmlAnyElement(lax = true)
private List<Element> any;
public List<Element> getAny() {
return any;
}
}
In newInstance you must add the class root element that map your xml... below an example
Here an example ..
public static void main(String[] args) throws JAXBException {
final JAXBContext context = JAXBContext.newInstance(Vehicals.class);
final Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
final Vehicals vehicals = new Vehicals();
List<Car> cars = new ArrayList<Car>();
Car c = new Car();
c.setName("Mercedes");
cars.add(c);
c = new Car();
c.setName("BMW");
cars.add(c);
vehicals.setCar(cars);
m.marshal(vehicals, System.out);
}
Vehicals.java
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Vehicals {
private List<Car> Car;
public List<Car> getCar() {
return Car;
}
public void setCar(List<Car> cars) {
this.Car = cars;
}
}
Car.java
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
#XmlRootElement
public class Car {
#XmlTransient
private Long id;
private String name;
#XmlTransient
private String code;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
output.xml
<Vehicle>
<Car>
<name>Mercedes</name>
</Car>
<Car>
<name>BMW</name>
</Car>
</Vehicle>
For the Unmarshal is the same thing. In my case i added Vehicals as parameter in newInstance method.

using JaxB to unmarshall object which contains List<String> field

I have a Java class which contains a List field.
public class Machine{
public int ID;
public String Name;
public String Status;
public String Environment;
public String Cluster;
public List<String> SupportedLocales;
}
Below is an instance of the class in XML that I am trying to unmarshall.
<?xml version="1.0" encoding="utf-8"?>
<Machine xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ID>27</ID>
<Name>QA14ADMINOPM201</Name>
<Status>Decom</Status>
<Environment>QA14</Environment>
<Cluster>ADMINOPM</Cluster>
<SupportedLocales>
<SupportedLocale>NA</SupportedLocale>
<SupportedLocale>Global</SupportedLocale>
</SupportedLocales>
</Machine>
When I unmarshall the Xml though, the resulting object has an empty SupportedLocales list, with no elements. Any reason why this might be happening or suggested fixes? All other fields are being unmarshalled correctly.
Annotate your field with an XmlElementWrapper annotation:
#XmlElementWrapper(name = "SupportedLocales")
#XmlElement(name = "SupportedLocale")
public List<String> SupportedLocales;
Also try to follow the convention of using variables that start with a lowercase (supportedLocales instead of SupportedLocales). This would need to map the XML element name for each field as follows:
#XmlElement(name="ID")
public int id;
#XmlElement(name="Name")
public String name;
#XmlElement(name="Status")
public String status;
#XmlElement(name="Environment")
public String environment;
#XmlElement(name="Cluster")
public String cluster;
#XmlElementWrapper(name = "SupportedLocales")
#XmlElement(name = "SupportedLocale")
public List<String> supportedLocales;

How to create model class for XML parsing which has iteration of element

I'm beginner JAVA programming. I'm making model class through XML parsing. I know there are some example such as : JAXB, xmapper etc..
I have some xml file which element has iteration. How to create model class for this xml ? Any help..
Let’s map some xml:
<root a="2.2">
<main>
<node1>123</node1>
<node2>123</node2>
</main>
<client value="1" use="true">
<C_node1>aaa</C_node1>
<C_node2>bbb</C_node2>
</client>
<client value="2" use="true">
<C_node1>aaa</C_node1>
<C_node2>bbb</C_node2>
</client>
<client value="3" use="true">
<C_node1>aaa</C_node1>
<C_node2>bbb</C_node2>
</client>
// ...
<client value="100" use="true">
<C_node1>aaa</C_node1>
<C_node2>bbb</C_node2>
</client>
<System>
<DebugFrame>0</DebugFrame>
</System>
</root>
I found http://docs.oracle.com/cd/E12840_01/wls/docs103/webserv/data_types.html. Is that what I want ?
Edited
Here is real code. I have some compile error. Java version is
java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b17)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
Here is error message ;
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Class has two properties of the same name "mode"
this problem is related to the following location:
at public java.lang.String xmlParserTest.RootTest.getMode()
at xmlParserTest.RootTest
this problem is related to the following location:
at private java.lang.String xmlParserTest.RootTest.mode
at xmlParserTest.RootTest
Class has two properties of the same name "inputFile"
this problem is related to the following location:
at public java.lang.String xmlParserTest.MainEntity.getInputFile()
at xmlParserTest.MainEntity
at private xmlParserTest.MainEntity xmlParserTest.RootTest.main
at xmlParserTest.RootTest
this problem is related to the following location:
at private java.lang.String xmlParserTest.MainEntity.inputFile
at xmlParserTest.MainEntity
at private xmlParserTest.MainEntity xmlParserTest.RootTest.main
at xmlParserTest.RootTest
: console.java
package xmlParserTest;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class console {
public static void main(String[] args) {
try
{
JAXBContext jc = JAXBContext.newInstance(RootTest.class);
Unmarshaller u = jc.createUnmarshaller();
File f = new File("Testing.xml");
RootTest product = (RootTest) u.unmarshal(f);
System.out.println(product.getMode());
System.out.println(product.getMainEntity().getInputFile());
System.out.println(product.getMainEntity().getOutputFolder());
}catch (JAXBException e) {
e.printStackTrace();
}
}
}
: RootTest.java
package xmlParserTest;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Function")
public class RootTest {
private MainEntity main;
private String mode;
#XmlElement(name="Main")
public MainEntity getMainEntity() {
return main;
}
public void setMainEntity(MainEntity _main) {
this.main = _main;
}
#XmlAttribute(name="mode")
public String getMode() {
return mode;
}
public void setMode(String _mode) {
this.mode = _mode;
}
public RootTest()
{
}
}
: MainEntity.java
package xmlParserTest;
import javax.xml.bind.annotation.XmlElement;
public class MainEntity {
private String inputFile;
private String inputType;
private String outputFolder;
private String outputType;
#XmlElement(name="InputFile")
public String getInputFile() {
return inputFile;
}
public void setInputFile(String _inputFile) {
this.inputFile = _inputFile;
}
public String getInputType() {
return inputType;
}
public void setInputType(String _type) {
this.inputType = _type;
}
#XmlElement(name="OutputFolder")
public String getOutputFolder() {
return outputFolder;
}
public void setOutputFolder(String _outputFolder) {
this.outputFolder = _outputFolder;
}
public String getOutputType() {
return outputType;
}
public void setOutputType(String _type) {
this.outputType = _type;
}
public MainEntity()
{
}
}
: Testing.xml
<?xml version="1.0" encoding="UTF-8"?>
<Function mode="Execute">
<Main>
<InputFile type="string">C:\DATA\test.txt</InputFile>
<OutputFolder type="string">C:\Test</OutputFolder>
</Main>
</Function>
If You wnat to use JAXB, first of all, You need to create main model, that looks like this:
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
private MainEntity main;
#XmlElement(name = "client")
private List<ClientEntity> clients;
#XmlAttribute
private String a;
#XmlElement(name = "System")
private SystemEntity system;
//getters and setters for all fields
}
Then, specify entities:
public class MainEntity {
private String node1;
private String node2;
//getters and setters for all fields
}
#XmlAccessorType(XmlAccessType.FIELD)
public class ClientEntity {
#XmlElement(name = "C_node1")
private String C_node1;
#XmlElement(name = "C_node2")
private String C_node2;
#XmlAttribute
private Long value;
#XmlAttribute
private boolean use;
//getters and setters for all fields
}
#XmlAccessorType(XmlAccessType.FIELD)
public class SystemEntity {
#XmlElement(name = "DebugFrame")
private Long debugFrame;
//getters and setters for all fields
}
As You see, we use #XmlElement(name = "System") to set alias for field and #XmlAttribute to read field from attribute.
To unmarshall XML with JAXB, create context for your class model:
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(file);
Don't forget: when You create model, You need to specify getters and setters for fields that You want to marshall/unmarshall and also specify non-argument constructor for class.
More about annotations You can find here:
http://www.techferry.com/articles/jaxb-annotations.html
Have fun!:)
With JAXB, you can create the required Java classes as below:
#XmlRootElement(name = "main")
public class Main {
String node1;
String node1;
//getters and setters for fields
}
#XmlRootElement(name = "client")
public class Client {
String node1;
String node1;
#XmlAttribute
private boolean use;
#XmlAttribute
private int value;
//getters and setters for fields
}
And then create a Root class to represent your XML file:
#XmlRootElement(name = "root")
public class Root {
//add a list of client instances
#XmlElement(name = "client")
private List<Client> clientList;
//add an instance of main
#XmlElement(name = "main")
private Main main;
// setters to set the values for main and clients
}
Now, with these lines of code you can create the XML representation for the Root class:
Root root = new Root();
root.setMain(CREATE_AND_SET_AN_INSTANCE_OF_MAIN);
root.setClientList(CREATE_AND_SET_A_LIST_OF_CLIENTS);
String filePath = "PATH_TO_SAVE_YOUR_FILE";
File file = new File(filePath);
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(alpha, file);
And you can use these lines of code to read the XML back to Java object:
String filePath = "XML_FILE_PATH";
File file = new File(filePath);
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Root root = (Root) jaxbUnmarshaller.unmarshal(file);
Ref: Java Architecture for XML Binding (JAXB)

JAXB - Unexpected elements in XML output

I have a class called Building.
It has a list of BuildingBenchAssociation records (List<BuildingBenchAssociation> benches)
BuildingBenchAssociation has a composite id made up of buildingId and benchId
The ID is represented by separate class called BuildingBenchAssociationPKwhich has only two properties - buildingId and benchId
This is the output I get when I marshal a Building instance
<building buildingId="9">
<benches>
DOMRecord(<?xml version="1.0" encoding="UTF-8"?><buildingBenchAssociation><benchId>245865</benchId><buildingId>9</buildingId></buildingBenchAssociation>)
</benches>
<benches>
DOMRecord(<?xml version="1.0" encoding="UTF-8"?><buildingBenchAssociation><benchId>245866</benchId><buildingId>9</buildingId></buildingBenchAssociation>)
</benches>
<benches>
But I don't want DOMRecord(<?xml version="1.0" encoding="UTF-8"?> to appear in the output. Required output is something like this:
<building buildingId="9">
<benches>
<buildingBenchAssociation><benchId>245865</benchId><buildingId>9</buildingId></buildingBenchAssociation>
</benches>
<benches>
<buildingBenchAssociation><benchId>245866</benchId><buildingId>9</buildingId></buildingBenchAssociation>
</benches>
<benches>
What's wrong and how do I correct it? I am using the Eclipselink MOXy library.
Classes for reference:
Class 1
#Entity
#Table(name="building")
#XmlRootElement
public class Building implements Serializable {
....
private List<BuildingBenchAssociation> benchs = new ArrayList<BuildingBenchAssociation>();
#XmlIDREF
#OneToMany(mappedBy="building")
public List<BuildingBenchAssociation> getBenchs() {
return benchs;
}
public void setBenchs(List<BuildingBenchAssociation> benchs) {
this.benchs = benchs;
}
}
Class 2
#Entity
#Table(name="building_bench_rel")
#XmlRootElement
public class BuildingBenchAssociation implements Serializable {
private static final long serialVersionUID = 1L;
private BuildingBenchAssociationPK idx;
private Bench bench;
private Building building;
private byte alertFlags;
private byte status;
public BuildingBenchAssociation() {
idx=new BuildingBenchAssociationPK();
}
#XmlID
#XmlPath(".")
#Id
public BuildingBenchAssociationPK getIdx() {
return this.idx;
}
public void setIdx(BuildingBenchAssociationPK id) {
this.idx = id;
}
#Column(name="ALERT_FLAGS")
public byte getAlertFlags() {
return this.alertFlags;
}
public void setAlertFlags(byte alertFlags) {
this.alertFlags = alertFlags;
}
#Column(name="STATUS", insertable=false, updatable=false)
public byte getStatus() {
return this.status;
}
public void setStatus(byte status) {
this.status = status;
}
#XmlIDREF
#ManyToOne
#JoinColumn(name="BENCH_ID",insertable=false,updatable=false)
public Bench getBench() {
return bench;
}
public void setBench(Bench bench) {
this.bench = bench;
this.idx.setBenchId(bench==null?null:bench.getBenchId());
}
#XmlIDREF
#ManyToOne
#JoinColumn(name="BUILDING_ID",insertable=false,updatable=false)
public Building getBuilding() {
return building;
}
public void setBuilding(Building building) {
this.building = building;
this.idx.setBuildingId(building==null?null:building.getBuildingId());
}
}
Class 3
#Embeddable
#XmlRootElement
public class BuildingBenchAssociationPK implements Serializable {
...
private Integer buildingId;
private Integer benchId;
public BuildingBenchAssociationPK() {
}
#XmlKey
#Column(name="BUILDING_ID")
public Integer getBuildingId() {
return this.buildingId;
}
public void setBuildingId(Integer buildingId) {
this.buildingId = buildingId;
}
#XmlKey
#Column(name="BENCH_ID")
public Integer getBenchId() {
return this.benchId;
}
public void setBenchId(Integer benchId) {
this.benchId = benchId;
}
}
Below is how you can currently map this use case using MOXy. I have opened the following enhancement request to make this use case easier to map:
http://bugs.eclipse.org/407460
REFERENCED OBJECT
Embedded ID (EmployeeId)
Below is an example of an embedded ID class:
import java.math.BigDecimal;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
#Embeddable
#XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeId {
#Column(name="E_ID")
BigDecimal eId;
String country;
}
Class with Embedded ID (Employee)
We want to use the embedded ID class for as the key in an XML relationship. Currently MOXy does not allow this to be done via annotations, so we will leverage the #XmlCustomizer annotation to programmatically modify the metadata.
import java.util.List;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
#IdClass(EmployeeId.class)
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlCustomizer(EmployeeCustomizer.class)
public class Employee {
#EmbeddedId
#XmlPath(".")
EmployeeId id;
#OneToMany(mappedBy="contact")
List<PhoneNumber> contactNumber;
}
Customize Mapping Metadata for Employee (EmployeeCustomizer)
In the customizer class we will specify the XPaths for the mappings that compose the key on the embedded class.
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
public class EmployeeCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
descriptor.addPrimaryKeyFieldName("eId/text()");
descriptor.addPrimaryKeyFieldName("country/text()");
}
}
REFERRING OBJECT
PhoneNumber
We are also going to need to programatically add the mapping based on the composite key, so once again we will use the #XmlCustomizer annotation.
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
#XmlAccessorType(XmlAccessType.FIELD)
#XmlCustomizer(PhoneNumberCustomizer.class)
public class PhoneNumber {
#ManyToOne
#JoinColumns({
#JoinColumn(name="E_ID", referencedColumnName = "E_ID"),
#JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
})
Employee contact;
}
Customize Mapping Metadata for PhoneNumber (PhoneNumberCustomizer)
In this customizer we will remove the default mapping, and programatically create the new one based on the composite keys.
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping;
public class PhoneNumberCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
descriptor.removeMappingForAttributeName("contact");
XMLObjectReferenceMapping contactMapping = new XMLObjectReferenceMapping();
contactMapping.setAttributeName("contact");
contactMapping.setReferenceClass(Employee.class);
contactMapping.addSourceToTargetKeyFieldAssociation("contact/#eID", "eId/text()");
contactMapping.addSourceToTargetKeyFieldAssociation("contact/#country", "country/text()");
descriptor.addMapping(contactMapping);
}
}
DEMO CODE
The following demo code can be used to demonstrate that everything works:
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Employee.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("input.xml");
Employee employee = (Employee) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(employee, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<eId>10</eId>
<country>Canada</country>
<contactNumber>
<contact eID="10" country="Canada"/>
</contactNumber>
<contactNumber>
<contact eID="10" country="Canada"/>
</contactNumber>
</employee>
FOR MORE INFORMATION
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/JPA/EmbeddedIdClass

Getting MOXy #XmlPath to Work with Namespace

I'm writing a script to parse a KML file using JAXB and MOXy, but I'm having difficulty getting #XmlPath to work with a provided namespace.
If my KML looks like this:-
<kml>
<Document>
<name>Test</name>
</Document>
</kml>
... and my bean looks like this:-
#XmlRootElement(name = "kml")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
... then, kml.getName() returns Test, which works like it should.
However, if my KML contains a namespace like this:-
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Test</name>
</Document>
</kml>
... and my bean looks like this:-
#XmlRootElement(name = "kml", namespace = "http://www.opengis.net/kml/2.2")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
... then, kml.getName() returns null.
I do have jaxb.properties at the right package level and I'm using the following MOXy's dependency:-
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.3.2</version>
</dependency>
What exactly am I missing here? Thanks.
Below is an example demonstrating how to configure the namespace information.
package-info
You can use the #XmlSchema annotation to specify the namespace information and qualification. In the example below we will specify the namespace, and that by default all elements should be namespace qualified.
#XmlSchema(
namespace="http://www.opengis.net/kml/2.2",
elementFormDefault=XmlNsForm.QUALIFIED)
#XmlAccessorType(XmlAccessType.FIELD)
package forum9931520;
import javax.xml.bind.annotation.*;
Kml
We do not need to specify any namespace information in the Kml class. This information comes from the settings in package-info:
package forum9931520;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name = "kml")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Demo
package forum9931520;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Kml.class);
File xml = new File("src/forum9931520/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Kml kml = (Kml) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(kml, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Test</name>
</Document>
</kml>
For More Information
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

Categories

Resources