Deserialization of xml with simplexml in java - java

I'm trying to deserialize an xml string with SimpleXML, i've looked at their examples but i'm not really sure that wether i grasp the concept or not.
Sample XML (validates):
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<Response xmlns="http://localhost/webservices/">
<Result>
<Item><ID>0</ID><language /><price>168</price></Item>
<Item><ID>1</ID><language /><price>178</price></Item>
<Item><ID>2</ID><language /><price>195</price></Item>
<Item><ID>3</ID><language /><price>169</price></Item>
<Item><ID>4</ID><language /><price>178</price></Item>
<Item><ID>5</ID><language /><price>178</price></Item>
<Item><ID>6</ID><language /><price>149</price></Item>
<Item><ID>7</ID><language /><price>178</price></Item>
<Item><ID>8</ID><language /><price>168</price></Item>
<Item><ID>9</ID><language /><price>179</price></Item>
<Item><ID>10</ID><language /><price>147</price></Item>
<Item><ID>11</ID><language /><price>165</price></Item>
<Item><ID>12</ID><language /><price>192</price></Item>
<Item><ID>13</ID><language /><price>218</price></Item>
<Item><ID>14</ID><language /><price>144</price></Item>
<Item><ID>15</ID><language /><price>141</price></Item>
</Result>
</Response>
</soap:Body></soap:Envelope>
And the java code:
#Root(name="Result",strict=false)
public class ItemList {
#ElementList(entry="Item")
private List<Item> _list;
public List<Book> GetItemList()
{
return _list;
}
public void SetItemList(List<Item> value)
{
this._list = value;
}
}
#Root(strict=false)
public class Item {
#Element(name="ID")
private String _ID;
#Element(name="price")
private String _price;
public String GetPrice()
{
return _price;
}
public void SetPrice(String value)
{
this._price = value;
}
public String GetID()
{
return _ID;
}
public void SetID(String value)
{
this._ID = value;
}
public Item(String ID,
String price)
{
this._ID = ID;
this._price = price;
}
}
Any help is appreciated.

I have a suggestion, but it's not ready to run (see below). However, ther maybe another, better solution ...
Class Item
Holding all your informations.
#Root(name="Item")
public class Item
{
#Element(name="ID", required=true)
private int id;
#Element(name="language", required=true)
private String language;
#Element(name="price", required=true)
private int price;
// ...
}
Class Result
Constructing everything around Item. Btw. you dont have to use inner classes here.
#Namespace(prefix="soap", reference="http://schemas.xmlsoap.org/soap/envelope/")
#Root(name="Envelope")
public class Result
{
#Namespace(prefix="soap")
#Element(name="Body")
private SoapBody body;
// ...
// -----------------------------------------------------------------
// -- Some inner classes, constructing the elements as in you xml --
// -----------------------------------------------------------------
#Namespace(prefix="soap")
#Root(name="Body")
static class SoapBody
{
#Element(name="Response")
private Response response;
// ...
}
#Root(name="Response")
static class Response
{
#ElementList(name="Result", required=true)
private List<Item> result;
// ...
}
}
(Example) How to use this code
Writing
File f = ...
Serializer ser = new Persister();
Result r = new Result();
ser.write(r, f);
Reading
File f = ...
Serializer ser = new Persister();
Result r = ser.read(Result.class, f);
Now ... there's one problem which prevents this example from running: <language />
This empty Element let SimpleXML throw a ValueRequiredException.

#Element( required=false)
private String language;
Add this in your Item class and generate the getter and setter.I think it should work

Related

UnMarshaling xml attribute and value in java using JAXB

