This is my first question on StackOverflow in general, so please bear with me.
I have an issue with marshalling XML that uses the default prefix for different namespaces. Each element that uses the default prefix should specify its namespace in its opening tag. An example what I'm trying to achieve would be something like this (simplified):
<parent xmlns="parentNamespace" xmlns:cd1="child1Namespace">
<cd1:child1/>
<child2 xmlns="child2Namespace">
...
</child2>
<child3 xmlns="child3Namespace">
...
</child3>
</parent>
I have tried setting namespaces prefixes in package-info.java of the object I'm trying to marshall using annotations like this:
#javax.xml.bind.annotation.XmlSchema(
namespace = "parentNamespace",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(prefix="",parentNamespace"),
#XmlNs(prefix="cd1", namespaceURI="child1Namespace"),
#XmlNs(prefix="", namespaceURI="child2Namespace"),
#XmlNs(prefix="", namespaceURI="child3Namespace")
}
)
But the end result is something like this:
<ns1:parent xmlns:ns1="parentNamespace" xmlns:cd1="child1Namespace" xmlns="child2Namespace xmlns:ns2="child3Namespace"<
<cd1:child1/>
<child2>
...
</child2>
<ns2:child3>
...
</ns2:child3>
</ns1:parent>
Which really is a valid XML, but unfortunately for reasons that are outside my control isn't good enough (doesn't pass validation). Also note that solution using Java 8 is highly preferable as I wouldn't want to mess with NamespacePrefixMapper if at all possible (if it even works).
So the question is: Is it possible to generate XML using JAXB that uses same prefix for multiple namespaces and how?
Related
I have the situation there is an web service implemented in old Visual Studio 2008, which accepts the SOAP requests with content having namespaces only in this form:
<Root xmlns="http://A">
<A>
<A1 />
</A>
<B xmlns="http://B">
<B1 />
</B>
</Root>
All other forms of the XML (unqualified, or qualified with namespace prefix) are causing problems even if the wsdl and referenced xsd structures are manipulated and modified in various ways and the service is recompiled in Visual Studio 2008, the author of the ASP.NET web service is not able to get any other form of XML working.
Is there any way how to achieve the generation of the classes for our Java client accessing this web service by using the external JAXB binding specification, used during the class generation, so the XML would be from the objects marshalled in the above described form?
Am I right, if I think, this could be achieved by the forcing the JAXB to generate the class(ses in multiple directories)
package-info.java
instead of the default form
#javax.xml.bind.annotation.XmlSchema(
namespace = "http://some/custom/namespace",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package some.custom.namespace;
in the following form?
#javax.xml.bind.annotation.XmlSchema(
namespace = "http://some/custom/namespace",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {#XmlNs(prefix = "", namespaceURI = "http://some/custom/namespace")})
package some.custom.namespace;
and if I am right, is there any way to do it? I am unfamiliar with writing the XJB bindings, so any pointer would be appreciated...
Or maybe, after the generation the source code of this class should be postprocessed by something like ant task, which would modify the initially generated JAXB form into the form I think it was the desired content of the class package-info.java?
Could this be somehow achieved by one universal jxb binding file for all usages without necessity to modify it for every namespace folder creating its own package?
I hope this could really work even with multiple different namespaces without prefixes, because the xmlns definitions are then used in JAXBContextImpl as a set of XmlNs types, so if there is an prefix or not hopefully should not matter... Am I right?
Is it possible to bind xml prefix→namespace mapping to a map using javax.xml.bind.* annotations?
Something like:
class FooPOJO {
...
#Namespacebindingannotation
Map<String,String> prefixToNamespaceMap;
...
}
And in the xml
<foo
xmlns="http://foo.com"
xmlns:bar="http://bar.com"
xmlns:baz="http://baz.com">
...
When unmarshaling the xml, prefixToNamespaceMap will map the 3 prefixes to their appropriate namespaces.
You want to dynamically extract the namespaces URIs and the prefixes from the XML? That's a genuinely bad idea.
XML namespaces are part of the contract between your application code and the XML it processes. They ought to be hard-coded into your application.
The reason is simple. These XMLs look different but are all the same document:
<foo:root xmlns:foo="http://main/ns" xmlns:bar="http://secondary/ns">
<foo:child bar:attr="1234">some data</foo:child>
</foo:root>
or
<bar:root xmlns:bar="http://main/ns" xmlns:foo="http://secondary/ns">
<bar:child foo:attr="1234">some data</bar:child>
</bar:root>
or
<root xmlns="http://main/ns" xmlns:baz="http://secondary/ns">
<child baz:attr="1234">some data</child>
</root>
So if you extract namespaces dynamically from them, your subsequent code will inevitably (and unnecessarily) break.
Use actual namespace URIs in your code and choose prefixes to your liking - prefixes are ephemeral, they don't have to match up with the XML files. XML is strongly typed data, treat it accordingly.
In other words, namespace prefixes are aliases, a convenience facility, they only exist in serialized data. They exist in XML, they don't exist in the DOM. They exist in your application's XPath expressions, they don't exist in the abstract tree the XPath expressions are parsed into. Those are two completely separate domains. If the same prefixes are used in both domains, that's entirely coincidental. Don't build application logic that transfers prefixes from one domain to the other, as this is bound to break.
I'm trying to create an xml element which i want to have as prefix the atom.
I know that i can't do this:
#XmlElement(prefix="atom")
And create
<XmlAttribute>
<atom:link ...>
</XmlAttribute>
Is there a possible way to do this or not?
Yes, you just need to define the namespace corresponding to this prefix:
#XmlElement(name="link", namespace="..")
this will just add the namespace corresponding to the atom prefix to your link element. If your question is about specifically getting atom as the prefix for this namespace, then please look at this question: Is it possible to customize the namespace prefix that JAXB uses when marshalling to a String?
I am trying to work out how to unmarshall and XML document to a Java document.
The top of the xml document looks like this
<xs:myData xmlns:xs="http://www.example.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com example.xsd ">
There is a schema file whose top section looks like this:
<schema targetNamespace="http://www.example.com"
elementFormDefault="qualified"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xs="http://www.example.com">
I would like to unmarshall the xml document using Spring/JaxB and eventually convert it to a JPA object. I am not sure how to go about so i looked for examples on google and came up with this http://thoughtforge.net/610/marshalling-xml-with-spring-ws-and-jaxb/
I understand most of it except how or where the schema is used.
I have seen other examples where the schema is explicitly specified, i.e.
SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema sysConfigSchema = schemaFac.newSchema(
new File("example.xsd"));
unmarshaller.setSchema(sysConfigSchema);
RootElement root = (RootElement)unmarshaller.unmarshal(
new File("example1.xml"));
How is the schema shown in the first link used to validate the xml document?
Are there any disadvantages to using Spring's jaxb2Marshaller as opposed to direct use of JAXB?
What is the effect of having the namespace next to the XmlElement annotation? (See the Person class)
I would appreciate any more examples showing Spring/REST with unmarshalling with schema validation.
Thanks
As far as I know JAXB does not parse xsi attribute to dereference XSD, load it and use for validation. Perhaps that was done to disable automatic validation, otherwise it would be problematic to switch it off :)
Spring Jaxb2Marshaller was obviously added to implement the same interface org.springframework.oxm.Marshaller (which is implemented also by CastorMarshaller, JibxMarshaller, ...). It is very powerful and allows you to tune JAXBContext in very flexible way (I can't imagine the scenario when provided API is not enough). From pattern point of new Jaxb2Marshaller is a builder, so it does not add anything to core JAXB functionality. But there are some evident advantages. For example, schema loading is very simple. In the article the Spring context refers the person.xsd (<property name="schema" value="classpath:schema/person.xsd"/>) which one need to put into resources explicitly. Then JAXB marshaller/unmarshaller will use this schema to validate XML when XML is generated/loaded.
#XmlElement(..., namepsace="xxx") will automatically generate this XML element with a specified namespace. It's rare case if somebody does not use namespaces. I would say writing XSD without namespaces is not normal, as you want to avoid the element name collision.
Using JAXB with RestTemplate is very simple. You need to be sure that JAXB runtime is in your classpath (JDK 6 already has it) and your bean is annotated with #XmlRootElement. Then just use Person person = restTemplate.getForObject(restServiceUrl, Person.class),
I am creating amazon feed, the feed xml should be like:
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
I am using jaxb to generate xml files from java classes, I used NamespacePrefixMapperImpl from jaxb samples to add namespaces to the xml. But currently it generates the root like:
<AmazonEnvelope xmlns:xsi:noNamespaceSchemaLocation="amzn-envelope.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
how I can remove the xmlns from amzn-envelope.xsd??
Here's the mapping I used in NamespacePrefixMapperImpl
if( "http://www.w3.org/2001/XMLSchema-instance".equals(namespaceUri) )
return "xsi";
if("amzn-envelope.xsd".equals(namespaceUri))
return "xsi:noNamespaceSchemaLocation";
I found a property at Marshaller that can add the amzn-envelope.xsd:
marshaller.setProperty("jaxb.noNamespaceSchemaLocation", "amzn-envelope.xsd");
and left the NamespacePrefixMapper to add the "http://www.w3.org/2001/XMLSchema-instance".
Hope this helps others.
If I understand your intent, your document has a default namespace, and you're trying to add the schemalLocation for that namespace.
NamespacePrefixMapper won't let you do this, it's useful only for picking a prefix for a namespace. There are no namespaces in this document, and so no useful way of using NamespacePrefixMapper. It can't be used for adding schemaLocation hints - those are treated specially by JAXB, and you're just confusing it.
Are you sure you need the noNamespaceSchemaLocation="amzn-envelope.xsd" at all? Have you tried sending it to the web service without it?