Multiple XML tag by JAXB - java

I'm using JAXB for generating XML, like this:
<Country>
<City>..</City>
<Adr>...</Adr>
</Country>
I have special class, which generate this XML:
#XmlElement(name = "Country")
private String country;
#XmlElement(name = "City")
private String city;
#XmlElement(name = "Adr")
private String adr;
with setters and getters, of course. But, how need I change this code, if I want to see XML like this?
<Country>
<City>..</City>
<Adr>...</Adr>
<City>..</City>
<Adr>...</Adr>
</Country>

Related

JAXB: how to unmarshal a List of objects of different types inside a wrapper?

I'm stucked at parsing the following xml with JAXB:
<?xml version="1.0" encoding="utf-8"?>
<dashboardreport name="exampleDashboard" version="6.5.6.1013" reportdate="2016-12-16T11:05:19.329+01:00" description="">
<data>
<incidentchartdashlet name="Incident Chart" description="" />
<chartdashlet name="WebRequestTime" showabsolutevalues="false" />
<chartdashlet name="WebServiceTime" showabsolutevalues="false" />
</data>
</dashboardreport>
I used the following java classes to unmarshal the xml:
Dashboardreport.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "dashboardreport")
public class Dashboardreport {
#XmlElementWrapper(name = "data")
#XmlElement(name = "chartdashlet")
protected List<Chartdashlet> chartdashlets;
#XmlElementWrapper(name = "data")
#XmlElement(name = "incidentchartdashlet")
protected List<Incidentchartdashlet> incidentchartdashlets;
#XmlAttribute(name = "name")
protected String name;
}
I just want to unmarshal the xml without using a wrapper class around incidentchartdashlets and chartdashlet, cause both types differ a lot.
I only can use the XmlElementWrapper annotation once, so that only chartdashlets get filled and incidentchartdashlets is null.
Is there any solution with JAXB without using a seperate wrapper class?
I assume your dashlet classes are defined like
class Chartdashlet extends Dashlet and class Incidentchartdashlet extends Dashlet.
Then the preferred JAXB way to handle your mixed list of dashlets would be
by using the #XmlElements
annotation:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "dashboardreport")
public class Dashboardreport {
#XmlElementWrapper(name = "data")
#XmlElements({
#XmlElement(name = "chartdashlet", type = Chartdashlet.class),
#XmlElement(name = "incidentchartdashlet", type = Incidentchartdashlet.class)
})
protected List<Dashlet> dashlets;
#XmlAttribute(name = "name")
protected String name;
}

Parsing optional nested XML Elements via JAXB

I have XML input that could basically look like this:
<mxGraphModel>
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<object label="" Property1="43" id="2">
<mxCell style="whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="196" y="161" width="200" height="30" as="geometry"/>
</mxCell>
</object>
<object label="" Property2="Helloooo" id="3">
<mxCell style="whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="192" y="269" width="200" height="30" as="geometry"/>
</mxCell>
</object>
<object label="" Property3="23" id="4">
<mxCell style="whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="210" y="383" width="200" height="30" as="geometry"/>
</mxCell>
</object>
</root>
</mxGraphModel>
I'm trying to parse this input via JAXB:
MxGraphModel.java:
#XmlRootElement(name = "mxGraphModel")
#XmlAccessorType(XmlAccessType.FIELD)
public class MxGraphModel {
#XmlElementWrapper(name = "root")
#XmlElement(name = "object")
private ArrayList<MxObject> mxObjects;
#XmlElement(name = "mxCell")
private ArrayList<MxCell> mxCells;
//getters and setters...
}
MxObject.java:
#XmlAccessorType(XmlAccessType.FIELD)
public class MxObject {
#XmlAttribute
private String id;
#XmlAttribute
private String label;
#XmlAttribute
private String documentName;
#XmlAttribute
private String documentDescription;
#XmlElement
private MxCell mxCell;
//getters and setters...
}
MxCell.java:
#XmlAccessorType(XmlAccessType.FIELD)
public class MxCell {
#XmlAttribute
private String id;
#XmlAttribute
private String parent;
#XmlAttribute
private String value;
#XmlAttribute
private String style;
#XmlAttribute
private String vertex;
#XmlElement(name = "mxGeometry")
private MxGeometry geometry;
//getters and setters...
}
DemoController.java:
#RestController
#RequestMapping("/xml")
public class DemoController {
#RequestMapping(method = RequestMethod.POST, consumes = {MediaType.APPLICATION_XML_VALUE})
public void parseXML(#RequestBody MxGraphModel mxGraphModel) {
//mxGraphModel contains EITHER objects of type MxObject
//OR
//MxCell
}
}
My problem is, that the parsing operation results in an MxGraphModel object that contains either a collection of objects OR a collection of mxCells - but never both.
It seems to me that the order in which I declare the XmlElements ("object" and "mxCell") is relevant for the parsing result. When I declare mxCell before object, 2 mxCells are being parsed (which is correct), but the object collection remains null. And the other way around.
Is it possible to have both XmlElements parsed? I don't know whether the issue is related to the fact that an object element could contain an mxCell element itself...
Thanks.
#Dimpre Jean-Sébastien:
You're totally right, sorry for posting the answer this late.
The solution is not to use the root ElementWrapper
So instead of using
#XmlElementWrapper(name = "root")
I had to create a root XmlElement in MxGraphModel.java:
#XmlElement(name = "root")
private MxRoot mxRoot;
Furthermore I created a file called MxRoot.java and moved all collections inside it:
MxRoot.java:
#XmlAccessorType(XmlAccessType.FIELD)
public class MxRoot {
#XmlElement(name = "UserObject")
private ArrayList<MxObject> mxUserObjects;
#XmlElement(name = "object")
private ArrayList<MxObject> mxObjects;
//XmlElement sets the name of the entities
#XmlElement(name = "mxCell")
private ArrayList<MxCell> mxCells;
//getters and setters...
}
It seems the #XmlWrapper Annotation expects exactly one collection. It is not meant to wrap around multiple collections (makes sense now that I know it :))
Thanks to all!