I have a XML response from REST API like below :
<?xml version="1.0" encoding="UTF-8"?>
<ns2:testpla xmlns:ns2="http:xyz" xmlns:ns7="xyz">
<ns2:category term="Default Category" value="Default Category Value"/>
<ns2:testase ns7:resource="https://www.cyz.com" units="PH"
href="ww.com">XYZ</ns2:testase>
<ns2:testase ns7:resource="https://ww.cyz.com" units="LH"
href="ww.org">AZ</ns2:testase>
<com.abc xmlns="http://lq.net" extensionDisplayName="QWZ-KEY-TP-TEST-ZWE-
TI">
<div xmlns="http://www.w3.org/1999/xhtml">TriggerA ND confirm the
functionality</div>
</com.abc>
</ns2:testpla>
I know how to get the xml element value ie"XYZ"using jaxb and bind to bean. But I'm stuck on know how to fetch the value of resource(ie;"https://www.cyz.com"),units("PH"),href("ww.com"),value of xmlns inside div ?And then to map the value to object property.
Please help me.
create the separate two classes for testpla and testase
Testpla.java
#XmlRootElement(name = "ns2:testpla")
public class Testpla {
private Testase testase;
public Testase getTestase() {
return testase;
}
#XmlElement(name = "ns2:testase")
public void setTestase(Testase testase) {
this.testase = testase;
}
}
Testase.java
#XmlRootElement(name = "ns2:testase")
public class Testase {
private String resource;
private String units;
public String getResource() {
return resource;
}
#XmlAttribute(name = "ns7:resource")
public void setResource(String resource) {
this.resource = resource;
}
public String getUnits() {
return units;
}
#XmlAttribute(name = "units")
public void setUnits(String units) {
this.units = units;
}
}

Read From XML (List inside List) into Java Class Using Serializer

I did serialize same as this example without list inside list
but Cannot Serialize xml to list if its inside another list.the code of all classes and xml bellow :
Read Code:
PaymentEBillList bills = null;
try {
Serializer serializer = new Persister();
bills = serializer.read(PaymentEBillList.class, output);
} catch (Exception e) {
}
the list of Bills is null after executing code
PaymentEBillList Class:
#Root(name="ArrayOfPaymentBill")
public class PaymentEBillList {
#ElementList(required=true, inline=true)
public List<PaymentBill> list = new ArrayList<>();
}
PaymentBill Class:
#Root(name="PaymentBill")
public class PaymentBill {
#Element
public String SerialNumber;
#Element
public String CustomerName;
#Element
public String TotalAmount;
#Element
public EBillList EBill;
public PaymentBill()
{
super();
}
public PaymentBill(String SerialNumber, String CustomerName, String
TotalAmount,EBillList EBill) {
super();
this.SerialNumber = SerialNumber;
this.CustomerName = CustomerName;
this.TotalAmount = TotalAmount;
this.EBill= EBill;
}
}
EBillList Class:
#Root(name="Bill")
public class EBillList {
#ElementList(required=true, inline=true)
public List<EBill> list = new ArrayList<>();
}
EBill Class:
#Root(name="EBill")
public class EBill
{
#Element
public String NB;
#Element
public String Amount;
public EBill()
{
super();
}
public EBill( String NB,String Amount) {
super();
this.NB = NB;
this.Amount = Amount;
}
}
XML :
<ArrayOfPaymentBill>
<PaymentBill>
<SerialNumber>1</SerialNumber>
<CustomerName>XXX</CustomerName>
<TotalAmount>4500.00</TotalAmount>
<Bill>
<EBill>
<NB>1</NB>
<Amount>2500.00</Amount>
</EBill>
<EBill>
<NB>2</NB>
<Amount>2000.00</Amount>
</EBill>
</Bill>
</PaymentBill>
<PaymentBill>
<SerialNumber>2</SerialNumber>
<CustomerName>YYY</CustomerName>
<TotalAmount>2900.00</TotalAmount>
<Bill>
<EBill>
<NB>1</NB>
<Amount>2900.00</Amount>
</EBill>
</Bill>
</PaymentBill>
</ArrayOfPaymentBill>
Any Suggestion to solve this issue
Inside PaymentBill.java you should name EBillList according to XML:
#Element
public EBillList Bill;
or specify XML name in the annotation:
#Element(name = "Bill")
public EBillList EBill;
Sorry its work as its in question the issue because of mistake in XML as Alexey edit question with correction of XML

