Jaxb Unmarshalling java files from XML file with namespace - java

This is my XML
<?xml version="1.0"?>
<gpx version="1.1" creator="Example" xmlns="http://www.Example.com/1" xmlns:football="https://www.Example-football.com/xsd/football-ext">
<metadata>
<name>hello world</name>
<time>2018-04-26T12:32:52</time>
<extensions>
<sportsMeta>
<football:length>5080.3714454417996</football:length>
</sportsMeta>
</extensions>
</metadata>
</gpx>
Added this to package-info.java
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.Example.com/1", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED, attributeFormDefault = XmlNsForm.UNQUALIFIED, xmlns = {
#javax.xml.bind.annotation.XmlNs(prefix = "football", namespaceURI = "https://www.Example-football.com/xsd/football-ext"),
#javax.xml.bind.annotation.XmlNs(prefix = "", namespaceURI = "https://www.Example-football.com/xsd/football-ext/1/1") })
package com.example.football.share.gpx;
import javax.xml.bind.annotation.XmlNsForm;
I am able to read name, time. But not able to read guid, length.
Here is SportsMeta.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "sportsMeta", propOrder = {
"length"
})
public class SportsMeta {
protected BigDecimal length;
public BigDecimal getLength() {
return length;
}
public void setLength(BigDecimal length) {
this.length = length;
}
}
How can I read length info from the XML file.

In your XML input you have this part:
<sportsMeta>
<football:length>5080.3714454417996</football:length>
</sportsMeta>
where the namespace prefix football refers to the namespace URI
"https://www.Example-football.com/xsd/football-ext"
as defined by xmlns:football="https://www.Example-football.com/xsd/football-ext"
in your XML.
To map this XML to Java correctly you need to specify
that namespace URI for the length property of yourSportsMeta class.
You do this by annotating the length property
with #XmlElement and specifying the namespace within there.
(See also the API documentation of XmlElement.namespace.)
#XmlElement(namespace = "https://www.Example-football.com/xsd/football-ext")
protected BigDecimal length;

Related

JAXB How to remove default ns2 name space prefix in xml

While create request XML default "ns2" prefix added with name space declaration.
I am getting request XML as below format.
<ns2:ARTNCIS xmlns:ns2="http://namespace_uri">
<ARTNCIS>
<IDOCDATA>
...
</IDOCDATA>
</ARTNCIS>
</ns2:ARTNCIS>
Expected request XML should be like below,
<ARTNCIS xmlns="http://namespace_uri">
<ARTNCIS>
<IDOCDATA>
...
</IDOCDATA>
</ARTNCIS>
</ARTNCIS>
Below provided is package-info.java file.
#XmlSchema(
namespace = "http://namespace_uri",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.UNQUALIFIED,
xmlns={#XmlNs(prefix = "", namespaceURI = "http://namespace_uri")}
)
package com.vam.abc.motor;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;
While marshaling JAXB element added NamespacePrefixMapper to remove default "ns2" prefix. Find below code,
NamespacePrefixMapper mapper = new NamespacePrefixMapper() {
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
if ("http://namespace_uri".equals(namespaceUri) && !requirePrefix)
return "";
return suggestion;
}
};
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper);
marshaller.marshal(reqObject, document);
Below is my Root Element declaration.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "artncis" })
#XmlRootElement(name = "ARTNCIS")
public class ARTNCIS {
...
}

How can I determine the location of the XML namespace on Java (JAXB or another method)?

