Namespace with no prefix in JAXB - java

I am trying to create a Sitemap index file with JAXB. Following the requirements for creating the sitemap, I have to add the namespace attribute in the root element:
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
I would like to have a simple way to sort this out. Since this seems to be a standard procedure I would like to not do a complex workaround or add more dependencies to my project in order to solve this issue
The current output is the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:sitemapindex xmlns:ns2="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://www.example.com/sitemap-1.xml</loc>
<lastmod>2017-05-01T15:41:17.561+01:00</lastmod>
</sitemap>
</ns2:sitemapindex>
My SitemapIndex model is the following:
#XmlRootElement(name = "sitemapindex", namespace="http://www.sitemaps.org/schemas/sitemap/0.9")
#XmlAccessorType(XmlAccessType.FIELD)
public class SitemapIndex {
#XmlElement(name = "sitemap")
private List<Sitemap> sitemaps;
public void setSitemaps(List<Sitemap> sitemaps) {
this.sitemaps = sitemaps;
}
public List<Sitemap> getSitemaps() {
return sitemaps;
}
}
I have also tried to add the namespace field manually and it works for generating the file but I an exception is thrown when I try to read the file.
#XmlAttribute(name="xmlns")
private final String namespace ="http://www.sitemaps.org/schemas/sitemap/0.9";

You can use #XmlSchmea [1] package level annotation in order to set prefix. In your case, we just set empty prefix.
Simply create package-info.java file in your package e.g. com.stackoverflow.jaxb, with similar content.
package-info.java
#XmlSchema(namespace = "http://www.sitemaps.org/schemas/sitemap/0.9",
xmlns = {#XmlNs(prefix = "",
namespaceURI = "http://www.sitemaps.org/schemas/sitemap/0.9")},
elementFormDefault = XmlNsForm.QUALIFIED)
package com.stackoverflow.jaxb;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Note, that you can remove namespace attribute from #XmlRootElement annotation.
[1] https://jaxb.java.net/nonav/2.2.4/docs/api/javax/xml/bind/annotation/XmlSchema.html

Related

How to set default namespace with JAXB (JDK 7)

I've got problem with setting default namespace with JAXB. I have followed tips from here but problem still exist. Here is how looks like my package-info:
#XmlSchema(
namespace = "my/xml/namespace",
xmlns = {
#XmlNs(namespaceURI="my/xml/namespace",prefix=""),
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package my.xml.namespace;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.XMLConstants;;
But still created xml looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:resp xmlns:ns2="my/xml/namespace">
....
</ns2:resp>
I would like to get rid of these prefix but run out of ideas. Anyone maybe know why?
UPDATE
I habe followed advice and implement NamespacePrefixMapper and:
It's crucial to be com.sun.xml.bind.marshaller.NamespacePrefixMapper. I've use another one and get wierd exceptions.
It does not work too - the same issue persist. Here is my mapper:
NamespacePrefixMapper mapper = new NamespacePrefixMapper(){
#Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix)
{
if("amc/xml/pay03_entryresponse".equals(namespaceUri)) {
return "";
}else return suggestion;
}
};
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper);
You have to use a Namespace mapper.
There are some examples on the web:
http://hwellmann.blogspot.co.at/2011/03/jaxb-marshalling-with-custom-namespace.html
http://java.dzone.com/articles/jaxb-and-namespace-prefixes

How to map a XML ignoring namespace using JAXB?

I'm receiving a XML from a web service with the following format:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<string xmlns="http://someurl.com">somethingheresomethinghere</string>
And I'm trying to unmarshall this to a POJO that looks like this:
#XmlRootElement(name="string")
public class StringValue {
#XmlValue
private String value;
public StringValue () {
}
}
And my unmarshalling code is this:
public T xmlToObject(Class<T> contextPath, Reader reader) throws Exception {
JAXBContext context = JAXBContext.newInstance(contextPath);
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setEventHandler(new XMLValidationEventHandler());
T objectToConvert = (T) unmarshaller.unmarshal(reader);
return objectToConvert;
}
But I'm getting the following error:
unexpected element (uri:"http://someurl.com", local:"string"). Expected
elements are <{}string>
If the namespace in the XML were to be omitted from it, then it will work, but instead of altering the XML I want to know how can I make it so the namespace part doesn't cause me any trouble when marshalling or unmarshalling with JAXB.
How can I achieve this behaviour?
You can map the namespace using the package level #XmlSchema annotation.
#XmlSchema(
namespace = "http://someurl.com",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.*;
For More Information
I have written more about JAXB and namespace qualification on my blog:
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

MOXy Dynamix JAXB context unmarshalls to wrong property names