Unmarshaling XML

I'm trying to unmarshal existing xml file so that i can handle the data properly but the XML structure looks weird. below is the sample of the xml together with the objects I've created.
<?xml version="1.0" encoding="UTF-8"?>
<Record>
<identifier>11</identifier>
<TotalRecords>266</TotalRecords>
<ListOfSections>
<SECTION>AA1001</SECTION>
<ListOfStudents>
<SequenceNumber>11</SequenceNumber>
<RecordCount>1</RecordCount>
<StudentId>201614354</StudentId>
</ListOfStudents>
<SECTION>AA1002</SECTION>
<ListOfStudents>
<SequenceNumber>15</SequenceNumber>
<RecordCount>1</RecordCount>
<StudentId>201614356</StudentId>
<SequenceNumber>16</SequenceNumber>
<RecordCount>2</RecordCount>
<StudentId>201614355</StudentId>
</ListOfStudents>
</ListOfSections>
</Record>
Below are my java classes. I just removed the variables for readability.
#XmlRootElement
public class Record {
#XmlElement(name = "TotalRecords")
public Integer getTotalNoOfRecords() {
return totalNoOfRecords;
}
#XmlElement(name = "ListOfSections")
public List<Section> getSectionList() {
return sectionList;
}
}
#XmlRootElement
public class Section {
#XmlElement(name = "SECTION")
public String getSection() {
return section;
}
#XmlElement(name = "ListOfStudents")
public List<Student> getStudentList() {
return studentList;
}
}
#XmlRootElement
public class Student {
#XmlElement(name = "SequenceNumber")
public Integer getSequenceNumber() {
return sequenceNumber;
}
#XmlElement(name = "RecordCount")
public Integer getRecordCount() {
return recordCount;
}
#XmlElement(name = "StudentId")
public Integer getStudentId() {
return studentId;
}
}
I was trying to get all the records within the ListOfSections tag but I'm only getting the last section which is AA1002.
for the ListOfStudents I'm only getting the first record in my case I'm only getting record with sequence number 15
<SequenceNumber>12</SequenceNumber>
<RecordCount>2</RecordCount>
<StudentId>201614355</StudentId>
This simplified code works with your xml, it should give you a hint where to look for the problem:
class Record {
#XmlElementWrapper(name="ListOfSections")
#XmlElement(name="SECTION")
List<String> listOfSections;
}
here how to run:
Record r = JAXB.unmarshal(new File("1.xml"), Record.class);
System.out.println(r.listOfSections);
result:
[AA1001, AA1002]

How can I encourage JAXB to read XmlElement content string?

