Probably this question might have been asked. I am new to the conversion of xml to java classes.
I have an xml like this:
<Root>
<Book name="harel" price="5" />
<Book name="xml" price="9" />
</Root>
IS there a way to generate java classes dynamicaly for a structure like this ?
A small correction, i don't have an xsd for the xml
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
IS there a way to generate java classes dynamicaly for a structure
like this ?
JAXB implementations provide the ability to generate a Java model from an XML schema. The reference implementation which is included in the JDK starting in Java SE 6 is available at:
<JAVA_HOME>/bin/xjc
An example of generating an object model from an XML schema can be found here:
http://blog.bdoughan.com/2010/09/processing-atom-feeds-with-jaxb.html
A small correction, i don't have an xsd for the xml
If you don't have an XML schema you could find a utility to generate an XML schema from an XML document:
Any tools to generate an XSD schema from an XML instance document?
Or start from code.
STARTING FROM CODE
You can also start from code and annotate your model to map to the existing XML structure.
Root
package forum11213872;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement(name="Root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElement(name="Book")
private List<Book> books;
}
Book
package forum11213872;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Book {
#XmlAttribute
private String name;
#XmlAttribute
private int price;
}
Demo
package forum11213872;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum11213872/input.xml");
Root root = (Root) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
input.xml/Output
<Root>
<Book name="harel" price="5" />
<Book name="xml" price="9" />
</Root>
Yes, see the castor framework (http://www.castor.org/) or jaxb (http://www.oracle.com/technetwork/articles/javase/index-140168.html)
Try Java Castor. You can specify a xsd and convert it to object. There is also a plugin for Eclipse.
http://www.castor.org/
Have a look at XStream.
It converts between XML and Java and between Java and XML.
Use JAXB, it is included in JavaSE now and you can use XJC to generate the classes from an XSD. However if you truly mean dynamically as in the structure of the XML isn't known till runtime you will need to use something like JDOM.
Related
I am trying to create the XML using the marshaling method from the JAXB library. For this approach, I am using the standard java class and assigning the annotation to it. I would like to have a wrapper element to some of the element in the class which are not Collections.
I am ware of #XmlElementWrapper which can be used for Collections but I do not have a collection. I have some elements for which I want to have an outer XML element so that it can match the standard XSD.
I just want to know if there is a way to add an outer XML element to some of the elements so that the create XML matches the standard XSD format. If there is no direct approach then what alternative approach can I take?
As we can see from the example XML the carinfo tag is a outer (wrapper) tag for the elements engine and year but this carInfo tag is not present within the Parent or Child class. As these are standard classes I cannot modify the fields/ Add new fields. Hence I would like to handle wrapper XML tag addition using the JAXB.
Following is the input JSON:
{
"brand": "Ferari",
"build": "Italy",
"engine": "Mercedes",
"year": "2021"
}
Following is the output XML that I would like to have:
<?xml version="1.0"?>
<Car>
<brand>Ferari</brand>
<build>Italy</build>
<carinfo>
<engine>Mercedes</engine>
<year>2021</year>
</carinfo>
</Car>
Following are my classes:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlTransient
#XmlType(name = "Parent")
public class Parent{
private String brand;
private String year;
//Getters and Setters avoided
}
Class based on which XML is being created:
#XmlRootElement(name = "Car")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Child",propOrder={"brand","engine","build","year"})
public class Child extends Parent{
private String engine;
private String build;
//Getter and Setters avoided
}
The main class which will create the XML: I am using the Jackson library to read the values from the Json file and create the XML based on Jaxb annotations.
public class Main{
public static void main(String []args){
JsonFactory jsonFactory = new JsonFactory();
JsonParser jsonParser = jsonFactory.createParser(new File(Main.class.getClassLoader().getResource("input.json").toURI()));
Child eventInfo = jsonParser.readValueAs(Child.class);
JAXBContext context = JAXBContext.newInstance(Child.class);
Marshaller mar = context.createMarshaller();
mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
mar.marshal(eventInfo, System.out);
}
}
From my point of view, it is possible to include a new tag inside your xml preserving the original classes with a combination of jaxb and javax.xml.transform api. The first thing is create a xsl stylesheet file for the transformation like below:
template.xsl
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Car>
<brand>
<xsl:value-of select="/Car/brand"/>
</brand>
<build>
<xsl:value-of select="/Car/build"/>
</build>
<carinfo>
<engine>
<xsl:value-of select="/Car/engine"/>
</engine>
<year>
<xsl:value-of select="/Car/year"/>
</year>
</carinfo>
</Car>
</xsl:template>
</xsl:stylesheet>
Then you can use the set a Transformer and pass to it a new JAXBSource like below:
Child eventInfo = jsonParser.readValueAs(Child.class);
JAXBContext context = JAXBContext.newInstance(Child.class);
// Create Transformer
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xslt = new StreamSource(xslFile);
Transformer transformer = tf.newTransformer(xslt);
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
//Print to the stdout the desired xml with the new nested tag
//including the two existing tags
StreamResult result = new StreamResult(System.out);
JAXBSource source = new JAXBSource(context, eventInfo);
transformer.transform(source, result);
Finally, I was able to get it using the #XmlPath from Moxy which is and library based on the Jaxb. You can use the #XmlPath to any of the elements such as collection, non-collection, String etc. I have spent a lot of time trying to configure and do workarounds so posting the answer here so it can be useful to someone in the future and they do not endup so much time as me :)
Please find the answer for configuring the Moxy here
Also, see how to get the wrapper elements for the XML using the #XmlPath here
You can also read more about it in the EclipseLink documentation.
I have XML like this which I get from middleware
<Example library="somewhere">
<book>
<AUTHORS_TEST>Author_Name</AUTHORS_TEST>
<EXAMPLE_TEST>Author_Name</EXAMPLE_TEST>
</book>
</Example>
What I want to do is convert the XML to Java object(and Vice Versa) as:
class Example
{
private String authorsTest;
private String exampleTest;
}
So Is there any way to map these two,The thing to be noted is that XML Tag Name and the Class attribute name is different,So can anyone suggest to implement this with minimal changes?Xstream is a good Choice,but if I have large number of fields it will be difficult to add aliases,so any better choices other than XStream?
What you are looking for is called XML Binding, where you actually turn an xml into a java class based on an xml schema. The reference implementation for this is jaxb but there are many other alternatives.
There are good libraries which does this for you. An easy one is XStream for example.
See this example from the Two Minute Tutorial:
Person joe = new Person("Joe", "Walnes");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
Now, to convert it to XML, all you have to do is make a simple call to XStream:
String xml = xstream.toXML(joe);
The resulting XML looks like this:
<person>
<firstname>Joe</firstname>
<lastname>Walnes</lastname>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
</person>
I would prefer XStream because it is very easy to use. If you want to do more complex things like generating Java classes from the XML you should have a look at JAXB as Miquel mentioned. But it is more complex and needs more time to get started.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
Most XML-binding libraries require an object per level of nesting in the XML representation. EclipseLink JAXB (MOXy) has the #XmlPath extension that enables XPath based mapping to remove this restriction.
Example
Below is a demonstration of how the #XmlPath extension can be applied to your use case.
package forum10511601;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="Example")
#XmlAccessorType(XmlAccessType.FIELD)
class Example {
#XmlAttribute
private String library;
#XmlPath("book/AUTHORS_TEST/text()")
private String authorsTest;
#XmlPath("book/EXAMPLE_TEST/text()")
private String exampleTest;
}
jaxb.properties
To specify MOXy as your JAXB provider you need to add a file named jaxb.properties in the same package as your domain model with the following entry (see Specifying EclipseLink MOXy as Your JAXB Provider).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
As MOXy is a JAXB (JSR-222) implementation, you use the standard JAXB runtime APIs (which are included in the JRE/JDK starting with Java SE 6).
package forum10511601;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Example.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum10511601/input.xml");
Example example = (Example) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(example, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<Example library="somewhere">
<book>
<AUTHORS_TEST>Author_Name</AUTHORS_TEST>
<EXAMPLE_TEST>Author_Name</EXAMPLE_TEST>
</book>
</Example>
When i create a jaxbcontext with all my classes, jaxb build xml for a class with a namespace from other class.
If i pass to jaxbcontext only one class it work fine.
My classes are generated by xjc.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
})
#XmlRootElement(name = "eReq")
public class EReq {
...
And when i pass only this class to jaxbcontext the output is following.
<eReq><status>UNBLOCKED</status></eReq>
But i put all my classes into jaxb context output will be like this:
<eReq xmlns:ns2="myns1" xmlns:ns3="myns2" xmlns:ns4="http://schemas.xmlsoap.org/soap/envelope/"><status>UNBLOCKED</status></eReq>
This is namespaces from my other classes. Why jaxb put it to this class?
Why jaxb put it to this class?
Because the JAXB context contains the superset of all namespaces that it's created with, and it just puts them all in each document it generates.
It does this because the namespaces need to be added to the root element (to avoid hugely wasteful re-declaration of namespaces on each child element), and it doesn't know in advance which namespaces are required for any given set of bound objects (JAXB supports incremental serialization).
So the JAXB runtime probably could avoid doing that; but it doesn't.
If you don't like it, then you need to build multiple contexts.
Is it possible to transform a POJO instance into its XML representation without storing it to DB and load it back again in DOM4J mode (and from XML to POJO)?
I have not used this yet, but DOM4J appears to have some JAXB integration that could be used to convert your POJOs to XML (DOM4J):
http://dom4j.sourceforge.net/dom4j-1.6.1/apidocs/org/dom4j/jaxb/package-summary.html
UPDATE
DOM4J also offers a DocumentResult class that implements javax.xml.transform.Result. You can use JAXB to marshal to this class and then manipulate the resulting DOM4J Document object:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import org.dom4j.Document;
import org.dom4j.io.DocumentResult;
public class Demo {
public static void main(String[] args) throws Exception {
// Create the JAXBContext
JAXBContext jc = JAXBContext.newInstance(Customer.class);
// Create the POJO
Customer customer = new Customer();
customer.setName("Jane Doe");
// Marshal the POJO to a DOM4J DocumentResult
Marshaller marshaller = jc.createMarshaller();
DocumentResult dr = new DocumentResult();
marshaller.marshal(customer, dr);
// Manipulate the resulting DOM4J Document object
Document document = dr.getDocument();
document.getRootElement().addAttribute("foo", "bar");
// Output the result
System.out.println(document.asXML());
}
}
You don't need anything except JAXB (package javax.xml.bind) which is part of JDK (I think starting from JDK6). Look into JAXBContext and #XmlRootElement annotation for starters
There are many XML serialization libraries, take your pick:
JAXB
DOM4J
XStream
I am a big fan of XStream myself, it is dead simple to use and does not require an .xsd.
I would like to know how to bind an XML tag in a certain namespace to some implementation in Java e.g. the way Mule does with the tags defined in it's various XSD files. Is it related/done with JAXB or is that just for mapping Java beans to XML?
Regards Ola
Check out my article on JAXB and namespaces:
http://bdoughan.blogspot.com/2010/08/jaxb-namespaces.html
With JAXB you can choose the granularity at which namespace information is provided:
At the package level using #XmlSchema
At the type level using #XmlType
At the field/property level using #XmlElement and #XmlAttribute
I dont fully understad your question. Are you asking about unmarshalling ?
If so try use sth like below:
JAXBContext ctx = JAXBContext.newInstance("some.package");
Unmarshaller u = ctx.createUnmarshaller();
XMLInputFactory inFac = XMLInputFactory.newFactory();
XMLStreamReader reader = inFac.createXMLStreamReader(this.getClass().
getResourceAsStream("inputFile.xml"));
JAXBElement<Mule> freestyleElement = u.unmarshal(reader,Mule.class);