I am currently trying to unmarshall the following XML file using the DynamicJaxbContext from MOXy:
<?xml version="1.0" encoding="UTF-8"?>
<request xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://somehost.com/schema_schedule_request.xsd">
<header>
<originator>MySatelliteCompany</originator>
<recipient>Recipient</ recipient>
<schedule_valid_from>2008-12-17T00:00:00Z</schedule_valid_from>
<schedule_valid_to>2008-12-18T00:00:07Z</schedule_valid_to>
<request_reference>HGT4285T3</request_reference>
<generation_time>2008-12-16T08:24:00Z</generation_time>
</header>
<body>
<schedule_request>
<start_time>2008-12-17T09:30:47Z</start_time>
<end_time>2008-12-17T09:33:47Z</end_time>
<satellite_name>MySat</satellite_name>
</schedule_request>
</body>
</request>
It works but the dynamically created Java classes' properties do not correspond to the fields given in the XML. For example: <satellite_name> is unmarshalled to "satelliteName". This makes writing a custom binding file for my backend API quite difficult, because I would have to first either unmarshall all XML files I will get as Input and manually write down the corresponding property names or write another helper app which does this for me.
Is there any way to change this MOXy behavior so it unmarshalls the field names correctly as they are in the XML?
ADDITION:
So I found why this is in the MOXy Documentation:
XML names found in the metadata (complex type names, element names,
attribute names) will be translated to Java identifiers according to
the algorithms described in "Appendix D: Binding XML Names to Java
Identifiers" of the Java Architecture for XML Binding (JAXB) 2.2
Specification (http://jcp.org/en/jsr/detail?id=222). - See more at:
http://www.eclipse.org/eclipselink/documentation/2.4/moxy/dynamic_jaxb001.htm#BABCDJDF
but my principle question still stands: is there any way to shut this off or modify this behavior?
Your ADDITION is correct, MOXy isn't unmarshalling wrong property names, it just unmarshals to property names that correspond to what the mapped property/field names would be in the generated classes.
What the Solution Should Be
binding.xml
The default XML Schema to Java naming rules in JAXB is to remove the _. You can supply a binding file to have this behaviour be different.
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings underscoreBinding="asCharInWord"/>
</jaxb:bindings>
Demo
Using MOXy's Dynamic JAXB, below is an example of how you can leverage the bindings file.
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
StreamSource schemaSource = new StreamSource("src/forum20146935/schema.xsd");
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(DynamicJAXBContextFactory.EXTERNAL_BINDINGS_KEY, new StreamSource("src/forum20146935/binding.xml"));
JAXBContext jc = DynamicJAXBContextFactory.createContextFromXSD(schemaSource, null, Demo.class.getClassLoader(), properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum20146935/input.xml");
DynamicEntity root = (DynamicEntity) unmarshaller.unmarshal(xml);
System.out.println(root.get("foo_bar"));
}
}
Why Didn't it Work?
As I mentioned earlier MOXy will base the dynamic property name based on the corresponding mapped field/property generated by XJC. This happens to look something like where the property name has the _ but the corresponding mapped field does not.
#XmlElement(name = "foo_bar", required = true)
protected String fooBar;
public String getFoo_Bar() {
return fooBar;
}
public void setFoo_Bar(String value) {
this.fooBar = value;
}
What you Could Do Instead
Use the transformed key name.
You could use the getValueByXPath functionality on the MOXy JAXBContext to interact with the objects in a more XML like way.
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.jaxb.JAXBHelper;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
StreamSource schemaSource = new StreamSource("src/forum20146935/schema.xsd");
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(DynamicJAXBContextFactory.EXTERNAL_BINDINGS_KEY, new StreamSource("src/forum20146935/binding.xml"));
JAXBContext jc = DynamicJAXBContextFactory.createContextFromXSD(schemaSource, null, Demo.class.getClassLoader(), properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum20146935/input.xml");
DynamicEntity root = (DynamicEntity) unmarshaller.unmarshal(xml);
String fooBar = JAXBHelper.getJAXBContext(jc).getValueByXPath(root, "foo_bar/text()", null, String.class);
System.out.println(fooBar);
}
}

Null values while un-marshalling XML with namspaces using JAXB