I'm not getting my "announcements" when I try to parse messages like these:
<?xml version="1.0" encoding="UTF-8"?>
<message messageType="SUBSCRIBER" messageName="ANNOUNCEMENT">
<announcement time="12:30">
Lunchtime!
</announcement>
<announcement time="32:00">
Good night ...
</announcement>
<errorText>Phone number missing, subscriber: Dick</errorText>
</message>
The JAXB Java class seemed pretty straightforward. And is based on similar messages that work. In this case the difference seems to be that I can have two different types of nested element (XmlElement) in the main block.
The code below actually parses the XML but it doesn't call the Announcement.setMessageText() method. Whereas I can see that the time attribute is set from the XML and I have an array size=2 for announcements, it reads and sets the single errorText XmlElement. Btw, I also removed the tag from the code and XML -- Not change in treatment of my messageText. Ideas welcome!
#XmlRootElement(name = "message")
public class AnnouncementMessage
{
#XmlAttribute
public String getMessageName(){
return this.messageName;
}
public void setMessageName( String name ){
this.messageName = name;
}
#XmlAttribute
public String getMessageType(){
return messageType;
}
public void setMessageType( String newMessageType ){
this.messageType = newMessageType;
}
#XmlElement(name = "errorText")
public String getErrorText(){
return errorText;
}
public void setErrorText( String newMsg ){
this.errorText = newMsg;
}
private List<Announcement> announcements = new ArrayList<>();
#XmlElement(name = "announcement")
public List<Announcement> getAnnouncements(){
return this.announcements;
}
public void setAnnouncements( List<Announcement> newAnnouncements ){
this.announcements = newAnnouncements;
}
}
And the Announcement class:
#XmlRootElement(name = "announcement")
public class Announcement
{
private String messageText = "";
private String time = "12:00";
XmlAttribute(name ="time")
public String getTime(){
return this.time;
}
public void setTime( String newMsg ){
this.messageText = time;
}
#XmlElement(name="announcement")
public String getMessageText(){
return this.messageText;
}
public void setMessageText( String newMsg ){
this.messageText = newMsg;
}
Announcement(){
}
}
Using the name parameter in the for the XmlElement seem to make no difference. My thanks in advance.
Use the #XmlValue annotation for the message text:
#XmlValue
public String getMessageText(){
return this.messageText;
}
Additionally, as noted in this related answer by OP, an #XmlAccessorType(XmlAccessType.NONE) is needed on the Announcement class if it contains getter/setter pairs that are not mapped to/from XML and don't have an #XmlTransient annotation.

Custom IDResolver gets wrong target type

I wrote this custom IDResolver:
final class MyIDResolver extends IDResolver {
Map<String, Course> courses = new HashMap<>();
/**
* #see com.sun.xml.bind.IDResolver#bind(java.lang.String, java.lang.Object)
*/
#Override
public void bind(String id, Object obj) throws SAXException {
if (obj instanceof Course)
courses.put(id, (Course)obj);
else
throw new SAXException("This " + obj.toString() + " cannot found");
}
/**
* #see com.sun.xml.bind.IDResolver#resolve(java.lang.String, java.lang.Class)
*/
#Override
public Callable<?> resolve(final String id, final Class targetType) throws SAXException {
return new Callable<Object>() {
#Override
public Object call() throws Exception {
if (targetType == Course.class)
return courses.get(id);
else
throw new ClassNotFoundException(targetType.toString() + " cannot found");
}
};
}
}
And I have two classes like:
#XmlRootElement(name = "course")
public class Course {
#XmlID
#XmlAttribute
private String id;
#XmlAttribute
private int units;
#XmlAttribute
private Level level;
#XmlAttribute
private String name;
#XmlIDREF
#XmlElement(name = "pre")
private ArrayList<Course> prerequisite;
#XmlIDREF
#XmlElement(name = "co")
private ArrayList<Course> corequisite;
}
#XmlRootElement(name = "dept")
#XmlAccessorType(XmlAccessType.FIELD)
public final class Department {
#XmlAttribute
private String name;
#XmlElementWrapper(name = "courses")
#XmlElement(name = "course")
private ArrayList<Course> courses;
}
And sample XML like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<dept name="ece">
<courses>
<course id="1" units="4" level="UNDERGRADUATE" name="Fundamentals of Programming"/>
<course id="2" units="3" level="UNDERGRADUATE" name="Advanced Programming">
<pre>1</pre>
</course>
</courses>
</dept>
And a simple main like this:
unmarshaller.unmarshal(new FileReader(arg0))
context = JAXBContext.newInstance(Department.class);
unmarshaller = context.createUnmarshaller();
unmarshaller.setProperty(IDResolver.class.getName(), new MyIDResolver());
The resolve() method of a custom IDResolver gets Object.class as targetType. But it should be Course.class. This results in wrong ID resolving. Where is my problem?
You should not use IDResolve when Department contains course. It should be used when Department want to reference to a Course. So for this reason when jaxb arrives a course inside of a department that it contains an element (here <pre>) it will pass object.class to your resolve function.

Categories