Unmarshaling XML - java

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]

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;
}
}

JAXB Unmarshall XML with same tag name but different structure

I'm trying to unmarshall this kind of XML:
<result>
<avance>0.0000</avance>
<operation_status>0</operation_status>
<service>Bank Account</service>
<service>
<min_amount>1.00</min_amount>
<max_amount>1499.00</max_amount>
<currency>USD</currency>
</service>
</result>
I have created this kind of class structure:
public class Result {
private BigDecimal avance;
private Integer operationStatus;
private String serviceDesc;
private Service service;
#XmlElement(name = "service")
public String getServiceDesc() {
return serviceDesc;
}
public void setServiceDesc(String serviceDesc) {
this.serviceDesc = serviceDesc;
}
#XmlElement(name = "service")
public Service getService() {
return service;
}
public void setService(Service service) {
this.service = service;
}
#XmlElement(name = "avance")
public BigDecimal getAvance() {
return avance;
}
public void setAvance(BigDecimal avance) {
this.avance = avance;
}
#XmlElement(name = "operation_status")
public Integer getOperationStatus() {
return operationStatus;
}
public void setOperationStatus(Integer operationStatus) {
this.operationStatus = operationStatus;
}
}
and Service looks like this:
#XmlRootElement
public class Service {
private BigDecimal minAmount;
private BigDecimal maxAmount;
private String currency;
#XmlElement(name = "min_amount")
public BigDecimal getMinAmount() {
return minAmount;
}
public void setMinAmount(BigDecimal minAmount) {
this.minAmount = minAmount;
}
#XmlElement(name = "max_amount")
public BigDecimal getMaxAmount() {
return maxAmount;
}
public void setMaxAmount(BigDecimal maxAmount) {
this.maxAmount = maxAmount;
}
#XmlElement(name = "currency")
public String getCurrency() {
return currency;
}
public void setCurrency(String currency) {
this.currency = currency;
}
}
When I receive response from some external service I'm able to unmarshal that string and result has correct Service class set but serviceDesc is always null. Is there any way how I can unmarshall this structure correctly?
In another question (for which this question is marked as duplicate) case is when you have same tag name but different number of attributes in my case content of the tag is different, also in that question classes to which content should be unmarshaled are child and parent in my case one is String another one some custom object. Think that's why I wasn't able to implement XmlAdapter properly.
Your XML structure is not valid.
You shouldn't have the same tag twice for different structure in the same namespace.
Solutions :
Rename your tag (serviceDesc for example)
Use 2 different namespaces ( ns1:service and ns2:service for example)

JAXB umarshall exception

