I'm new to using namespaces in xml so I am kind of confused and would like some clarification. I have a java service where I am receiving xml documents with many different namespaces and while i got it working, I feel like I must have done something wrong so I want to check. In my package-info.java I have my schema annotation such as:
#javax.xml.bind.annotation.XmlSchema(
xmlns={
#javax.xml.bind.annotation.XmHS(prefix="train", namespaceURI="http://mycompany/train"),
#javax.xml.bind.annotation.XmHS(prefix="passenger", namespaceURI="http://mycompany/passenger")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm=QUALIFIED
)
I have a Train.java annotated on the class level with:
#XmlRootElement(name="Train", namespace="http://mycompany/train")
and each field in the class annotated with:
#XmlElement(name="Color") for example
Train contains a List of Passenger(s) so there's a property
private Set<Passenger> passengers;
and this collection is annotated with:
#XmlElementWrapper(name="Passengers")
#XmlElements(#XmlElement(name="Passenger", namespace="http://mycompany/passenger"))
Then within Passenger.java the class itself is annotated with:
#XmlElement(name="Passenger", namespace="http://mycompany/passenger")
Finally for individual fields within Passenger.java, they are annotated like this:
#XmlElement(name="TicketNumber", namespace="http://mycompany/passenger")
So when I have an xml that looks like:
<train:Train>
<train:Color>Red</train:Color>
<train:Passengers>
<train:Passenger>
<passenger:TicketNumber>T101</passenger:TicketNumber>
</train:Passenger>
</train:Passengers>
</train:Train>
Now I unmarshal this xml I received and Train's Color property is set and Passenger's TicketNumber property is set. But I don't know why I need to add the namespace url on the XmlElement annotation on TicketNumber for that to work but I didn't need to do so for the Color property on Train. If I remove the namespace attribute from the XmlElement annotation on TicketNumber, the value from the xml wont get mapped to the object unless I also remove the namespace prefix from the xml request. I feel like since I've got the namespace attribute defined on the XmlRootElement for Passenger, I shouldn't need to do that for every single field in the class as well just like I didn't have to for Train so I am assuming I must have setup something wrong. Can someone point me in the right direction? Thanks!
Below is an explanation of how namespaces work in JAXB (JSR-222) based on your model.
JAVA MODEL
package-info
Below is a modified version of your #XmlSchema annotation. It contains some key information:
namespace - The default namespace that will be used to qualify global elements (those corresponding to #XmlRootElement and #XmlElementDecl annotations (and local elements based on the elementFormDefault value) that don't have another namespace specified.
elementFormDefault by default only global elements are namespace qualified but by setting the value to be XmlNsForm.QUALIFIED all elements without an explicit namespace specified will be qualified with the namespace value.
xmlns is the preferred set of prefixes that a JAXB impl should use for those namespaces (although they may use other prefixes).
#XmlSchema(
namespace="http://mycompany/train",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(prefix="train", namespaceURI="http://mycompany/train"),
#XmlNs(prefix="passenger", namespaceURI="http://mycompany/passenger")
}
)
package forum15772478;
import javax.xml.bind.annotation.*;
Train
Since all the elements corresponding to the Train class correspond to the namespace specified on the #XmlSchema annotation, we don't need to specify any namespace info.
Global Elements - The #XmlRootElement annotation corresponds to a global element.
Local Elements - The #XmlElementWrapper and #XmlElement annotations correspond to local elements.
package forum15772478;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement(name="Train")
public class Train {
private List<Passenger> passengers;
#XmlElementWrapper(name="Passengers")
#XmlElement(name="Passenger")
public List<Passenger> getPassengers() {
return passengers;
}
public void setPassengers(List<Passenger> passengers) {
this.passengers = passengers;
}
}
Passenger
If all the elements corresponding to properties on the Passenger class will be in the http://mycompany/passenger namespace, then you can use the #XmlType annotation to override the namespace from the #XmlSchema annotation.
package forum15772478;
import javax.xml.bind.annotation.*;
#XmlType(namespace="http://mycompany/passenger")
public class Passenger {
private String ticketNumber;
#XmlElement(name="TicketNumber")
public String getTicketNumber() {
return ticketNumber;
}
public void setTicketNumber(String ticketNumber) {
this.ticketNumber = ticketNumber;
}
}
Alternatively you can override the namespace at the property level.
package forum15772478;
import javax.xml.bind.annotation.*;
public class Passenger {
private String ticketNumber;
#XmlElement(
namespace="http://mycompany/passenger",
name="TicketNumber")
public String getTicketNumber() {
return ticketNumber;
}
public void setTicketNumber(String ticketNumber) {
this.ticketNumber = ticketNumber;
}
}
DEMO CODE
The following demo code can be run to prove that everything works:
Demo
package forum15772478;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Train.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum15772478/input.xml");
Train train = (Train) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(train, System.out);
}
}
input.xml/Output
In the XML below I have added the necessary namespace declarations that were missing from the XML document in your question.
<train:Train
xmlns:train="http://mycompany/train"
xmlns:passenger="http://mycompany/passenger">
<train:Color>Red</train:Color>
<train:Passengers>
<train:Passenger>
<passenger:TicketNumber>T101</passenger:TicketNumber>
</train:Passenger>
</train:Passengers>
</train:Train>
FOR MORE INFORMATION
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Related
I want to know how to type only one time namespace in jabx, because in every fields i need to put the namespace.
The code below show it.
#XmlRootElement(name = "nfeProc", namespace = "http://www.portalfiscal.inf.br/nfe")
#XmlAccessorType(XmlAccessType.FIELD)
class NFeProc {
#XmlElement(name = "NFe", namespace = "http://www.portalfiscal.inf.br/nfe")
private NFe nfe;
#XmlAttribute(name = "versao")
private String versao;
public NFe getNfe() {
return nfe;
}
public void setNfe(NFe nfe) {
this.nfe = nfe;
}
public String getVersao() {
return versao;
}
public void setVersao(String versao) {
this.versao = versao;
}
}
I just wanna to put one time.
Thanks
You can set it at the package level using the #XmlSchema annotation. By setting element form default to be qualified, all elements without a namespace specified via an annotation will belong to the given namespace.
package-info.java
#XmlSchema(
namespace = "http://www.portalfiscal.inf.br/nfe",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
I would like to build some kind of object generation engine for my domain objects.
For example, lets assume, I'm working with graphs. The models are represented by xml and I should be able to load them and build a java representation at runtime.
Lets say, graph has vertices and edges
So it will look like this:
<graph>
<vertex id="n1" color="red", thickness="2">
<vertex id="n2">
<edge end1="${n1}", end2="${n2}"/>
</graph>
For this I would like to get the objects that can be described by the following java classes:
class Graph {
List<Vertex> vertexList
List<Edge> edgeList
}
class Vertex {
String id
... various properties ...
}
class Edge {
Vertex end1
Vertex end2
}
Another requirement is to be able to define vertices in loop like this:
<graph>
...
<for var = i, min = 1, max = 10, step = 1>
<vertex id=$i.../>
</for>
...
</graph>
I thought about using Apache Jelly but it seems to be a 'dead' project, JaxB doesn't allow such a level of dynamic behavior AFAIK...
My question is - what framework can you recommend for implementing such a task?
If there is something that works like Apache Jelly but still maintained, it could be great also :)
Thanks a lot in advance
JAXB (JSR-222) implementations can easily handle references within a document using a combination of #XmlID and #XmlIDREF. I will demonstrate below with an example.
JAVA MODEL
Graph
package forum13404583;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
class Graph {
#XmlElement(name = "vertex")
List<Vertex> vertexList;
#XmlElement(name = "edge")
List<Edge> edgeList;
}
Vertex
In the Vertex class you need to use the #XmlID annotation to indicate that the id field is the id.
package forum13404583;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
class Vertex {
#XmlAttribute
#XmlID
String id;
#XmlAttribute
String color;
#XmlAttribute
Integer thickness;
}
Edge
In the Edge class the #XmlIDREF annotation is used to indicate that the XML value contains a foreign key that references the real value.
package forum13404583;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
class Edge {
#XmlAttribute
#XmlIDREF
Vertex end1;
#XmlAttribute
#XmlIDREF
Vertex end2;
}
DEMO CODE
package forum13404583;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Graph.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum13404583/input.xml");
Graph graph = (Graph) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(graph, System.out);
}
}
INPUT (input.xml)/OUTPUT
Below is the input to and output from running the demo code.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<graph>
<vertex id="n1" color="red" thickness="2"/>
<vertex id="n2"/>
<edge end1="n1" end2="n2"/>
</graph>
For More Information
http://blog.bdoughan.com/2010/10/jaxb-and-shared-references-xmlid-and.html
I have xml like this
<abc:city>
<def:cityname />
<xyz:postalTown>
Sacramento
</xyz:postalTown>
</abc:city>
<abc:city>
<def:cityname />
<pqr:postalTown>
Sacramento
</pqr:postalTown>
</abc:city>
Can xstream handle these namespaces like 'abc' in <abc:city>
Also namespace for <pqr:postalTown> can be changed as I am unaware of the response coming. How can this be handled dynamically through xstream.
If this is impossible in xstream; can it be handled using jaxb?
EDIT:
My class will be City:
Class City{
String cityName;
String postalTown;
}
How can I map above xml to City class as tags contain prefixes?
UPDATE
If the prefixes do not correspond to namespace declarations, then you could use the approach from the answer I linked below from a related question:
https://stackoverflow.com/a/11970622/383861
NOTE ABOUT NAMESPACE QUALIFICATION
The prefixes used don't come into play in terms of object-to-XML mapping. As long as the the xyz and pqr prefixes correspond to the same namespace you will be fine with any object-to-XML solution that supports namespaces.
Even though the following documents contain different prefixes they have the same namespace qualification.
Document #1
<abc:city xmlns:abc="ABC" xmlns:def="DEF" xmlns:ghi="XYZ">
<def:cityName/>
<ghi:postalTown>
Sacramento
</ghi:postalTown>
</abc:city>
Document #2
<jkl:city xmlns:jkl="ABC" xmlns:mno="DEF" xmlns:pqr="XYZ">
<mno:cityName/>
<pqr:postalTown>
Sacramento
</pqr:postalTown>
</jkl:city>
JAXB AND NAMESPACES
Below is how you would map your City class to the XML documents above. Note how it is the namespace URI and not the prefix that is specified on the #XmlRootElement and #XmlElement annotations.
package forum11932402;
import javax.xml.bind.annotation.*;
#XmlRootElement(namespace="ABC")
public class City {
#XmlElement(namespace="DEF")
String cityName;
#XmlElement(namespace="XYZ")
String postalTown;
}
Below is some information on JAXB and namespaces:
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
http://blog.bdoughan.com/2011/11/jaxb-and-namespace-prefixes.html
DEMO CODE
The following demo code can be used to unmarshal either of the XML documents I have posted earlier in this answer.
package forum11932402;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(City.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum11932402/input.xml");
City city = (City) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(city, System.out);
}
}
Below is the output from running the demo code. The JAXB implementation has assigned new prefixes. The cityName element is still namespace qualified, it just corresponds to the default namespace which was declared as xmls="DEF".
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:city xmlns="DEF" xmlns:ns2="XYZ" xmlns:ns3="ABC">
<cityName></cityName>
<ns2:postalTown>
Sacramento
</ns2:postalTown>
</ns3:city>
I've studied Blaise Doughan's answer to a question on this subject but have a further question.
XmlJavaTypeAdapters lets you list a bunch of XmlJavaTypeAdapter annotations, each of which governs how a non-bindable type is mapped to a bindable type by JAXB.
You can use this annotation at the package level. When you do so, every XmlJavaTypeAdapter annotation needs its type() attribute fully specified.
There does not appear to be a requirement that the package that is being annotated have anything to do with the package of the non-bindable types being adapted. That is convenient and nice.
That, however, leads me to my next question: if there is no relationship between the annotated package and the package of the type being adapted, how does JAXB discover package-level XmlJavaTypeAdapters annotations? How, in other words, does it know which packages to consult for potential XmlJavaTypeAdapters annotations? May I make a random package in, say, a .jar file in my .ear file's lib directory that contains a single, ginormous package-info class that is annotated with all the adapters for all of my non-bindable types?
When the JAXB runtime loads a JAXB-annotated class, it looks for a package-info.java in the same package as that class, and checks that to look for package-level annotations. So while XmlJavaTypeAdapters doesn't have to reside in the same package as the "non-bindable" types, it does have to reside in the same package as the "bindable" types.
For example, say I have a JAXB-annotated class A, in package X, which has a property of type B in package Y. In order to bind the B property, let's say a type adapter is required. That adapter can be specified in A itself, or it can be specified in the package-info.java in package X. Package Y is pretty much arbitrary, and is of no interest to the JAXB runtime.
I hope that makes sense.
There does not appear to be a requirement that the package that is
being annotated have anything to do with the package of the
non-bindable types being adapted. That is convenient and nice.
This is correct. When #XmlJavaTypeAdapter is used at the package level it means apply this adapter to all properties of the specified type for classes that reside in this package. I'll demonstrate below with an example.
forum8735737.bar.package-info
For this package we will specify an XmlAdapter that will be applied to all fields/properties of type String within this package.
#XmlJavaTypeAdapters({
#XmlJavaTypeAdapter(value=StringAdapter.class, type=String.class)
})
package forum8735737.bar;
import javax.xml.bind.annotation.adapters.*;
forum8735737.bar.StringAdapter
Our XmlAdapter will simply convert all instances of String to upper case when marshalling:
package forum8735737.bar;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringAdapter extends XmlAdapter<String, String> {
#Override
public String unmarshal(String v) throws Exception {
return v;
}
#Override
public String marshal(String v) throws Exception {
if(null == v) {
return v;
}
return v.toUpperCase();
}
}
forum8735737.bar.Bar
Bar represents a POJO in this package with a property of type String:
package forum8735737.bar;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Bar {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
forum8735737.foo.Foo
Foo represents a domain object with a property of type String that exists in a different package. The XmlAdapter we registered for the forum8735737.bar package will not apply to this class:
package forum8735737.foo;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Foo {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Demo
The following code will create instances of both Foo and Bar and marshal them to XML:
package forum8735737;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import forum8735737.bar.Bar;
import forum8735737.foo.Foo;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class, Bar.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Foo foo = new Foo();
foo.setName("Foo");
marshaller.marshal(foo, System.out);
Bar bar = new Bar();
bar.setName("Bar");
marshaller.marshal(bar, System.out);
}
}
Output
Notice how the value of the name element within bar has been converted to upper case:
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<name>Foo</name>
</foo>
<?xml version="1.0" encoding="UTF-8"?>
<bar>
<name>BAR</name>
</bar>
I am trying to generate xml using jaxb. I created xsd and generated java classes.
But when I generate xml, I am geeting prefix ns2 to the root tag, which I don't want.
ex: I want root tag to be
<report>
<id>rep 1</id>
</report>
, But getting as
<ns2:report>
....
</ns2:report>
In the generated java class, I gave annotation as #XmlRootElement(name="report",namespace="urn:report")
Can some one pls help
If this is your class:
package example;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="report",namespace="urn:report")
public class Root {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Then it makes sense that there is a prefix on the root element, because you have specified that the "root" element is namespace qualified and the "id" element is not.
<ns2:report xmlns:ns2="urn:report">
<id>123</id>
</ns2:report>
If you add a package-info class to your model, you can leverate the #XmlSchema annotation:
#XmlSchema(
namespace = "urn:report",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Then the JAXB implementation may choose to leverage the default namespace, but note now all of the elements are namespace qualified which may or may not match your XML schema:
<report xmlns="urn:report">
<id>123</id>
</report>
For more information on JAXB and namespaces see:
http://bdoughan.blogspot.com/2010/08/jaxb-namespaces.html
Take a look at this answer. It describes how to use a SAX Filter to remove any namespace.
The blog entry Customizing JAXB shows the alternatives provided by implementing a PreferredMapper . Unfortunately it explains, that is not possible to fully suppress namespaces.
Use this attribute in your root element of your schema: elementFormDefault="qualified"
So for instance:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
Somehow the accepted answer did not work for me. I got success when I found solutions in some related stockOverflow questions involving DelegatingXMLStreamWriter from cxf and a filter, NoNamesWriter. The implementation I used with NoNamesWriter:
public class NoNamesWriter extends DelegatingXMLStreamWriter
{
#Override
public void writeStartElement(String prefix, String local, String uri) throws XMLStreamException {
delegate.writeStartElement("", local, uri);
}
public static XMLStreamWriter filter(FileOutputStream fileOutputStream) throws XMLStreamException {
return new NoNamesWriter(XMLOutputFactory.newInstance().createXMLStreamWriter(fileOutputStream));
}
public NoNamesWriter(XMLStreamWriter writer) {
super(writer);
}
}
Invoke the same as described here, like:
xmlmarshaller.marshal(xc, NoNamesWriter.filter(new FileOutputStream(outfile, false));