I try to unmarshal a xml file to custom classes via jaxb.
The (not changeable) xml file looks as follow:
<demo>
<customers>
<customer usrid="1" name="jane" />
<customer usrid="2" name="leia" />
<customer usrid="3" name="tobi" />
</customers>
<phonenumbers>
<phonenumber usrid="1">123-456-789</phonenumber>
<phonenumber usrid="2">987-654-321</phonenumber>
<phonenumber usrid="2">111-222-333</phonenumber>
</phonenumbers>
<mobilenumbers>
<mobilenumber usrid="3">666-666-666</mobilenumber>
</mobilenumbers>
</demo>
Java classes look something special:
public class Demo {
public List<Customer> customers;
}
public class Customer {
public String usrid;
public String name;
public List<Number> numbers;
}
public class Number {
public NumberType type;
public String value;
}
public enum NumberType {
phone, mobile
}
Is this possible with jaxb (e.g. adapter) or do i have to do a xslt transform first ?
Btw. using jaxb straightforward works fine (annotations omitted):
public class Demo {
public List<Customer> customers;
public List<Phonenumber> phonenumbers;
public List<Mobilenumbers> mobilenumbers;
}
public class Customer {
public String usrid;
public String name;
}
public class Phonenumber {
public String usrid;
public String value;
}
public class Mobilenumber {
public String usrid;
public String value;
}
Related
I have an XML which looks like below
<Book>
<Name>Book1</Name>
<Cost>20$</Cost>
</Book>
I have used a Bean Class with properties name, cost and successfully unmarshaled the xml file contents to Book bean object.
Now I want to have multiple book objects in the same XML file like below.
<Books>
<Book>
...
</Book>
<Book>
...
</Book>
I know that I can create one more class with Name Books.java and have an arraylist of book objects annotated with #XmlElement tag and unmarshall it.
But, I don't want to waste one more public class for doing that.
Can anyone let me know if there is any other way of parsing that xml file with JaxB.
Thanks in advance.
Found the solution..
I can have a class like below. I can use List list; variable member within the same class Book.java instead of using one more public class Books.java.
#XmlRootElement(name = "Books")
#XmlAccessorType(XmlAccessType.FIELD)
public class BookBean {
private String name;
private String cost;
#XmlElement(name = "Books")
public List<BookBean> books;
public BookBean(){
}
public BookBean(String s1, String s2){
name=s1;
cost=s2;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCost() {
return cost;
}
public void setCost(String cost) {
this.cost = cost;
}
public List<BookBean> getBooks() {
return books;
}
public void setBooks(List<BookBean> books) {
this.books = books;
}
}
In the below sample, the Data block inside A and the Data block inside B should be unmarshalled into different classes. Is this achievable using JAXB?
<Content>
<A>
<Data>
<Name></Name>
<Age></Age>
</Data>
</A>
<B>
<Data>
<MobilePhone></MobilePhone>
<WorkPhone></WorkPhone>
</Data>
</B>
</Content>
The Data inside A and the Data inside B represent different classes.The data inside A should be mapped to AData.class and the Data inside B should be mapped to BData.class.
Note: Marshalling is working fine. Any number of classes can have the same name tag. The generated xml contains the same tag for all those classes. In this case, AData and BData will both be written to XML as <Data> . But even the same marshalled xml cannot be unmarshalled again. I am hoping this can be solved by adding some additional annotations.
You just need to have the following:
#XmlAccessorType(XmlAccessType.FIELD)
public class A {
#XmlElement(name="Data")
private AData data;
}
#XmlAccessorType(XmlAccessType.FIELD)
public class B {
#XmlElement(name="Data")
private BData data;
}
#XmlRootElement(name="Content")
#XmlAccessorType(XmlAccessType.FIELD)
public class Content {
#XmlElement(name="A")
private A a;
#XmlElement(name="B")
private B b;
}
The solution that Blaise has posted will be a good way to tackle this if you know ahead of time the objects that Content will contain, such as here:
public class Content {
#XmlElement(name="A")
private A a;
#XmlElement(name="B")
private B b;
}
But another way you could do this is to have the data that could be contained in content be wrapped in a list of some supertype that A/B extend from, which results in XML that looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Content>
<myContent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="a">
<Data>
<Name>Joe Smith</Name>
<Age>25</Age>
</Data>
</myContent>
<myContent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="b">
<Data>
<MobilePhone>555-234-5678</MobilePhone>
<WorkPhone>555-555-5555</WorkPhone>
</Data>
</myContent>
</Content>
You can get this by annotating your classes like so:
#XmlRootElement(name = "Content")
#XmlAccessorType(XmlAccessType.FIELD)
public class Content {
#XmlElement
List<SomeSuperType> myContent;
public Content() {
}
public List<SomeSuperType> getMyContent() { return this.myContent; }
public void setMyContent(List<SomeSuperType> myContent ) { this.myContent = myContent; }
}
// class for A
#XmlRootElement(name = "A")
#XmlAccessorType(XmlAccessType.FIELD)
public class A extends SomeSuperType {
#XmlElement(name="Data")
AData data;
public A() {
data = new AData();
}
public void setName(String name) {
data.name = name;
}
public void setAge(int age) {
data.age = age;
}
public String getName() { return data.name; }
public int getAge() { return data.age; }
}
class AData {
#XmlElement(name = "Name")
String name;
#XmlElement(name = "Age")
int age;
}
// class for B
#XmlRootElement(name = "B")
#XmlAccessorType(XmlAccessType.FIELD)
public class B extends SomeSuperType {
#XmlElement(name = "Data")
BData data;
public B() {
data = new BData();
}
public void setMobilePhone(String mobilePhone) { data.mobilePhone = mobilePhone; }
public void setWorkPhone(String workPhone) { data.workPhone = workPhone; }
public String getMobilePhone() { return data.mobilePhone; }
public String getWorkPhone() { return data.workPhone; }
}
class BData {
#XmlElement(name="MobilePhone")
String mobilePhone;
#XmlElement(name="WorkPhone")
String workPhone;
public BData() {
}
}
I am using dom parser in Java.
<Countries>
<Country name="USA" states="50"/>
<Country name="UK" states="4"/>
</Countries>
For the xml given above, if I have USA element node which I want to print as Country[#name="USA"][#states="50"]
Is there an easy way to get this done? Or I have to write custom method ?
If you use DOM parser , You may need to write the custom method to achieve the above feature.
If you go with JAXB , you can do the above feature by overriding the toString method of POJO class.
#XmlRootElement
public class Countries {
#XmlElement
Country country;
}
import javax.xml.bind.annotation.XmlAttribute;
public class Country {
#XmlAttribute
private String name;
#XmlAttribute
private String states;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStates() {
return states;
}
public void setStates(String states) {
this.states = states;
}
#Override
public String toString() {
return "Country[#name="+getName()+"][#states="+getStates();
}
}
Hope this helps you !.
<requests>
<request id="246">
<employee id="40350">Michael Daniels</employee>
<start>2012-10-20</start>
<end>2012-10-25</end>
<created>2012-10-11</created>
<status lastChanged="2012-10-24" lastChangedByUserId="2270">superceded</status>
<type id="4">Vacation</type>
<amount unit="hours">2</amount>
<notes>
<note from="employee">Having wisdom teeth removed.</note>
<note from="manager">Get well soon</note>
</notes>
</request>
<request id="248">
<employee id="40350">Michael Daniels</employee>
<start>2012-11-12</start>
<end>2012-11-15</end>
<created>2012-10-19</created>
<status lastChanged="2012-10-30" lastChangedByUserId="2270">superceded</status>
<type id="4">Vacation</type>
<amount unit="hours">2</amount>
<notes>
<note from="employee">My dog ate my homework so I can't come to work.</note>
</notes>
</request>
I am having a horrible time of figuring out how xstream wants me to set this up.... this is what I am currently doing:
class Holder
{
Requests requests;
#XStreamAlias("requests")
public static class Requests
{
List<Request> requests = new ArrayList<Request>();
}
#XStreamAlias("request")
public static class Request
{
int id;
Employee employee;
String start;
String end;
String created;
Status status;
Type type;
Amount amount;
Notes notes;
}
public static class Employee
{
int id;
String content;
}
public static class Status
{
String content;
String lastChanged;
int lastChangedByUserId;
}
public static class Type
{
int id;
String content;
}
public static class Amount
{
String unit;
int content;
}
public static class Notes
{
List<Note> notes = new ArrayList<Note>();
}
public static class Note
{
String from;
String content;
}
}
Coud someone please help me figure out how to set up the structure so that xstream will fill it in from the bove xml?
I think you need the structure of getter and setter in your static class just as public static class Employee, for "int id" and "String content".
I've read a time ago about generate xml from Java using annotations, but I'm not finding a simple example now.
If I want to make a xml file like:
<x:element uid="asdf">value</x:element>
from my java class:
public class Element {
private String uid = "asdf";
private String value = "value";
}
Which annotations should I use to perform that? (I have a xml-schema, if this helps the generation)
--update
The javax.xml.bind.annotation package have the annotations, "but I still haven't found what I'm looking for": an exemple of usage.. :)
Found it:
import java.io.FileOutputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
public class JavaToXMLDemo {
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Employee.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Employee object = new Employee();
object.setCode("CA");
object.setName("Cath");
object.setSalary(300);
m.marshal(object, System.out);
}
}
#XmlRootElement
class Employee {
private String code;
private String name;
private int salary;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int population) {
this.salary = population;
}
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<code>CA</code>
<name>Cath</name>
<salary>300</salary>
</employee>
From: http://www.java2s.com/Code/JavaAPI/javax.xml.bind.annotation/javaxxmlbindannotationXmlRootElement.htm
For the benefit of anyone else hitting this thread, I imagine you did the following:
#XmlRootElement
public class Element {
#XmlAttribute
private String uid = "asdf";
#XmlValue
private String value = "value";
}
For More Information
http://bdoughan.blogspot.com/2011/06/jaxb-and-complex-types-with-simple.html
There are various tools that you can use to do this. XStream (http://x-stream.github.io/) is a reasonably easy tool to use that allows you to use annotations to determine the schema of XML that is created.