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.
Related
I have recently done an experiment to see how we can use Lombok to reduce boilerplate in our code.
The issue:
When creating a simple data class with a builder through Lombok annotations, in IntelliJ IDEA, I cannot right click a field, then select Analyze Data Flow to Here.
This is using the latest IntelliJ Lombok Plugin. IntelliJ Ultimate 2019.2.3.
Is there any fix for this or is it simply not supported?
Example 1 - no lombok:
public class Person {
private String name;
private int age;
private Person() {
}
public Person(Builder builder) {
name = builder.name;
age = builder.age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public static class Builder {
private String name;
private int age;
public Builder name(String val) {
this.name = val;
return this;
}
public Builder age(int val) {
this.age = val;
return this;
}
public Person build() {
return new Person(this);
}
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person.Builder().name("tom").age(3).build();
}
}
With the above code, when I right click the "name" variable and select analyse dataflow to here, I am able to see the dataflow. As shown in screenshot:
Example 2 - with Lombok:
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
#NoArgsConstructor
#Builder
#Getter
public class Person {
private String name;
private int age;
}
public class Main {
public static void main(String[] args) {
Person person = Person.builder().name("tom").age(3).build();
}
}
With the above code example, selecting 'analyse data flow to here' on the name field will show the variable name, but with no tree to expand as shown in the screenshot.
"Analyze data flow to here" will not work with generated code provided by Lombok annotations.
May be I am repeating this question as compared to previous question(Define namespaces tags so that generated XML have those tags?), but since in my previous question this scope gets limited to XStream that is why I need to ask this new question.
I have two classes People.java and PeopleMain.java
People.java
package com.test;
public class People {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
PeopleMain.java
package com.test;
import com.thoughtworks.xstream.XStream;
public class PeopleMain {
public static void main(String args[]){
People p= new People();
p.setAge("21");
p.setName("Manish Sharma");
String xml = //JAXB code to get xml from Person p object
System.out.println(xml);
}
}
My output on console on running PeopleMain.java comes as:
<com.test.People>
<name>Manish Sharma</name>
<age>21</age>
</com.test.People>
but I want an output as
<People xmlns:ns2="http://example.com/foo" xmlns:ns3="http://example.com/bar">
<ns2:name>Manish Sharma</ns2:name>
<ns3:age>21</ns3:age>
</People>
What changes should I make in my People.java file to get the desired output?
You can do the following and specify the namespace on the #XmlElement annotation:
import javax.xml.bind.annotation.*;
#XmlRootElement(name="People")
#XmlAccessorType(XmlAccessType.FIELD)
public class People {
#XmlElement(namespace="http://example.com/foo")
private String name;
#XmlElement(namespace="http://example.com/bar")
private int age;
}
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
http://blog.bdoughan.com/2011/11/jaxb-and-namespace-prefixes.html
http://blog.bdoughan.com/2010/10/how-does-jaxb-compare-to-xstream.html
I'm trying to implement all Java classes for handling the following XML code snippet:
<party date="2012-09-30">
<guest name="Albert">
<drink>wine</drink>
</guest>
</party>
I've wrote 3 classes:
Party.java:
package li.mnet.www.java.xml;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "party")
public class Party {
#XmlAttribute(name = "date")
private String partyDate;
public Party() {}
public String getPartyDate() {return partyDate;}
public void setPartyDate(String partyDate) {
this.partyDate = partyDate;
}
}
Guest.java:
package li.mnet.www.java.xml;
import javax.xml.bind.annotation.XmlElement;
public class Guests {
private String name;
public Guests() {}
public void setGuestName(String name) {this.name = name;}
#XmlElement(name = "name")
public String getGuestName() {return name;}
}
PartyRunner.java:
package li.mnet.www.java.xml;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class PartyRunner {
public static void main(String[] args) {
Party party = new Party();
Guests guest = new Guests();
party.setPartyDate("2012-09-03");
guest.setGuestName("Albert");
JAXBContext context;
try {
context = JAXBContext.newInstance(Party.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(party, System.out);
} catch (JAXBException e) {e.printStackTrace();}
}
}
After running the application i get following console output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<party date="2012-09-03"/>
What do i have to change, that class Guest.java gets printed out too?
Thanks a lot for your support!
When you're trying to marshal some data through JAXB, you'll give it an instance of your class (here is Party) and it will traverse your object and all of its attributes and tries to serialize them to the final output using hints provided by JAXB annotations.
Remember that JAXB ignores properties of the class which has no JAXB annotation. Also You can it tell whether to generate an XML Element or XML Attribute for given class property. You can use these annotations on properties or their getter methods.
In your example, you want to have a guest element inside party element. In your main method (in PartyRunner), you're marshaling an instance of Party class, but this class has no reference to your Guests class. Creating an instance of Guests class wouldn't be enough. You have to create a logical relationship between two classes and annotate them to make it possible to generate an appropriate XML. So your Party class should be something like this:
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "party")
public class Party {
#XmlAttribute(name = "date")
private String partyDate;
#XmlElement(name="guest")
private Guests guests;
public Party() {}
public String getPartyDate() {return partyDate;}
public void setPartyDate(String partyDate) {
this.partyDate = partyDate;
}
public Guests getGuests() {
return guests;
}
public void setGuests(Guests guests) {
this.guests = guests;
}
}
If you run the PartyRunner again you'll have something like this in your output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<party>
<partyDate>2012-09-03</partyDate>
<guest>
<name>Albert</name>
</guest>
</party>
As you can see, there is an inner element named name in your guests element. This is due to the annotation you've specified for getGuestName method in your Guests class. In order to make JAXB to generate an XML attribute for this property (instead of an XML element), you need to change the JAXB annotation in your Guests class too. You have annotated the getGuestName method as #XmlElement. This will cause to generate an XML element. If you change it to #XmlAttribute and run the PartyRunner again, you'll have this in your output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<party date="2012-09-03">
<guest name="Albert"/>
</party>
Also in your sample XML you have a drink element inside your guests property. Same is true for drink property. The drink could be a String property in your Guests class annotated as #XmlAttribute(name = "drink"). So your final Guests class to generate the XML mentioned at the beginning of your question should be something like this:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
public class Guests {
private String name;
private String drinkType;
public Guests(){}
public void setGuestName(String name) {this.name = name;}
#XmlAttribute(name = "name")
public String getGuestName() {return name;}
#XmlElement(name = "drink")
public String getDrinkType() {
return drinkType;
}
public void setDrinkType(String drinkType) {
this.drinkType = drinkType;
}
}
and your PartyRunner should initialize the drink property to something like wine:
public static void main(String[] args) {
Party party = new Party();
Guests guest = new Guests();
party.setPartyDate("2012-09-03");
guest.setGuestName("Albert");
guest.setDrinkType("wine");
party.setGuests(guest);
JAXBContext context;
try {
context = JAXBContext.newInstance(Party.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(party, System.out);
} catch (JAXBException e) {e.printStackTrace();}
}
I think the party class should contain a guest (or list of guests if you want more)
public class Party {
#XmlAttribute(name = "date")
private String partyDate;
private Guest guest;
public Party() {}
public String getPartyDate() {return partyDate;}
public void setPartyDate(String partyDate) {
this.partyDate = partyDate;
}
// getter and setter for guest
}
set the guest of the party object then marshal the party object.
Also change the XmlElement annotiantion to XmlAttribute in the guest class at the name.
I have read a XML document into JAVA DOM data structure. I am able to search through the Document and find information using a For Loop. Then I can print out to the terminal all the information held within the parent and child nodes.
However what I need to be able to do is get certain elements and print them into a spreadsheet. So somehow writing the values to a csv doc that I can then import into Excel.
This would save me a lot of time as I would have to manually copy values into a spreadsheet which would takes me weeks. So automating it is the best option but I'm inexperienced in Java. Any help is appreciated.
Doing this with a single DOM parser instance can be quite cumbersome. For that I recommend to create a JavaBean which contains all the data from the xml file. A simple method called toCsv of that class will iterate over all items and returns you the formatted content or prints it to a csv file.
If you follow this approach you can simply use the Java Architecture for XML Binding (JAXB) which will do the marshalling and unmarshalling between XML and Java- objects for you. There is no longer a need for a custom DOM parser implementation which is maybe hard to maintain. JAXB works with annotations, which defines parser rules. Here's a simple example:
public interface DataEntity {
/**
* NameSpace of XSD schema files.
*/
public final static String NSP = "https://localhost/project/xsd/";
}
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import at.fhj.ase.dao.data.validation.ValidationHelper;
/**
* Represents a product category
*
*/
#XmlRootElement(name = "category", namespace = DataEntity.NSP)
public class Category implements Serializable {
/**
*
*/
private static final long serialVersionUID = -487248720383832971L;
private Integer id;
private String name;
private String description;
protected Category() {
}
public Category(final Integer id, final String name,
final String description) {
setId(id);
setName(name);
setDescription(description);
}
#XmlAttribute
public Integer getId() {
return id;
}
private void setId(Integer id) {
ValidationHelper.validateId(id);
this.id = id;
}
#XmlElement(namespace = DataEntity.NSP)
public String getName() {
return name;
}
private void setName(String name) {
ValidationHelper.validateSingleName(name, "name");
this.name = name;
}
#XmlElement(namespace = DataEntity.NSP)
public String getDescription() {
return description;
}
private void setDescription(String description) {
ValidationHelper.validateSingleName(description, "description");
this.description = description;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Id: ").append(id).append(" Name: ").append(getName())
.append(" Description: ").append(description);
return sb.toString();
}
}
And the xml file as input:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<category xmlns="https://localhost/project/xsd/" id="1">
<description>des_swdevelopment</description>
<name>swdevelopment</name>
</category>
And how to unmarshall from xml to java:
Interface Unmarshaller
You just need to add the toCsv method and it is done. This approach will save you a lot of time and is quite easy to maintain.
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 !.