I am new to Jaxb and having problem parsing a simple XML. The XML in question is shown below:
<tables>
<table id="1" >
<schema>validator_test</schema>
<name>test1</name>
<rowCountToValidate>6</rowCountToValidate>
<columnTypeCheckRequired>FALSE</columnTypeCheckRequired>
<additionalColumns>column1,column2</additionalColumns>
</table>
<table id="2">
<schema>validator_test</schema>
<name>validate_external1</name>
<rowCountToValidate>2</rowCountToValidate>
<columnTypeCheckRequired>FALSE</columnTypeCheckRequired>
<additionalColumns>column1,column2</additionalColumns>
</table>
<table id="3">
<schema>validator_test</schema>
<name>Test_View1</name>
<rowCountToValidate>2</rowCountToValidate>
<columnTypeCheckRequired>FALSE</columnTypeCheckRequired>
<additionalColumns>column1,column2</additionalColumns>
</table>
</tables>
The Jaxb class to unmarshall this is:-
#XmlRootElement(name = "table")
#XmlType(propOrder = { "name", "schema", "rowCountToValidate","columnTypeCheckRequired","additionalColumns","targetName"})
#Service
public class TableInfo {
private static final boolean TRUE = true;
#Value("${default.row.count.to.validate}")
private Integer defaultRowCountToValidate;
/**
*
*/
public TableInfo() {
}
private String name;
private String schema;
private Integer rowCountToValidate;
private String targetName;
private String columnTypeCheckRequired;
private String additionalColumns;
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(name = "schema")
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
#XmlElement(name = "rowCountToValidate")
public Integer getRowCountToValidate() {
return rowCountToValidate;
}
#XmlElement(name = "columnTypeCheckRequired")
public String getColumnTypeCheckRequired() {
return columnTypeCheckRequired;
}
public void setColumnTypeCheckRequired(String columnTypeCheckRequired) {
this.columnTypeCheckRequired = columnTypeCheckRequired;
}
#XmlElement(name = "additionalColumns")
public String getAdditionalColumns() {
return additionalColumns;
}
public void setAdditionalColumns(String additionalColumns) {
this.additionalColumns = additionalColumns;
}
public void setRowCountToValidate(Integer rowCountToValidate) {
// If user configured value is not null and greater than zero then set
// the value otherwise use default value
if ((null != rowCountToValidate) && (rowCountToValidate.intValue() > 0)) {
this.rowCountToValidate = rowCountToValidate;
}else {
this.rowCountToValidate = defaultRowCountToValidate;
}
}
#XmlElement(name = "targetName")
public String getTargetName() {
return targetName;
}
public void setTargetName(String targetName) {
this.targetName = targetName;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
However, I am ggetting the following exception:-
`JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"tables"). Expected elements are <{tables}table>`
I would really appreciate if someone can point out the error I am doing. I am new to this and am not really able to understand how jaxb works.
You need to create class Tables with #XmlRootElement(name = "tables") and that class must contain table field with type TableInfo.
When you unmarshal example xml, you need to pass Tables class to unmarshaller.
#XmlRootElement(name = "table")
<tables>
<table id="1" >
Below are the 2 solution for above issue:
You need to generate the classes using XSD.
You need to generate the classes as per your required XML:
in XML table is inside the tables so tables should be the root element.
And table should be in the form of list in tables class.
in your code root element is #XmlRootElement(name = "table") where in your XML file it is "tables"
Suggest you to use xjc command to build java POJO classes automatically
xjc -d -p sample.xsd
-d to define where the generated classes shall be stored in the file system,
-p to define the package to be used

Parsing XML with more sub-elements with JAXB

I have such XML and I want to parse it into Java object.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CreatePreOrderResponse>
<Errors>
<Error>
<Code>code 1</Code>
<Message>message 1</Message>
<ErrorElement>element 1</ErrorElement>
</Error>
<Error>
<Code>code 2</Code>
<Message>message 2</Message>
<ErrorElement>element 2</ErrorElement>
</Error>
</Errors>
</CreatePreOrderResponse>
I work with JAXB to parse XML string that has no "sub elements", has only one element with its values at the level of errors.
Question: I would like to know how to get all Error elements in Errors element, e.g. into List in CreatePreOrderResponse object? Is it possible to parse it automatically with JAXB unmarshaller ro do I have to traverse XML and parse it manually?
NOTE: just for information, this works for me - these classes I use for parsing this XML (with no sub-elements).
<CreatePreOrderResponse>
<PreOrder>
<ID>123456789</ID>
</PreOrder>
</CreatePreOrderResponse>
BtnPreorderResponse
#XmlRootElement(name = "CreatePreOrderResponse")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlSeeAlso(BtnDocLine.class)
public class BtnPreorderResponse {
#XmlElement(name = "PreOrder")
private BtnPreorder btnPreorder;
#XmlElement(name = "Errors")
private BtnErrorListType btnErrorListType;
public BtnPreorder getBtnPreorder() {
return btnPreorder;
}
public void setBtnPreorder(BtnPreorder btnPreorder) {
this.btnPreorder = btnPreorder;
}
public BtnErrorListType getBtnErrorListType() {
return btnErrorListType;
}
public void setBtnErrorListType(BtnErrorListType btnErrorListType) {
this.btnErrorListType = btnErrorListType;
}
#Override
public String toString() {
return "BtnPreorderResponse{" +
"btnPreorder=" + btnPreorder +
", btnErrorListType=" + btnErrorListType +
'}';
}
}
BtnPreorder
#XmlRootElement(name = "PreOrder")
#XmlAccessorType(XmlAccessType.FIELD)
public class BtnPreorder {
#XmlElement(name = "ID")
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
#Override
public String toString() {
return "BtnPreorder{" +
"id=" + id +
'}';
}
}
I suppose you've already implemented individual error clause as class BtnErrorType. Now comes the list of them:
#XmlType(name = "Errors")
#XmlAccessorType(XmlAccessType.FIELD)
public class BtnErrorListType {
#XmlElement(name = "Error")
private ArrayList<BtnErrorType> btnError;
...
public ArrayList<BtnErrorType> getBtnError() {
if (btnError == null)
btnError = new ArrayList<BtnErrorType>();
return btnError;
}
...
}
Note, that there is only getter and you should call it if you want to add elements to list.

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.

Categories