I'm using JAXB to marshall an Java object to XML.
Example;
com.abc.Defter.java object package-info.java:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.example.com",
xmlns = {#javax.xml.bind.annotation.XmlNs(namespaceURI = "http://www.example.com", prefix = "abc")})
package com.abc;
com.xyz.Xbrl.java object package-info.java:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.example2.com",
xmlns = {#javax.xml.bind.annotation.XmlNs(namespaceURI = "http://www.example2.com", prefix = "xyz")})
package com.xyz;
Marshalling result xml string;
<abc:defter xmlns:abc="http://www.example.com" xmlns:xyz="http://www.example2.com">
<xyz:xbrl>
<xyz:unit id="try">
<measure>iso4217:TRY</measure>
</xyz:unit>
</xyz:xbrl>
</abc:defter>
All namespaces are in the root directory, but I do not want it. I would like the following example;
<abc:defter xmlns:abc="http://www.example.com">
<xyz:xbrl xmlns:xyz="http://www.example2.com">
<xyz:unit id="try">
<measure>iso4217:TRY</measure>
</xyz:unit>
</xyz:xbrl>
</abc:defter>
How can I do it JAXB or another method using?

XML Value extraction using Java JAXB

I need a help in the following scenario. I have got a XML String response. In that XML response I need to extract three values. I could not achieve it. I have specified the XML response and the value I need. Also I created set of .java file using pojo one line tool.
My XML Response:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<control>
<status>success</status>
<senderid>XXXXX</senderid>
<controlid>ControlIdHere</controlid>
<uniqueid>false</uniqueid>
<dtdversion>3.0</dtdversion>
</control>
<operation>
<authentication>
<status>success</status>
<userid>XXXXX1</userid>
<companyid>XXXXX</companyid>
<sessiontimestamp>2014-08-22T07:12:37-07:00</sessiontimestamp>
</authentication>
<result>
<status>success</status>
<function>readByQuery</function>
<controlid>testControlId</controlid>
<data listtype="customer" count="100" totalcount="5142" numremaining="5042">
<customer>
<name>A</name>
<id>12</id>
</customer>
<customer>
<name>A</name>
<id>12</id>
</customer>
<customer>
<name>A</name>
<id>12</id>
</customer>
</data>
</result>
</operation>
In this XML response I would need the following values
Like count=100, totalcount=5142
My object class is like this
public class Data {
private String totalcount;
private Sodocument[] sodocument;
private String numremaining;
private String count;
private String listtype;
public String getTotalcount ()
{
return totalcount;
}
public void setTotalcount (String totalcount)
{
this.totalcount = totalcount;
}
public Sodocument[] getSodocument ()
{
return sodocument;
}
public void setSodocument (Sodocument[] sodocument)
{
this.sodocument = sodocument;
}
public String getNumremaining ()
{
return numremaining;
}
public void setNumremaining (String numremaining)
{
this.numremaining = numremaining;
}
public String getCount ()
{
return count;
}
}
XMLInputFactory xif = XMLInputFactory.newFactory();
Reader reader = new StringReader(response.toString());
XMLStreamReader xsr = xif.createXMLStreamReader(reader);
JAXBContext jc = JAXBContext.newInstance(Data.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Data jb = unmarshaller.unmarshal(xsr,Data.class).getValue();
System.out.println(jb.getCount());
This is my JAXB class. For the value getCount gives me null response. Can somebody help me on fixing this?
The generated class is too long for me to paste here but here is what you can try:
1) Use freeformatter.com/xsd-generator.html to generate an xsd from your xml. Copy and paste the generated xsd to a file.
2) Use xjc (comes with jdk installation) to generate the java class. It is a command line tool and you just have to run "xjc generated.xsd" and it will generate the annotated version of your class. The generated file will be for the entire xml response - so your class will really be Response.java, not Data.java and you then can drill into the Data element and it's attributes.
Add these annotations:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Data {
#XmlAttribute
private String totalcount;
#XmlElement
private Sodocument[] sodocument;
#XmlAttribute
private String numremaining;
#XmlAttribute
private String count;
#XmlAttribute
private String listtype;
...
But note that Sodocument[] sodocument (which should be a List!) does not match <customer>. Not sure what the model is - could it be another element as well (depending on listtype!)

JAXB: unmarshal from XML subtree?

My JAVA program uses an internal class hierarchy which resembles GPX 1.1, but is not identical. since rewriting it to conform 1:1 to GPX is a huge effort, I'd like to change it bit by bit, i.e. reading the <metadata> subtree into the Class MetadataType as generated with xjc from the XSD file
the remaining GPX file is parsed with DOM, until <metadata> shows up:
private void parseMetadata(MetadataType metadata, Element element) throws JAXBException {
try {
System.out.println(element.getNodeName()); // output: metadata
JAXBContext context = JAXBContext.newInstance(MetadataType.class);
javax.xml.bind.Unmarshaller u = context.createUnmarshaller();
JAXBElement<MetadataType> meta = u.unmarshal(element, MetadataType.class);
metadata = meta.getValue();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(metadata.getName()); // NULL
System.out.println(metadata.getAuthor().getName()); // NULL
}
throws
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"metadata"). Expected elements are <{http://www.topografix.com/GPX/1/1}gpx>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:647)
the class looks like this:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "metadataType", propOrder = {
"name",
"desc",
"author",
"copyright",
"link",
"time",
"keywords",
"bounds",
"extensions"
})
#XmlRootElement(name = "metadata")
public class MetadataType {
protected String name = "";
protected String desc = "";
protected PersonType author;
protected CopyrightType copyright = new CopyrightType();
protected List<LinkType> link = new ArrayList<LinkType>();
#XmlSchemaType(name = "Date")
protected Date time;
protected String keywords = "";
protected BoundsType bounds = new BoundsType();
protected ExtensionsType extensions = new ExtensionsType();
[...]
}
is it possible to unmarshal from an XML subtree; and if yes, what am I doing wrong?
UPDATE/1:
thanks to lexicore, I'm a step further: element definitely contains the metadata node, #XmlRootElement is set, unmarshaling now with unmarshal(element, MetadataType.class).
unmarshaling works, but the content of the objects is empty. I wonder if I run into some namespace troubles here?
the package com.topografix.gpx._1._1 contains a package-info.java, generated by xjc:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://www.topografix.com/GPX/1/1", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.topografix.gpx._1._1;
here's one of the test files:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx xmlns="http://www.topografix.com/GPX/1/1"
xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
xmlns:wptx1="http://www.garmin.com/xmlschemas/WaypointExtension/v1"
xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1"
creator="GPSMAP 62s" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1
http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas /GpxExtensions/v3
http://www8.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/WaypointExtension/v1
http://www8.garmin.com/xmlschemas/WaypointExtensionv1.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1
http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd">
<metadata>
<link href="http://www.garmin.com">
<text>Garmin International</text>
</link>
<time>2014-01-01T22:26:49Z</time>
</metadata>
[...]
UPDATE/2: the namespace/package name is right. If the namespace is set to (i.e.) "foobar", the following exception is thrown:
javax.xml.bind.JAXBException: Provider com.sun.xml.internal.bind.v2.ContextFactory could not be instantiated:
javax.xml.bind.JAXBException: "foobar" doesnt contain ObjectFactory.class or jaxb.index
when initialized as before, the exception is not thrown, meaning that the namespace is correct AND the ObjectFactory.class is found.
String contextPath = MetadataType.class.getPackage().getName();
JAXBContext context = JAXBContext.newInstance(contextPath);
So, the namespace is correct, but somehow the "link" to the MetadataType class is missing?
I guess you have a few problems here:
Your MetadataType does not have the #XmlRootElement. So JAXB does not know which element is supposed to match it.
You want to unmarshal partially, but you're unmarshalling (I guess) the whole document.
What you could try:
Try unmarshalling a specific class from the specific node using the unmarshal(node, class) method
From your stack trace, you try to unmarshal gpx:gpx element, not the metadata element. You have to go deeper
You have to overtake package-info.java as well (or provide namespaces in your MetadataType, otheriwse you're missing namespaces
See this answer about partial unmarshalling.

Marshalling and Unmarshalling changes xml using moxy

I am trying to create this kind(xsd inside) of documents. some examples are here. Because of constant values in root-element and some other constant elements i generated a template with eclipse:
<?xml version="1.0" encoding="UTF-8"?>
<invoice:response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:invoice="http://www.forum-datenaustausch.ch/invoice" xmlns="http://www.forum-datenaustausch.ch/invoice" xsi:schemaLocation="http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd" language="de">
<invoice:processing>
<invoice:transport from="" to="">
<invoice:via sequence_id="0" via=""/>
</invoice:transport>
</invoice:processing>
<invoice:payload response_timestamp="0">
<invoice:invoice request_date="2001-12-31T12:00:00" request_id="" request_timestamp="0"/>
</invoice:payload>
</invoice:response>
But simple unmarshalling and marshalling changes the content:
<?xml version="1.0" encoding="UTF-8"?>
<response xmlns="http://www.forum-datenaustausch.ch/invoice" xmlns:ns1="http://www.w3.org/2000/09/xmldsig#" xmlns:ns0="http://www.w3.org/2001/04/xmlenc#" language="de">
<processing>
<transport from="" to="">
<via via="" sequence_id="0"/>
</transport>
</processing>
<payload response_timestamp="0">
<invoice request_timestamp="0" request_date="2001-12-31T12:00:00.0" request_id=""/>
</payload>
</response>
for some reason the schema location attribute is gone. this could be added manually before marshalling. the 2nd problem is, all prefixes are gone.
i don't know who consumes the produced xml (do they unmarshal with handwritten code? with or without validation?). Because of this i want an output that is most similar to given examples and valid.
So is there either a way to leave existing elements and attributes untouched and to let moxy add namespace prefixes to each element?
The following should help. This question is also being handled on the EclipseLink forum:
http://www.eclipse.org/forums/index.php/t/487391/
for some reason the schema location attribute is gone.
You can specify the following property on the Marshaller to output a schema location:
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd");
2nd problem is, all prefixes are gone.
The namespace prefixes are gone, but the namespace qualification is the same (all elements have the same local name and namespace URI). In the first document the invoice prefix is assigned to the http://www.forum-datenaustausch.ch/invoice namespace, and in the second document that namespace is assigned as the default namespace
CONTROLLING NAMESPACE PREFIXES AT DESIGN TIME
You can provide MOXy hints at what namespace prefixes should be used by leveraging the #XmlSchema annotation (see: http://blog.bdoughan.com/2011/11/jaxb-and-namespace-prefixes.html).
package-info
#XmlSchema(
elementFormDefault=XmlNsForm.QUALIFIED,
namespace="http://www.forum-datenaustausch.ch/invoice",
xmlns={
#XmlNs(prefix="invoice", namespaceURI="http://www.forum-datenaustausch.ch/invoice"),
#XmlNs(prefix="ds", namespaceURI="http://www.w3.org/2000/09/xmldsig#"),
#XmlNs(prefix="xenc", namespaceURI="http://www.w3.org/2001/04/xmlenc#")
}
)
package forum16559889;
import javax.xml.bind.annotation.*;
Response
package forum16559889;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Response {
}
Demo
package forum16559889;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Response.class);
Response response = new Response();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd");
marshaller.marshal(response, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<invoice:response xsi:schemaLocation="http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:invoice="http://www.forum-datenaustausch.ch/invoice" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
CONTROLLING THE NAMESPACE PREFIXES AT RUNTIME
You cam leverage MOXy's NamespacePrefixMapper extension to control the namespace prefixes used at runtime.
package forum16559889;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.oxm.NamespacePrefixMapper;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Response.class);
Response response = new Response();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.forum-datenaustausch.ch/invoice generalInvoiceResponse_440.xsd");
marshaller.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, new NamespacePrefixMapper() {
#Override
public String getPreferredPrefix(String namespaceUri,
String suggestion, boolean requirePrefix) {
if("http://www.forum-datenaustausch.ch/invoice".equals(namespaceUri)) {
return "invoice";
} else if("http://www.w3.org/2000/09/xmldsig#".equals(namespaceUri)) {
return "ds";
} else if("http://www.w3.org/2001/04/xmlenc#".equals(namespaceUri)) {
return "xenc";
} else {
return null;
}
}
});
marshaller.marshal(response, System.out);
}
}

Categories