We are unmarshalling a response from http://xmlgw.companieshouse.gov.uk/. This is the text sent to the marshall:
<NameSearch xmlns="http://xmlgw.companieshouse.gov.uk/v1-0/schema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlgw.companieshouse.gov.uk/v1-0/schema http://xmlgw.companieshouse.gov.uk/v1-0/schema/NameSearch.xsd">
<ContinuationKey>...</ContinuationKey>
<RegressionKey>...</RegressionKey>
<SearchRows>20</SearchRows>
<CoSearchItem>
<CompanyName>COMPANY NAME</CompanyName>
<CompanyNumber>23546457</CompanyNumber>
<DataSet>LIVE</DataSet>
<CompanyIndexStatus>DISSOLVED</CompanyIndexStatus>
<CompanyDate></CompanyDate>
</CoSearchItem>
// more CoSearchItem elements
</NameSearch>
The model of CoSearchItem is like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "CoSearchItem", propOrder = {
"companyName",
"companyNumber",
"dataSet",
"companyIndexStatus",
"companyDate",
"searchMatch"
})
public class CoSearchItem {
#XmlElement(name = "CompanyName", required = true)
protected String companyName;
#XmlElement(name = "CompanyNumber", required = true)
protected String companyNumber;
#XmlElement(name = "DataSet", required = true)
protected String dataSet;
#XmlElement(name = "CompanyIndexStatus")
protected String companyIndexStatus;
#XmlElement(name = "CompanyDate")
#XmlSchemaType(name = "date")
protected XMLGregorianCalendar companyDate;
#XmlElement(name = "SearchMatch")
protected String searchMatch;
// getters and setters
}
NameSearch model has this structure:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "NameSearch", namespace = "http://xmlgw.companieshouse.gov.uk/v1-0/schema", propOrder = {
"continuationKey",
"regressionKey",
"searchRows",
"coSearchItem"
})
#XmlRootElement(name = "NameSearch", namespace = "http://xmlgw.companieshouse.gov.uk/v1-0/schema")
public class NameSearch {
#XmlElement(name = "ContinuationKey", required = true)
protected String continuationKey;
#XmlElement(name = "RegressionKey", required = true)
protected String regressionKey;
#XmlElement(name = "SearchRows", required = true)
protected BigInteger searchRows;
#XmlElement(name = "CoSearchItem")
protected List<CoSearchItem> coSearchItem;
// setters and getters
}
The package has this annotations:
#XmlSchema(namespace = "http://xmlgw.companieshouse.gov.uk/v1-0", elementFormDefault = XmlNsForm.QUALIFIED, //
xmlns = {
#XmlNs(prefix = "xsi", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance")
}
)
package uk.gov.companieshouse;
The unmarshaling is done from the first Node extracted from a larger Document, inside an any list of items. When we parse the xml however all the fields in CoSearchItem are set to null and can't figure out the reason.
You need to use a package level #XmlSchema annotation to specify the namespace qualification for your model.
#XmlSchema(
namespace = "http://xmlgw.companieshouse.gov.uk/v1-0/schema",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
This this specified you do not require to specify the namespace URI on the #XmlRootElement and #XmlType on your NameSearch class.
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
The unmarshaling is done from the first Node extracted from a larger
Document, inside an any list of items.
Make sure the DOM parer used to create the nodes is namespace aware.
documentBuilderFactory.setNamespaceAware(true);
I figured out the correct answer thanks to #Blaise Doughan. After looking at the package namespace qualification I found that it was pointing to:
"http://xmlgw.companieshouse.gov.uk/v1-0"
and it should have been pointing to:
"http://xmlgw.companieshouse.gov.uk/v1-0/schema"
Not sure how that got misplaced.
I solved this by making elementFormDefault="unqualified" in the xsd before generating stubs, else make the change manually in package-info.java
Related
Exception :
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.cleartrip.com/hotel/hotel-search-response", local:"hotel-search-response"). Expected elements are (none)
MyTestFile.txt(XML) :
<hotel-search-response xmlns="http://www.cleartrip.com/hotel/hotel-search-response" xmlns:hotel-info="http://www.cleartrip.com/places/hotel-info" xmlns:common="http://www.cleartrip.com/hotel/common">
<search-criteria>
<booking-date>2018-12-12+05:30</booking-date>
<check-in-date>2018-12-14+05:30</check-in-date>
<check-out-date>2018-12-16+05:30</check-out-date>
<number-of-rooms>1</number-of-rooms>
<number-of-nights>2</number-of-nights>
<number-of-room-nights>2</number-of-room-nights>
<city>Bangalore</city>
<country>IN</country>
</search-criteria>
<currency>INR</currency>
JAXB Class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "hotel-search-response", propOrder = {
"searchCriteria",
"additionalCurrency",
"currency",
"baseUrl",
"hotels",
"pgfeeJson",
"pgchargeJson"
})
public class HotelSearchResponse {
#XmlElement(name = "search-criteria", required = false)
protected SearchCriteria searchCriteria;
#XmlElement(name = "additional-currency",required= false)
protected AdditionalCurrency additionalCurrency;
#XmlElement(required = false)
protected String currency;
#XmlElement(name = "base-url", required = false)
protected String baseUrl;
#XmlElement(required = false)
protected Hotels hotels;
#XmlElement(name = "pgfee-json", required = false)
protected String pgfeeJson;
#XmlElement(name = "pgcharge-json", required = false)
protected String pgchargeJson;
}
Java main class:
JAXBContext jc= JAXBContext.newInstance(HotelSearchResponse.class);
javax.xml.bind.Unmarshaller ums = jc.createUnmarshaller();
HotelSearchResponse emp=(HotelSearchResponse) ums.unmarshal(new File("E:/MyTestFile.txt"));
First, you need the have a #XmlRootElement. Second, you need to specify the namespace (since you use namespaces).
#XmlRootElement(name = "hotel-search-response", namespace = "http://www.cleartrip.com/hotel/hotel-search-response")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "hotel-search-response", propOrder = { "currency", "baseUrl",
"pgfeeJson", "pgchargeJson" }, namespace = "http://www.cleartrip.com/hotel/hotel-search-response")
public class HotelSearchResponse
Above, the propOrder is simplified.
I'm trying to figure out how to get the list of elements (all the names in the 'propOrder') from an auto-generated Java file that was created using JAXB. I want something along the lines of:
List String> elements = getXMLElements(ExampleInfo.class);
I can't edit the generated java class because the XSD schema might be changed. I'm trying to get the elements which would be startTime, stopTime, and id.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "exampleInfo", propOrder = {
"startTime",
"stopTime",
"id",
...
})
public class ExampleInfo
extends TypeInfo
{
#XmlElement(name = "StartTime")
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar startTime;
#XmlElement(name = "StopTime")
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar stopTime;
#XmlElement(name = "id")
...
}
You can do it quite easily with the help of method Class.getAnnotation(Class<A>):
public static List<String> getXMLElements(Class<?> clazz) {
XmlType xmlType = clazz.getAnnotation(XmlType.class);
if (xmlType == null)
return null;
String[] propOrder = xmlType.propOrder();
return Arrays.asList(propOrder);
}
Then use it like this:
List<String> elements = getXMLElements(ExampleInfo.class);
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;
}
all, I have a package full of Beans generated from xsd with Jaxb.
I want to use some of them into another Bean to marshal/unmarshal an XML like this:
<WrongDocument>
<test>test label</test>
<CBISDDReqLogMsg xmlns="urn:CBI:xsd:CBISDDReqLogMsg.00.01.00">
<GrpHdr>
....
</GrpHdr>
<PmtInf>
</PmtInf>
</CBISDDReqLogMsg>
</WrongDocument>
the root Bean is
#XmlRootElement(name="WrongDocument")
#XmlType(name = "", propOrder = {
"test",
"CBISDDReqLogMsg"
})
#XmlAccessorType(XmlAccessType.FIELD)
public class WrongDocumentDTO implements Serializable {
private static final long serialVersionUID = 8545918230166653233L;
#XmlElement(required = true, type = String.class, nillable = true)
protected String test;
#XmlElement(required = true)
protected CBISDDReqLogMsg000100 CBISDDReqLogMsg;
....
}
and the CBISDDReqLogMsg000100 is
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "CBISDDReqLogMsg.00.01.00", propOrder = {
"grpHdr",
"pmtInf"
})
public class CBISDDReqLogMsg000100
implements Serializable
{
private final static long serialVersionUID = 1L;
#XmlElement(name = "GrpHdr", required = true)
protected CBIGroupHeader2 grpHdr;
#XmlElement(name = "PmtInf", required = true)
protected List<PaymentInstructionInformation2> pmtInf;
....
}
For CBISDDReqLogMsg000100 namespace is defined with package-info file.
This is the code for unmarshalling:
jc = JAXBContext.newInstance(WrongDocumentDTO.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
WrongDocumentDTO wrongDocumentDTO = unmarshaller.unmarshal(source, WrongDocumentDTO.class).getValue();
Unfortunately, inside my wrongDocumentDTO i have test field populated with the right value, however CBISDDReqLogMsg is null.
How can i resolve this issue?
thank you in advance
You will need to specify the namespace specifically on the element if it is not default for the whole package.
#XmlElement(required = true, namespace = "urn:CBI:xsd:CBISDDReqLogMsg.00.01.00")
protected CBISDDReqLogMsg000100 CBISDDReqLogMsg;
I have a dtd file and i used jaxb to generate java classes.
<!ELEMENT Conf (Node+) >
<!ELEMENT Node EMPTY >
<!ATTLIST Node Key CDATA #REQUIRED
Value CDATA #REQUIRED >
jaxb generated this.
Conf class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"node"
})
#XmlRootElement(name = "Conf")
public class Conf {
#XmlElement(name = "Node", required = true)
protected List<Node> node;
Node class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "Node")
public class Node {
#XmlAttribute(name = "Key", required = true)
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
protected String key;
#XmlAttribute(name = "Value", required = true)
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
protected String value;
For me is the Node class pointless and i'd like to have a map instead:
public class Conf {
protected Map<String,String> map
}
I guess that im looking for XmlAdater, i've read javadocs but i still have problems to understand how it works.