hi I got the following response as a string when hitting a client.
I need to unmarshall it so that I can set the values in a Java object and send it back to front end. Kindly help me to convert the following xml string to jaxb object.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:ValidateAustralianAddressResponse xmlns:ns2="http://api.auspost.com.au/ValidateAustralianAddress:v1">
<Address><AddressLine>481 CHURCH ST</AddressLine><SuburbOrPlaceOrLocality>RICHMOND</SuburbOrPlaceOrLocality><StateOrTerritory>VIC</StateOrTerritory><PostCode>3121</PostCode><DeliveryPointIdentifier>55461002</DeliveryPointIdentifier><Country><CountryCode>AU</CountryCode><CountryName>Australia</CountryName></Country></Address>
<ValidAustralianAddress>true</ValidAustralianAddress>
</ns2:ValidateAustralianAddressResponse>
Metadata
Since only the root element is namespace qualified you just need to set the namespace parameter on the #XmlRootElement annotation.
#XmlRootElement(name="ValidateAustralianAddressResponse", namespace="http://api.auspost.com.au/ValidateAustralianAddress:v1")
public class ValidateAustralianAddressResponse {
}
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Converting XML to Object
You can wrap the XML String in an instance of StringReader and unmarshal that.
For More Information
http://blog.bdoughan.com/2011/08/jaxb-and-java-io-files-streams-readers.html
Related
I am using a Web service and it returns a String value. But in my output, that value is in XML format:
String point = request.getParameter("point");
try {
String latLonListCityNames = proxy.latLonListCityNames(new BigInteger(point));
request.setAttribute("point", latLonListCityNames);
System.out.println(latLonListCityNames);
} catch (RemoteException e) {
e.printStackTrace();
}
I expect the output to be for example "Oklahoma", but the actual output is:
<?xml version='1.0' ?>
<dwml version='1.0' xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">
<latLonList>
<cityNameList>
Oklahoma
</cityNameList>
</dwml>
The responses of web-services are commonly (not always) in XML. If you need to extract the data from xml string response to your desired format, say, Java Objects (POJO), you need a converter i.e. marshaling and Un-marshaling of data.
Simple solution
Use JAXB.
What is JAXB? From wiki
Java Architecture for XML Binding (JAXB) is a software framework that allows Java developers to map Java classes to XML representations. JAXB provides two main features: the ability to marshal Java objects into XML and the inverse, i.e. to unmarshal XML back into Java objects.
How does it fit into my use-case?
Create a simple POJO for the type of response you are expecting. And then use JAXB convertor to convert them for you.
Eg. If you are expecting a list of cityName in response, you can create your POJO like below..
CityModel.java
public Class CityModel {
private List<String> cityName;
// if more field required, add here.
}
Sample XML response should be..
<ListOfCities>
<CityName>My City</CityName>
<CityName>Your City</CityName>
<CityName>So Pity</CityName>
</ListOfCities>
Then, pass this xml response string to JAXB binding for Equivalent Class type. i.e. CityModel.
How to do all this? Can You Share some good example?
Read this tutorial to get started.
I have problem with the response type names, they are not well described, how can I map them with different name that I want?
You might need to look at links below, they key part is investigate more about #XmlRootElement, #XmlAttribute, #XmlElement, etc annotations for custom configurations.
Few more important links that can help later on?
Convert Soap XML response to Object
convert xml to java object using jaxb (unmarshal)
Using JAXB for XML With Java
JAXB Unmarshalling Example: Converting XML into Object
Here's the xml I receive
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header/>
<soap-env:Body RequestId="1503948112779" Transaction="HotelResNotifRS">
<OTA_HotelResNotifRS xmlns="http://www.opentravel.org/OTA/2003/05" TimeStamp="2017-08-28T19:21:54+00:00" Version="1.003">
<Errors>
<Error Code="450" Language="en-us" ShortText="Unable to process " Status="NotProcessed" Type="3">Discrepancy between ResGuests and GuestCounts</Error>
</Errors>
</OTA_HotelResNotifRS>
</soap-env:Body>
</soap-env:Envelope>
This gets pseudo unmarshalled into an OTAHotelResNotifRS object which you can get .getErrors() on. The issue is that there was no type associated with this bit, so it comes back as an Object which is in the form of an ElementNSImpl. I don't control the OTAHotelResNotifRS object, so my best bet is to unmarshal the .getErrors() object into a pojo of my own. This is my attempt.
#XmlRootElement(name = "Errors")
#XmlAccessorType(XmlAccessType.FIELD)
public class CustomErrorsType {
#XmlAnyElement(lax = true)
private String[] errors;
public String[] getErrors() {
return errors;
}
}
This is the code used to try to unmarshal it into my CustomErrorsType object
Object errorsType = otaHotelResNotifRS.getErrors();
JAXBContext context = JAXBContext.newInstance(CustomErrorsType.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
CustomErrorsType customErrorsType = (CustomErrorsType)unmarshaller.unmarshal((Node)errorsType);
It throws the following exception when calling unmarshal
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.opentravel.org/OTA/2003/05", local:"Errors"). Expected elements are <{}Errors>
Any thoughts? I'm pretty weak when it comes to xml unmarshalling.
You are ignoring the XML namespace in the response, as defined in the xmlns attribute. See https://www.w3.org/TR/xml-names/ for a full explanation of namespaces and the attributes which define them.
A standard notation for describing an XML name with its namespace is {namespace-uri}local-name. So the exception is literally telling you that your CustomErrorsType expects an element with the local name Errors and an empty namespace ({}), but instead it encountered an element with the local name Errors and a namespace which is http://www.opentravel.org/OTA/2003/05.
Try changing this:
#XmlRootElement(name = "Errors")
to this:
#XmlRootElement(name = "Errors", namespace = "http://www.opentravel.org/OTA/2003/05")
As a side note, if you have access to the WSDL which defines the SOAP service, you can make your task considerably easier by invoking the standard JDK tool wsimport with the WSDL’s location as an argument. All marshalling will be implicitly taken care of by the generated Service and Port classes.
I have an application that reads and writes data from/to XML files to/from a DB using JAXB. The "human readability" of these XML files is one of the top priorities in this project as the idea is that XML files from different DBs can be compared to each other.
Now, I have some tables with attributes that hold XML strings themselves which need to be included to my JAXB objects. As I don't have control over these XML strings and readability is key, I helped myself so far with an XmlAdapter that pretty prints the XML from the DB and wraps it in a CDATA element.
The problem of this solution is that the XML string looks a bit lost within the CDATA element and smart text editors with syntax highlighting don't recognize the XML, so they don't highlight the syntax of that XML.
I was wondering therefore if there's a way to "embed" this XML within an element of my JAXB model as if it would be part of the model. So, I need a kind of XmlAdapter that would parse an XML from a String field of my JAXB class and somehow pass the parsing events to the underlying XMLWriter.
I've spent a lot of time looking for a solution combining JAXB and Stax but didn't succeed. In my view I would need some hook exactly between the JAXB and the Stax layer, so that I can customize the events that JAXB sends to the Stax Writers.
Example:
#XmlRootElement
public class MyJaxbModel {
#XmlAttribute
private Integer anAttribute;
#XmlElement
private String xml;
public MyJaxbModel(Integer anAttribute, String xml) {
this.anAttribute = anAttribute;
this.xml = xml;
}
...
}
Then marshalling the following instance of this class
new MyJaxbModel(999, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><element1><child1>bla</child1><child2>ble</child2></element1>");
should result in the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<MyJaxbModel anAttribute="999">
<xml>
<element1>
<child1>bla</child1>
<child2>ble</child2>
</element1>
</xml>
</MyJaxbModel>
Obviously I need it to work also the other way round, i. e. unmarshalling this XML would return me the MyJaxbModel object including the XML string in the xml field.
I am using Spring and it's REST template to bind XML from a webservice to a domain object using JAXB. The XML returned from the web service is as follows:
<response>
<user>
<id>1</id>
<name>bob</name>
...
</user>
</response>
I have a user class as follows:
public class User {
private String id;
private String name;
}
Is it possible to ignore the "response" element and specify the root element to "user"?
Thanks for any help.
XML that represents your class, has like a root <user> tag.
So:
or you use a java parser to extract the user subtree and after use JAXB,
otherwise you create another class response to mapping your webservice response.
I suggest the second choice.
For informations, when you use whatever XML-binding framework, you must remember the one-to-one relation between class fields and XML tags.
I have a JAXB object (ProductRequest) that represents an XML document for a webservice request. Assume it looks something like this:
<ProductRequest>
<getProducts/>
</ProductRequests>
For the response, the JAXB object (ProductResponse) will represent an XML document as shown below:
<ProductResponse>
<productId>1</productId>
<productName>Oranges</productName>
<productId>2</productId>
<productName>Apples</productName>
</ProductResponse>
Using Spring-WS, i can send the web service the request using two approaches
Using the JAXB object
ProductRequest productRequest = new productRequest();
ProductResponse productResponse = (ProductResponse) webServiceTemplate
.marshalSendAndReceive(productRequest);
Using plain XML/DOM
DOMResult domresult = new DOMResult();
webServiceTemplate.sendSourceAndReceiveToResult(source, domresult); //source represents the XML document as a DOMSource object
Element responseElement = (Element) domresult.getNode().getFirstChild();
When i try both approaches, the results are different. The first approach using the JAXB object the result is
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProductResponse xmlns="http://mySchema">
<productId>1</productId>
<productName>Oranges</productName>
<productId>2</productId>
<productName>Apples</productName>
</ProductResponse>
The second approach using the XML Dom object the result is (Includes namespaces)
<?xml version="1.0" encoding="UTF-8"?>
<ns2:ProductResponse xmlns:ns2="http://mySchema">
<ns2:productId>1</ns2:productId>
<ns2:productName>Oranges</ns2:productName>
<ns2:productId>2</ns2:productId>
<ns2:productName>Apples</ns2:productName>
</ns2:ProductResponse>
The header for the schema used for the response on the web service is declared as:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:z="http://mySchema"
targetNamespace="http://mySchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
-- Schema elements
</xs:schema>
There are two differences in the response
The first line on the response from JAXB request includes the entry standalone="yes">
The elements on the JAXB version are not prefixed with the namespace
Shouldn't the response with elements prefixed with the schema have used "z" (as defined in the schema) instead of ns2?
I don't understand what could be causing this difference given that they are both calling the same web service which generates the response based on the same schema. Any ideas?
The XML content is the same but the difference in the format of the XML is giving me problems as i cant use String.equals() to compare the two.
The responses are the same, just that one isn't qualified with a namespace.
On a side note, your XML design looks a bit flaky. Might be better like this;
<ProductResponse>
<product>
<id>1</id>
<name>Oranges</name>
</product>
<product>
<id>2</id>
<name>Apples</name>
</product>
</ProductResponse>
Why? Because you shouldn't rely on the order of elements.
The result is the same. ns2 is just the prefix for the namespace, jaxb uses default namespace and XML Dom uses a the prefix ns2. The xml files are equivalent, and both of them are valid against that schema. You can read more about XML namespace here.