I have an issue while un-marshalling simple XML (a subset of CSDL) using JAXB.
Someone already tried to assist me in the past (here), however it is partially worked and I don't know what to do...
Please consider the following XML:
<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
<edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="3.0">
<Schema xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" xmlns:sap="http://www.sap.com/Protocols/SAPData" xmlns="http://schemas.microsoft.com/ado/2009/11/edm" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" Namespace="myNS">
</Schema>
</edmx:DataServices>
</edmx:Edmx>
As I was told, I have a package-info.java file that looks like (in the same package):
#XmlSchema(
namespace="http://schemas.microsoft.com/ado/2007/06/edmx",
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(prefix="edmx", namespaceURI="http://schemas.microsoft.com/ado/2007/06/edmx"),
#XmlNs(prefix="", namespaceURI="http://schemas.microsoft.com/ado/2009/11/edm"),
#XmlNs(prefix="m", namespaceURI="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata")
}
)
#XmlAccessorType(XmlAccessType.FIELD)
package com.sap.ndb.studio.rdl.csdlparser.jaxb.objects;
import javax.xml.bind.annotation.*;
In addition, I have the following data structure:
Edmx.java
package com.sap.ndb.studio.rdl.csdlparser.jaxb.objects;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Edmx")
public class Edmx {
#XmlElement(name = "DataServices")
private DataService dataService;
public DataService getDataService() {
return dataService;
}
}
DataService.java
package com.sap.ndb.studio.rdl.csdlparser.jaxb.objects;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class DataService {
#XmlElement(name = "Schema")
private Schema schema;
#XmlAttribute(name = "DataServiceVersion")
private double version;
public Schema getSchema() {
return schema;
}
}
Schema.java
package com.sap.ndb.studio.rdl.csdlparser.jaxb.objects;
#XmlRootElement
public class Schema {
....
}
Notice: in Schema.java I have some implementation which does not related to the XML so I have took it off (internal logic).
After un-marshalling the XML using the JAXB, The returned Edmx object contains null values both in 'schema' and 'version' members, although I have mentioned all xmlns parameters in my package-info.java.
Anyone? :(
UPDATE
In my answer to one of your previous questions I provider a mapping for the model from this question.
Error while trying to unmarshal EDMX with JAXB
I have updated this answer to address the following comment that you made:
Why should I declare
'namespace=schemas.microsoft.com/ado/2009/11/edm'; in my #XmlElement?
sorry for being annoying (this is my first experience with JAXB) but I
just gonna have a long XML with many #XmlElement nodes similar to the
'Schema' and I would like to declare the namespace for them only
once...
You can reduce the number of times you need to declare a namespace by organizing your model classes into different packages based on the namespace that they correspond to.
Package 1 for Namespace http://schemas.microsoft.com/ado/2007/06/edmx
package-info
For each package we will use the #XmlSchema annotation to specify the namespace qualification. In this example we only need to specify the namespace for this particular package.
#XmlSchema(
namespace="http://schemas.microsoft.com/ado/2007/06/edmx",
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(
prefix="edmx",
namespaceURI="http://schemas.microsoft.com/ado/2007/06/edmx"
),
}
)
#XmlAccessorType(XmlAccessType.FIELD)
package forum14875956.edmx;
import javax.xml.bind.annotation.*;
Edmx
The XML elements corresponding to the Edmx class will be namespace qualified according to what we defined on the #XmlSchema annotation for this package.
package forum14875956.edmx;
import javax.xml.bind.annotation.*;
#XmlRootElement(name = "Edmx")
public class Edmx {
#XmlElement(name = "DataServices")
private DataService dataService;
public DataService getDataService() {
return dataService;
}
}
DataService
The DataService class contains a reference to a class corresponding to a different XML namespace. If the Schema class was in the same package we could use the #XmlElement annotation to override the namespace qualification. Since Schema is in a different package we can use the #XmlElementRef annotation. This tells JAXB to derive the element information from the root element configured for that class.
package forum14875956.edmx;
import javax.xml.bind.annotation.*;
import forum14875956.schema.Schema;
public class DataService {
//#XmlElement(namespace="http://schemas.microsoft.com/ado/2009/11/edm", name="Schema")
#XmlElementRef
private Schema schema;
public Schema getSchema() {
return schema;
}
}
Package 2 for Namespace http://schemas.microsoft.com/ado/2009/11/edm
Again we will use the #XmlSchema to declare the namespace information for the second package.
package-info
#XmlSchema(
namespace="http://schemas.microsoft.com/ado/2009/11/edm",
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(
prefix="",
namespaceURI="http://schemas.microsoft.com/ado/2009/11/edm"
)
}
)
#XmlAccessorType(XmlAccessType.FIELD)
package forum14875956.schema;
import javax.xml.bind.annotation.*;
Schema
The elements in the Schema class will be namespace qualified based namespace information in the #XmlSchema annotation for its package.
package forum14875956.schema;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="Schema")
public class Schema {
}
ORIGINAL ANSWER
You need to include the namespace URI on the mapping for the schema property:
#XmlRootElement
public class DataService {
#XmlElement(name = "Schema" , namespace="http://schemas.microsoft.com/ado/2009/11/edm")
private Schema schema;
#XmlAttribute(name = "DataServiceVersion")
private double version;
public Schema getSchema() {
return schema;
}
}
Full Example
A little while I ago I answered one of your questions providing a complete mapping for this model:
Error while trying to unmarshal EDMX with JAXB

JaxB unmarshal custom xml

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")

Categories

Resources