I need to unmarshall the following xml String named retornoExtrato in my code
<?xml version="1.0" encoding="UTF-8" ?>
<extrato xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<erro>
<codigo/>
<descricao/>
</erro>
<consultaextrato>
<header><![CDATA[SOME MULTIPLE
LINES HEADER]]></header>
<body><![CDATA[SOME MULTIPLE
LINES BODY]]></body>
<trailer><![CDATA[SOME MULTIPLE
LINES TRAILER]]></trailer>
</consultaextrato>
</extrato>
into an Extrato object, here are my classes (constructors, getters and setters ommited when default)
#XmlRootElement(name = "extrato")
public class Extrato {
private Erro erro;
private ConsultaExtrato consultaExtrato;
}
#XmlRootElement(name = "erro")
public class Erro {
private String codigo;
private String descricao;
}
#XmlRootElement(name = "consultaextrato")
public class ConsultaExtrato {
private String header;
private String body;
private String trailer;
#XmlCDATA
public String getHeader() {
return header;
}
#XmlCDATA
public String getBody() {
return body;
}
#XmlCDATA
public String getTrailer() {
return trailer;
}
}
The situation is when unmarshalling:
Erro always get umarshelled
ConsultaExtrato is getting null
Unmarshaller jaxbUnmarshaller = JAXBContext.newInstance(Extrato.class).createUnmarshaller();
Extrato extrato = (Extrato) jaxbUnmarshaller.unmarshal(new StringReader(retornoExtrato));
On the other hand, if I create a xml with only the consultaextrato tag, it gets unmarshelled ok. But it doesn't seems to work as an inner tag.
I've tried some extra jaxb annotation in all classes, none worked. What am I missing here?
You need to tell JAXB that the XML element <consultaextrato>
within the <extrato> element corresponds to
the Java property consultaExtrato in your Extrato class.
You do this by annotating this property (or rather its getter or setter method)
with #XmlElement and giving the XML name there:
#XmlElement(name = "consultaextrato")
If you don't do this, then JAXB would derive the XML element name
from the Java property name (i.e. consultaExtrato) and thus
get no match because of the different spelling.
And by the way: The #XmlRootElement(name = "consultaextrato")
has an effect only if the <consultaextrato> is the root element
of your XML content, but not if <consultaextrato> is a nested
element within another element (in your case within <extrato>
element).
Related
Thank you for taking the time to read.
My goal is to deserialize the response from an API request into 2 usable java objects.
I am sending an POST request to an endpoint to create a job in our schedule. The job is created successfully and the following XML is returned in the body:
<entry xmlns="http://purl.org/atom/ns#">
<id>0</id>
<title>Job has been created.</title>
<source>com.tidalsoft.framework.rpc.Result</source>
<tes:result xmlns:tes="http://www.auto-schedule.com/client">
<tes:message>Job has been created.</tes:message>
<tes:objectid>42320</tes:objectid>
<tes:id>0</tes:id>
<tes:operation>CREATE</tes:operation>
<tes:ok>true</tes:ok>
<tes:objectname>Job</tes:objectname>
</tes:result>
</entry>
When I attempt to only capture the elements id, title, and source the data is captured successfully. The problem is when I introduce the child object, which attempts to capture the data in the tes:result element.
Here's what the parent POJO looks like:
#XmlRootElement(name = "entry")
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
private String id;
private String title;
private String source;
ResponseDetails result;
public Response() {}
}
and here is the child object:
#XmlAccessorType(XmlAccessType.FIELD)
public class ResponseDetails {
#XmlElement(name = "tes:message")
String message;
#XmlElement(name = "tes:objectid")
String objectid;
#XmlElement(name = "tes:operation")
String operation;
#XmlElement(name = "tes:ok")
String ok;
#XmlElement(name = "tes:objectname")
String objectname;
}
Finally, here is the package-info.java file I am using:
#XmlSchema(
namespace = "http://purl.org/atom/ns#",
elementFormDefault = XmlNsForm.QUALIFIED)
package com.netspend.raven.tidal.request.response;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Any ideas are greatly appreciated. Thanks.
The problem is: Your Java code doesn't correctly specify the namespaces
corresponding to the inner XML element
<tes:result xmlns:tes="http://www.auto-schedule.com/client">
<tes:message>Job has been created.</tes:message>
<tes:objectid>42320</tes:objectid>
<tes:id>0</tes:id>
<tes:operation>CREATE</tes:operation>
<tes:ok>true</tes:ok>
<tes:objectname>Job</tes:objectname>
</tes:result>
The <tes:result> XML element has the namespace "http://www.auto-schedule.com/client".
The namespace prefix tes: itself is irrelevant for Java.
(XML namespace prefixes were invented only for better readability of the XML code.)
Therefore in your Response class, instead of just writing
ResponseDetails result;
you need to write
#XmlElement(namespace = "http://www.auto-schedule.com/client")
ResponseDetails result;
See also the javadoc of XmlElement.namespace.
Also all the XML sub-elements within the <tes:result> are specified
with this namespace "http://www.auto-schedule.com/client".
Therefore, also inside your ResponseDetails you have to correct
the namespace stuff. For example, instead of
#XmlElement(name = "tes:message")
String message;
you need to write
#XmlElement(name = "message", namespace = "http://www.auto-schedule.com/client")
String message;
You may also omit the name = "message" and simply write
#XmlElement(namespace = "http://www.auto-schedule.com/client")
String message;
because JAXB picks up this name from your Java property name message.
And similar for all the other properties in this class.
I'm trying to parse existing XML files for a java application and some of the elements have mixed content occasionally as demonstrated below:
XML_STRING
<root>
<name>Michael</name>
<question>Text here</question>
</root>
XML_STRING_2
<root>
<name>Michael</name>
<question>Text here<measure>More Text</measure></question>
</root>
I Made the below classes to unmarshall this data.
Root Class
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root implements Serializable
{
private String name;
private Question question;
}
Question Class
#XmlAccessorType(XmlAccessType.NONE)
public class Question implements Serializable
{
#XmlValue
private String questionText;
private String measure;
}
I can't seem to get both the Text Here and More Text to be stored inside the Question class.
JAXBContext.newInstance(Root.class)
.createUnmarshaller()
.unmarshal(new ByteArrayInputStream(XML_STRING_2.getBytes("UTF-8")));
I'm printing the result of the above code snippet (with Lombok's #ToString() annotation added to Root and Question) for both XML_STRING and XML_STRING_2.
XML_STRING: Root(name=Michael, question=Question(questionText=Text here, measure=null))
XML_STRING_2:Root(name=Michael, question=Question(questionText=, measure=null))
I was able to get something I could work with by using #XmlMixed along with #XmlElementRefs inside Question and creating a Measure class.
#XmlAccessorType(XmlAccessType.NONE)
public class Question implements Serializable
{
#XmlMixed
#XmlElementRefs({
#XmlElementRef(name = "measure", type=Measure.class)
})
private List<?> content;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="measure") // If this is removed I get the error: "Invalid #XmlElementRef : Type `Measure` or any of its subclasses are not known to this context."
public class Measure
{
#XmlValue
private String value;
}
I'm now getting the below output, which i can use via instanceof checking the items inside content
Root(name=Michael, question=Question(content=[Text here]))
Root(name=Michael, question=Question(content=[Text here, Measure(value=More Text)]))
The Root file remained unchanged.
I need to unmarshall a xml file which can return tag in following two ways.
<return_msg>Invalid Bank Code.</return_msg>
Second one
<return_msg>
<status_desc>Ok</status_desc>
<status_code>0</status_code>
</return_msg>
How can I create JAXB model class for this tag
Haven't tried, but you should be able to use this :
#XmlRootElement(name="return_msg")
#XmlAccessorType(XmlAccessType.FIELD)
public class ReturnMsg{
#XmlElement
private String status_desc;
#XmlElement
private String status_code;
#XmlMixed
private List<String> mixedContent;
//Getters and Setters
}
The mixed content should contains your "Invalid Bank Code." message if it's there.
I'm currently attempting to unmarshal some existing XML into a few classes I have created by hand. Problem is, I always get an error that tells me, JaxB expects a weather element but finds a weather element. (?)
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.aws.com/aws", local:"weather"). Expected elements are <{}api>,<{}location>,<{}weather>
I tried with and without "aws:" in the elements' name.
Here's my weather class:
#XmlRootElement(name = "aws:weather")
public class WeatherBugWeather
{
private WeatherBugApi api;
private List<WeatherBugLocation> locations;
private String uri;
#XmlElement(name="aws:api")
public WeatherBugApi getApi()
{
return this.api;
}
#XmlElementWrapper(name = "aws:locations")
#XmlElement(name = "aws:location")
public List<WeatherBugLocation> getLocations()
{
return this.locations;
}
public void setApi(WeatherBugApi api)
{
this.api = api;
}
public void setLocations(List<WeatherBugLocation> locations)
{
this.locations = locations;
}
#XmlAttribute(name="xmlns:aws")
public String getUri()
{
return this.uri;
}
public void setUri(String uri)
{
this.uri = uri;
}
}
And that's the XML I try to parse:
<?xml version="1.0" encoding="utf-8"?>
<aws:weather xmlns:aws="http://www.aws.com/aws">
<aws:api version="2.0" />
<aws:locations>
<aws:location cityname="Jena" statename="" countryname="Germany" zipcode="" citycode="59047" citytype="1" />
</aws:locations>
</aws:weather>
I'm not quite sure what I'm doing wrong. Any hints? I suspect the problem to be the xmlns definition, but I have no idea what to do about it. (You can see that by looking at the uri-property. That was one unsuccessful idea. ^^) And yes, I did try to set the namespace but that rather set's the namespace's uri instead of it's ... name.
I would recommend adding a package-info class in with your domain model with the #XmlSchema annotation to specify the namespace qualification:
package-info
#XmlSchema(
namespace = "http://www.aws.com/aws",
elementFormDefault = XmlNsForm.QUALIFIED)
package com.example.foo;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Note
Your XmlRootElement and #XmlElement annotation should not contain the namespace prefix. You should have #XmlRootElement(name = "weather") instead of #XmlRootElement(name = "aws:weather")
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
you need namespaces in your code. namespace prefixes are meaningless, you need the actual namespace (i.e. "http://www.aws.com/aws").
#XmlRootElement(name = "weather", namespace="http://www.aws.com/aws")
First. Sorry for bad english.
I want to make some "common" transformation of Map to XML according to given XSD in that way:
key of the Map will be equal to tag name in XML
tag names in XML will not be duplicated in different nodes (levels)
value in Map can contain for example List of Map that represent repeatable tags in the node
created xml have to accord an xsd.
etc.
So I am looking for a competent way to realize that.
Is there anybody who worked with similar tasks and can help me?
Any advise will appreciated. Thanks in advance!
P.S. Example.
Map:
"fname" : "Asdf"
"lname" : "Fdsa"
"cars" : "car" {"car1", "car2", "car3"}
XML:
<fname>Asdf</fname>
<lname>Fdsa</lname>
<cars>
<car>car1</car>
<car>car2</car>
<car>car3</car>
</cars>
First, you need one single root element. This is the requirement of XML syntax.
Now you can use JAXB. Define you class Data:
#XmlType
public class Data {
private String fname;
private String lname;
private Collection<String> cars;
// getters
public String getFname() {
return fname;
}
public String getLname() {
return lname;
}
#XmlElementWrapper(name = "cars")
#XmlElement(name = "car")
public String getCars() {
return cars;
}
// setters.....
}
Now your can create instance of this class instance, call all setters to fill the data and then call:
JAXBContext ctx = JAXBContext.newInstance("com.yourpackage");
Marshaller m = ctx.createMarshaller();
m.marshal(data, System.out);
And you will see your data serialized as XML on STDOUT.
To parse XML back say:
JAXBContext ctx = JAXBContext.newInstance("com.panpwr.api.model.deployment");
Unmarshaller unmarshaller = ctx.createUnmarshaller();
Data data = (Data)unmarshaller.unmarshal(in); // in is the input stream for XML
// now your instance of data is populated from XML