I want to generate xml string in java programmatically whose name space is custom as shown below
and all data must come dynamically in xml.How can I achieve something like this?
<faxml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="test.xsd">
<person>
<name>ABC</name>
</person>
</faxml>
I have gone through examples like this https://howtodoinjava.com/jaxb/write-object-to-xml/ but here when xml generated its starting line is
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
but I want start and end tag <faxml> and namespaces as I mentioned in my sample code as output
Here is one approach:
First, here is my class representing the required XML data:
package org.ajames.jaxb.persons;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "faxml")
public class Faxml {
private Person person;
public static class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
I chose to nest the Person class inside the root class - just for this test. There are other ways to arrange these classes, of course, so they are not nested.
Then I define the package-info for org.ajames.jaxb.persons as follows:
#XmlSchema(
namespace = "",
elementFormDefault = XmlNsForm.UNSET,
xmlns = {
#XmlNs(prefix = "", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance")
})
package org.ajames.jaxb.persons;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
To process the data from a Java object to XML, I use the following test data:
Faxml.Person person = new Faxml.Person();
person.setName("ABC");
Faxml faxml = new Faxml();
faxml.setPerson(person);
The JAXB context and marshaller are as follows, assuming we are writing the XML to a Java String, for this test:
JAXBContext jaxbContext = JAXBContext.newInstance(Faxml.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "test.xsd");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter stringWriter = new StringWriter();
marshaller.marshal(faxml, stringWriter);
String xml = stringWriter.toString();
System.out.println(xml);
The resulting XML is:
<faxml xsi:noNamespaceSchemaLocation="test.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<person>
<name>ABC</name>
</person>
</faxml>
String name= "name"
String createXml="<faxml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"//
xsi:noNamespaceSchemaLocation="test.xsd">"//
+"<person>"//
+"<name>"+name+"</name>"//
+"</>person">"//
+"</faxml>";
Sysout(createXml);
get the name in a variable. Hard code these lines and insert it like this..
Related
I'm using spring batch to generate xml files.
My writer looks like :
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(Person.class);
StaxEventItemWriter<Person> itemWriter = new StaxEventItemWriter<>();
itemWriter.setRootTagName("Persons");
itemWriter.setMarshaller(marshaller);
itemWriter.setRootElementAttributes(new HashMap<String, String>() {{
put("xmlns", "http://entreprise.uk/ns");
}});
itemWriter.setResource(new FileSystemResource(Paths.get("personOutput.xml").toFile()));
itemWriter.afterPropertiesSet();
return itemWriter;
And the person class :
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Person")
public class Person {
//...
}
When I run the batch I get this error :
Caused by: javax.xml.stream.XMLStreamException: xmlns has been already bound to . Rebinding it to http://entreprise.uk/ns is an error
Anyone knows how to fix it ? I need to see xmlns attribut at the root element like :
<?xml version="1.0" encoding="UTF-8"?>
<Persons xmlns="http://entreprise.uk/ns">
<person>...</person>
</Persons>
I'm using spring-boot-starter-batch:2.3.5.RELEASE
To add namespace at the root level, you have to modify the rootTagName in your configuration.
rootTagName("{http://entreprise.uk/ns}Persons")
Hope this solves your problem.
I would personally go with a container class called Persons that has an array/list of Person.
#XmlRootElement(name = "Persons", namespace = "http://entreprise.uk/ns")
#XmlAccessorType(XmlAccessType.FIELD)
public class Persons {
#XmlElement(name = "Person")
private List<Person> persons;
//...
}
This should also remove the need for some of the configurations you currently have to set.
There are 2 ways to solve this issue:
Method-1
Using the package-info file:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<Persons xmlns="http://entreprise.uk/ns">
<person>
<firstName>Batman</firstName>
</person>
</Persons>
package-info.java:
#XmlSchema(
elementFormDefault = XmlNsForm.QUALIFIED,
namespace = "http://entreprise.uk/ns",
xmlns = {#XmlNs(prefix = "", namespaceURI = "http://entreprise.uk/ns")})
package stackover;
import jakarta.xml.bind.annotation.XmlNs;
import jakarta.xml.bind.annotation.XmlNsForm;
import jakarta.xml.bind.annotation.XmlSchema;
Persons:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Persons")
#Data
public class Persons {
private Person person;
}
Person:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Person {
private String firstName;
}
Main:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("students.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Persons.class).createUnmarshaller();
final Persons persons = unmarshaller.unmarshal(xmlStreamReader, Persons.class).getValue();
System.out.println(persons.toString());
Marshaller marshaller = JAXBContext.newInstance(Persons.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(persons, System.out);
}
}
Output:
Persons(person=Person(firstName=Batman))
<Persons xmlns="http://entreprise.uk/ns">
<person>
<firstName>Batman</firstName>
</person>
</Persons>
Method-2
Using the prefix with namespace URI for XML and adding to the root class:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<Persons xmlns:ns0="http://entreprise.uk/ns">
<person>
<firstName>Batman</firstName>
</person>
</Persons>
Persons:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Persons", namespace = "http://entreprise.uk/ns")
#Data
public class Persons {
private Person person;
}
Person:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Person {
private String firstName;
}
Main:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("students.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Persons.class).createUnmarshaller();
final Persons persons = unmarshaller.unmarshal(xmlStreamReader, Persons.class).getValue();
System.out.println(persons.toString());
Marshaller marshaller = JAXBContext.newInstance(Persons.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(persons, System.out);
}
}
Output:
Persons(person=Person(firstName=Batman))
<ns0:Persons xmlns:ns0="http://entreprise.uk/ns">
<person>
<firstName>Batman</firstName>
</person>
</ns0:Persons>
I have a sample XML as shown below:
<?xml version="1.0" encoding="UTF-8"?>
<Education>
<School name="ABC" location="Mangalore">
<Student gender="M" housepincode="575020">
<FirstName>VJ</FirstName>
<LastName>K</LastName>
</Student>
<Student gender="M" housepincode="575002">
<FirstName>S</FirstName>
<LastName>K</LastName>
</Student>
</School>
</Education>
This has been unmarshalled with the help of JAXB using the following approach.
I have classes for Education,School and Student.
Education.java
import lombok.Data;
#Data
#XmlRootElement(name = "Education")
public class Education {
public School School;
}
School.java
import lombok.Data;
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class School {
#XmlAttribute
private String name;
#XmlAttribute
private String location;
#XmlElement(name ="Student")
private List<Student> Student;
}
Student.java
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
#XmlAttribute
private String gender;
#XmlAttribute
private String housepincode;
#XmlElement(name = "FirstName")
private String FirstName;
#XmlElement(name = "LastName")
private String LastName;
}
I have some concerns over the output I receive. First of all there are some warnings. I believe it is because i have missed some annotations which should be present. Any suggestions or guidance here please?
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.sun.xml.bind.v2.runtime.reflect.opt.Injector (file:/C:/Users/R.Premsagar/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.0-b170127.1453/jaxb-runtime-2.3.0-b170127.1453.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int)
WARNING: Please consider reporting this to the maintainers of com.sun.xml.bind.v2.runtime.reflect.opt.Injector
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Education(School=School(name=ABC, location=Mangalore, Student=[Student(gender=M, housepincode=575020, FirstName=VJ, LastName=K), Student(gender=M, housepincode=575002, FirstName=S, LastName=K)]))
Also, the heirarchy of output does not seem correct to me, Eg: School = School tag?
I want to print this output to a separate XML to verify the result.
However the script fails
Main program:
List<Education> Entries = new ArrayList<Education>();
try {
File xmlFile = new File("Withattributes.xml");
JAXBContext jaxbContext;
jaxbContext = JAXBContext.newInstance(Education.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Education entries = (Education) jaxbUnmarshaller.unmarshal(xmlFile);
Entries.add(entries); //storing objects in a list for later use
//--------------------------------------------------------------
JAXBContext jaxbContext_w = JAXBContext.newInstance(Education.class);
Marshaller jaxbMarshaller = jaxbContext_w.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
jaxbMarshaller.marshal(jaxbContext_w, System.out);
}
catch (JAXBException e)
{
e.printStackTrace();
} catch (FactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I get the following error message:
Neither the class com.sun.xml.bind.v2.runtime.JAXBContextImpl nor one of the associated superclasses is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:593)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:482)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:328)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:256)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:110)
at JaxbExample.main(JaxbExample.java:39)
Please let me know what could be done here..
UPDATE:
If the XML is updated to have a structure as below:
<?xml version="1.0" encoding="UTF-8"?>
<Education>
<School name="ABC" location="Mangalore">
<Student gender="M" housepincode="575020">
<FirstName>VJ</FirstName>
<LastName>K</LastName>
<Hobbies>
<Hobby time = "M">Novels</Hobby>
<Hobby time = "A">Gaming</Hobby>
</Hobbies>
</Student>
</School>
</Education>
Now the class of Student.java would change to
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
#XmlAttribute
private String gender;
#XmlAttribute
private String housepincode;
#XmlElement(name = "FirstName")
private String FirstName;
#XmlElement(name = "LastName")
private String LastName;
#XmlElementWrapper(name ="Hobbies")
#XmlElement(name="Hobby")
private List<Hobby> Hobbies;
}
and the Hobby.java
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Hobby{
#XmlAttribute(name="Time")
private String Time;
#XmlElement
private String Hobby;
}
With this modification I do not get the value of the Hobby tag. I get the list of Hobbies and values something like this:
Hobbies>
<Hobby time = "M"/>
<Hobby time = "A"/>
</Hobbies>
Could you correct me here please?
First issue:
I am no expert on JAXB so I do not have much idea on what could cause the warnings specified here but I tried following the code and it seems to work fine for me without any warnings. If you want to get more understanding then the best thing to do is search about it and read the doc to get more information. But my guess is that it's happening due to your second issue.
Also, I am using Moxy which is an extension of JAXB developed by Eclipse-link. It has many additional benefits compared to simple JAXB
Second issue:
obvious error is in this line:
jaxbMarshaller.marshal(jaxbContext_w, System.out);
why are you providing jaxbContext_w as an input to it. It should be the unmarshalled values. In your case, it is entries.
Following is the complete code:
Education:
#Data
#XmlRootElement(name = "Education")
#XmlAccessorType(XmlAccessType.FIELD)
public class Education {
public School School;
}
School:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class School {
#XmlAttribute
private String name;
#XmlAttribute
private String location;
#XmlElement
private List<Student> Student;
}
Student:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
#XmlAttribute
private String gender;
#XmlAttribute
private String housepincode;
#XmlElement
private String FirstName;
#XmlElement
private String LastName;
}
Main:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("students.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Education.class).createUnmarshaller();
final Education education = unmarshaller.unmarshal(xmlStreamReader, Education.class).getValue();
System.out.println(education.toString());
Marshaller marshaller = JAXBContext.newInstance(Education.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(education, System.out);
}
}
Output (Without any error or warnings):
Education(School=School(name=ABC, location=Mangalore, Student=[Student(gender=M, housepincode=575020, FirstName=VJ, LastName=K), Student(gender=M, housepincode=575002, FirstName=S, LastName=K)]))
<Education>
<School name="ABC" location="Mangalore">
<Student gender="M" housepincode="575020">
<FirstName>VJ</FirstName>
<LastName>K</LastName>
</Student>
<Student gender="M" housepincode="575002">
<FirstName>S</FirstName>
<LastName>K</LastName>
</Student>
</School>
</Education>
I know it doesn't make much sense, but I have to generate an XML from a Java object without the parent node of some elements, like explained below.
This is the example Java class model for the XML:
#XmlRootElement(name = "person")
public class PersonXml {
#XmlElement(name = "name")
private String name;
#XmlElement(name = "car")
private List<CarXml> cars;
.
#XmlRootElement(name = "car")
public class CarXml {
#XmlElement(name = "model")
private String model;
#XmlElement(name = "brand")
private String brand;
By default, if I generate the XML from an object of PersonXml like this:
StringWriter writer = new StringWriter();
JAXBContext ctx = JAXBContext.newInstance(PersonXml.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.marshal(xml, writer);
I would get:
<person>
<name>Pedro</name>
<car>
<model>Logan</model>
<brand>Renault</brand>
</car>
<car>
<model>Duster</model>
<brand>Renault</brand>
</car>
</person>
What I need is to remove the <car> tag, or even to prevent it to be generated at all.
I need the XML to be like this:
<person>
<name>Pedro</name>
<model>Logan</model>
<brand>Renault</brand>
<model>Duster</model>
<brand>Renault</brand>
</person>
Of course I could convert the XML to a String and remove the tags with replaceAll or something like this, but I was wondering if there is a nicer way to achieve this.
If you need to generate this output, you can use JAXB as follows:
1) Create a new Person class:
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"field"
})
#XmlRootElement(name = "person")
public class Person {
#XmlElementRefs({
#XmlElementRef(name = "name", type = JAXBElement.class, required = false),
#XmlElementRef(name = "model", type = JAXBElement.class, required = false),
#XmlElementRef(name = "brand", type = JAXBElement.class, required = false)
})
protected List<JAXBElement<String>> field;
public List<JAXBElement<String>> getNameOrModelOrBrand() {
if (field == null) {
field = new ArrayList<>();
}
return this.field;
}
}
2) Create an ObjectFactory to make it easier to use the person class:
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;
#XmlRegistry
public class ObjectFactory {
private final static QName _PersonName_QNAME = new QName("", "name");
private final static QName _PersonModel_QNAME = new QName("", "model");
private final static QName _PersonBrand_QNAME = new QName("", "brand");
public ObjectFactory() {
}
public Person createPerson() {
return new Person();
}
#XmlElementDecl(namespace = "", name = "name", scope = Person.class)
public JAXBElement<String> createPersonName(String value) {
return new JAXBElement<>(_PersonName_QNAME, String.class, Person.class, value);
}
#XmlElementDecl(namespace = "", name = "model", scope = Person.class)
public JAXBElement<String> createPersonModel(String value) {
return new JAXBElement<>(_PersonModel_QNAME, String.class, Person.class, value);
}
#XmlElementDecl(namespace = "", name = "brand", scope = Person.class)
public JAXBElement<String> createPersonBrand(String value) {
return new JAXBElement<>(_PersonBrand_QNAME, String.class, Person.class, value);
}
}
Use the factory as follows:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
import java.util.List;
...
ObjectFactory factory = new ObjectFactory();
Person person = factory.createPerson();
List<JAXBElement<String>> list = person.getNameOrModelOrBrand();
list.add(factory.createPersonName("Pedro"));
list.add(factory.createPersonModel("Logan"));
list.add(factory.createPersonBrand("Renault"));
list.add(factory.createPersonModel("Duster"));
list.add(factory.createPersonBrand("Renault"));
JAXBContext ctx = JAXBContext.newInstance(Person.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter writer = new StringWriter();
marshaller.marshal(person, writer);
System.out.println(writer.toString());
The end result is XML as follows:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<person>
<name>Pedro</name>
<model>Logan</model>
<brand>Renault</brand>
<model>Duster</model>
<brand>Renault</brand>
</person>
Creating elements in this way is the only way I know to get the end result you need.
There are probably various things you could do to refactor the above code, to streamline the creation of the list of elements - but this shows you the basic approach.
As you already know - this is far from ideal. The end result is not any type of XML that I would want to receive.
I'm trying to parse an xml file using JAXB.
My problem is that I need to skip the root node, If I delete it from the xml file I get what I need, otherwise - I get an empty object.
I'll give a simplified xml and my code (It behaves the same way):
XML:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<!-- <Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Office.xsd">
-->
<Office>
<Employees>
<Employee>
<name>George</name>
<rank>3</rank>
</Employee>
<Employee>
<name>Michael</name>
<rank>5</rank>
</Employee>
<Employee>
<name>Jeff</name>
<rank>1</rank>
</Employee>
<Employee>
<name>Todd</name>
<rank>7</rank>
</Employee>
<Employee>
<name>Jessica</name>
<rank>5</rank>
</Employee>
</Employees>
</Office>
</Root>
Office class:
import javax.xml.bind.annotation.*;
import java.util.Vector;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Office {
#XmlElementWrapper(name = "Employees")
#XmlElement(name = "Employee")
private Vector<Employee> employees;
}
Employee class:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
#XmlElement(name="name")
private String name;
#XmlElement(name="rank")
private int rank;
public void promote() {
rank++;
}
}
Driver:
import javax.xml.stream.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.Marshaller;
import java.io.FileReader;
public class Driver {
public static void main (String[] args) {
parseOffice();
}
public static void parseOffice() {
try {
XMLInputFactory f = XMLInputFactory.newInstance();
XMLStreamReader reader = f.createXMLStreamReader(new FileReader("Office.xml"));
JAXBContext context = JAXBContext.newInstance(Office.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Office office = unmarshaller.unmarshal(reader, Office.class).getValue();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(office, System.out);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
You can parse the XML with a StAX XMLStreamReader, then advance it to the element you want to unmarshal, and then unmarshal it.
I posted a full example that should help on the related question linked below:
How to unmarshall SOAP response using JAXB if namespace declaration is on SOAP envelope?
Why don't you create a generic root element?
#XmlRootElement(name="Root" ...)
public class Root {
#XmlAnyElement(lax=true)
private Object content;
}
Add it to your context and unmarshal. You should get a JAXBElement<Office> as content.
Simply add the root class in hierarcy. And get Office class from Root class.
Root Class:-
import javax.xml.bind.annotation.*;
import java.util.Vector;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElement(name = "Office")
private Office office;
}
Office class
import javax.xml.bind.annotation.*;
import java.util.Vector;
#XmlAccessorType(XmlAccessType.FIELD)
public class Office {
#XmlElementWrapper(name = "Employees")
#XmlElement(name = "Employee")
private Vector<Employee> employees;
}
Change in parse method :-
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = unmarshaller.unmarshal(reader, Root.class).getValue();
Office office = root.getOffice();
I'm writing a script to parse a KML file using JAXB and MOXy, but I'm having difficulty getting #XmlPath to work with a provided namespace.
If my KML looks like this:-
<kml>
<Document>
<name>Test</name>
</Document>
</kml>
... and my bean looks like this:-
#XmlRootElement(name = "kml")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
... then, kml.getName() returns Test, which works like it should.
However, if my KML contains a namespace like this:-
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Test</name>
</Document>
</kml>
... and my bean looks like this:-
#XmlRootElement(name = "kml", namespace = "http://www.opengis.net/kml/2.2")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
... then, kml.getName() returns null.
I do have jaxb.properties at the right package level and I'm using the following MOXy's dependency:-
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.moxy</artifactId>
<version>2.3.2</version>
</dependency>
What exactly am I missing here? Thanks.
Below is an example demonstrating how to configure the namespace information.
package-info
You can use the #XmlSchema annotation to specify the namespace information and qualification. In the example below we will specify the namespace, and that by default all elements should be namespace qualified.
#XmlSchema(
namespace="http://www.opengis.net/kml/2.2",
elementFormDefault=XmlNsForm.QUALIFIED)
#XmlAccessorType(XmlAccessType.FIELD)
package forum9931520;
import javax.xml.bind.annotation.*;
Kml
We do not need to specify any namespace information in the Kml class. This information comes from the settings in package-info:
package forum9931520;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name = "kml")
public class Kml {
#XmlPath("Document/name/text()")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Demo
package forum9931520;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Kml.class);
File xml = new File("src/forum9931520/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Kml kml = (Kml) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(kml, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>Test</name>
</Document>
</kml>
For More Information
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html