Retrofit with Simpleframework XML

I'm using retrofit to connect to my API and trying to parse messages with Simpleframework XML, but I keep getting the error below:
retrofit.RetrofitError: org.simpleframework.xml.core.ElementException: Element 'head' does not have a match in class Classes at line 5
Here are my classes and XML that I should be getting but Im connecting to an Microsoft asmx service and its returning the html above http://pastebin.com/ASvV0Cwq, somewhere in the soap envelope should be the xml body
#Root(name = "tables")
public class Classes
{
#ElementList(name = "tables", inline = true)
List<MyClass> tables;
}
:
Root(name="table")
public class MyClass implements Serializable
{
#Element(name = "id")
private String id;
#Element(name = "name")
private String name;
#Element(name = "value")
private String value;
#Element(name = "key")
private String key;
}
This should be the XML:
<?xml version="1.0" encoding="UTF-8"?>
<tables>
<table>
<id>1</id>
<name>Admin</name>
<value>111</value>
<key>999</key>
</table>
<table>
<id>5</id>
<name>Bari Limani</name>
<value>121</value>
<key>999</key>
</tables>
An end table tag is missing in the XML.

JAXB Element Wrapper for a Single Group of Elements When Marshalling

I wish to have an XML structure like this:
<?xml version="1.0" encoding="UTF-8"?>
<MSG>
<CASE>
<Field1></Field1>
<Field2></Field2>
</CASE>
</MSG>
The problem is, with the #XmlElementWrapper, I need a collection of items but there will be only 1 case item. How can I have multiple root elements, for a single collection of elements? Preferably in a single class.
I want something like this, but it throws an exception.
#XmlRootElement( name="MSG")
public class XMLStructure {
#XmlElementWrapper(name="CASE")
#XmlElement(name = "Field1")
private String field1;
#XmlElementWrapper(name="CASE")
#XmlElement(name = "Field2")
private String field2;
}
In the EclipseLink MOXy implementation of JAXB (JSR-222) we have an #XmlPath extension that enables you to map this as:
#XmlRootElement( name="MSG")
#XmlAccessorType(XmlAccessType.FIELD)
public class XMLStructure {
#XmlPath("CASE/Field1/text()")
private String field1;
#XmlPath("CASE/Field2/text()")
private String field2;
}
For More Information
I have written more about the #XmlPath extension on my blog:
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html

Serialize Java List to XML using Jackson XML mapper

Hi I need to create an XML from JAVA using Jackson-dataformat XMLMapper.
The XML should be like
<Customer>
<id>1</id>
<name>Mighty Pulpo</name>
<addresses>
<city>austin</city>
<state>TX</state>
</addresses>
<addresses>
<city>Hong Kong</city>
<state>Hong Kong</state>
</addresses>
</Customer>
But I get it always like with an extra "< addresses> < /addresses>" tag.
<Customer>
<id>1</id>
<name>Mighty Pulpo</name>
<addresses>
<addresses>
<city>austin</city>
<state>TX</state>
</addresses>
<addresses>
<city>Hong Kong</city>
<state>Hong Kong</state>
</addresses>
<addresses>
</Customer>
I am using below code to create XML
JaxbAnnotationModule jaxbAnnotationModule = new JaxbAnnotationModule();
XmlMapper mapper = new XmlMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.registerModule(jaxbAnnotationModule);
mapper.registerModule(new GuavaModule());
String xml = mapper.writeValueAsString(customer);
System.out.println(xml);
Please can some one help me? How can I remove the extra tag please. I have tried to use #XmlElement but it does not help help. TIA!!
Try the below code
#JacksonXmlRootElement(localName = "customer")
class Customer {
#JacksonXmlProperty(localName = "id")
private int id;
#JacksonXmlProperty(localName = "name")
private String name;
#JacksonXmlProperty(localName = "addresses")
#JacksonXmlElementWrapper(useWrapping = false)
private Address[] address;
// you can add it on getter method instead of declaration.
#JacksonXmlElementWrapper(useWrapping = false)
public Address[] getAddress(){
return address;
}
//getters, setters, toString
}
class Address {
#JacksonXmlProperty(localName = "city")
private String city;
#JacksonXmlProperty(localName = "state")
private String state;
// getter/setter
}
This setting changes default wrapping behavior, if you don't want to deal with annotation everywhere in your code.
XmlMapper mapper = new XmlMapper();
mapper.setDefaultUseWrapper(false);
Just to add to ManojP's answer, if adding the #JacksonXmlElementWrapper(useWrapping = false) on the declaration of your variable doesn't work (which was the case for me), adding it to the getter method will do the trick.

Categories

Resources