Transforming Java object to JSON via XSLT - java

I already have
a working JAXB setup for Schema A
a working JAXB setup for Schema B
an XSLT transformation from instances of A to instances of B (and vice versa)
If I have an XML instance of type A, I can use XSLT and Jettsion to produce a reasonable JSON representation of B. But what I really want to do is take a Java object of type A, a JAXB marshaller, my existing A->B XSLT, and a Jettsion XMLStreamWriter to produce JSON of type B, without having to produce an instance of B (XML or Java) in between.
Java Object A --> JAXB Marshaller --> ? --> XSLT A to B transfrom --> JSON B
I have an idea that I should be able to this by marshalling to a SAXResult that in turn act as an XMLReader that can feed the XSLT translation. I need a kind of ContentHandlerAdapter that can coordinate the marshalling with the transformation.
But here my head starts spinning.
Has anybody seen or written a setup like this, and hopefully point me to an example?

You can wrap the object and an instance of Marshaller (or JAXBContext) in JAXBSource and pass that to the Transformer.
http://blog.bdoughan.com/2012/11/using-jaxb-with-xslt-to-produce-html.html

That is the purpose of the trax TransformerHandler interface.
TransformerFactory tf = TransformerFactory.newInstance();
// or just use new net.sf.saxon.TransformerFactoryImpl() for Saxon (XSLT 2.0)
Source xslt = new StreamSource(....);
TransformerHandler handler =
((SAXTransformerFactory)tf).newTransformerHandler(xslt);
Result result = new StAXResult(theJettisonStreamWriter);
handler.setResult(result);
SAXResult marshallerResult = new SAXResult(handler);
// marshal to the marshallerResult as normal

Related

Converting JSON to POJO using JAXB

I´m using ElasticSearch to store some data related to events that are happening with objects, a Track and Trace Model. To do that I used JAXB to generate de model classes using a XSD file.
I can save the data on ES easily transforming the Data data comes in XML to POJO and after that to JSON.
The problem that I´m having is to get the data back. I´m trying to use the same logic JSON to POJO (using JAXB) and POJO to XML on the web service. Like that:
JAXBContext jc = JAXBContext.newInstance(EPCISDocumentType.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setProperty("eclipselink.media-type", "application/json");
unmarshaller.setProperty("eclipselink.json.include-root", true);
String eventJSON = elasticEvent.getSpecific("event", "raw", eventID);
The String comes with the expected event but when I try to transform to POJO the object comes only with the outer most class (EPCISDocumentType) but with 0 contents. I´m trying like that:
StreamSource eventStream = new StreamSource(new StringReader(eventJSON));
EPCISDocumentType foundEvent = unmarshaller.unmarshal(eventStream,EPCISDocumentType.class).getValue();
The problem is why this is happening, I´m using exactly the same libraries to do Marshal but I can´t unmarshal it back to the same content.
I use ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper) for both marshaling and unmarshaling. It's much easier to use.
See bellow:
ObjectMapper mapper = new ObjectMapper();
//Get the json as String
String objectAsJsonString= mapper.writeValueAsString(foundEvent);
//Create the object from the String
EPCISDocumentType foundEvent = mapper.readValue(objectAsJsonString,EPCISDocumentType.class);
When you have lists of objects you want to marshal/unmarshal, it works only if you put the list in a wrapper.
Also jackson is more performant than jaxb.
Check these tests: http://tuhrig.de/jaxb-vs-gson-and-jackson/

Java API for XML Schema manipulation

I am familiar with JAXB, JAXP and DOM. I know JAXB provides java2xml and xml2java generation(and validation against XML Schema(XSD)). What I want is convenient way to produce XML schema programmatically from scratch. I do not want to produce XSD from java classes. I want to have an object representing the schema itself. For example:
XMLSchemaFactory factory = XMLSchemaFactory.newInstance();
XMLSchema schema = factory.newSchema();
schema.setTargetNameSpace("http://www.example.com");
...
schema.addComplexType(complexTypeElement);
...
schema.addElement(name, type);
...
schema.export(new File("mySchema.xsd"));
I know XML schema is itself XML, so I can use Document, Element, Node and other classes/interfaces from org.w3c.dom, but I wonder is there something more convenient ?
Why I want this - I have some IDL, which I have to translate to WSDL. I have lexer/parser for the IDL and I have convenient representation of it as java objects. Now I want to produce the WSDL using this objects => a lot of XML schemas have to be generated !
From my point use WSDL4J it would be pretty easier for your xml manipulations.
Refer this pdf for more details.
http://wsdl4j.sourceforge.net/downloads/JSR110_proposed_final_draft.pdf

How to create multiple xml request by only changing one field?

I need help to find the approach of how to create xml multiple times while I will be changing only two fields everytime and rest of the fields would be same as now. Please tell me the way to do it in java?
This is the sample xml below:
I would be changing the value of <Id> and <Originator>
<TransactionBlk>
<Id>NIK</Id>
<CorrelationId />
<Originator>NIK</Originator>
<Service>GetIns</Service>
<VersionNbr>1</VersionNbr>
<VersionNbrMin>0</VersionNbrMin>
<MsgNm>Req</MsgNm>
<MsgFormatCd>XML</MsgFormatCd>
</TransactionBlk>
You can crate one class contain all this parameter as class variable, create getter and setter method. Create object of class set value by using setter method.
You can use JAXB API's class to convert your java object into XML format.
The JAXBContext class provides the client's entry point to the JAXB API.
It provides an abstraction for managing the XML/Java binding information
necessary to implement the JAXB binding framework operations: unmarshal,
marshal and validate.
Here is Doc reference for convert your Java object into XML.
Here are tutorial for same Tutorial Link
Sample Code :
#XmlRootElement(name="TransactionBlk_REQ",namespace="http://TransactionBlk.com")
#XmlAccessorType(XmlAccessType.FIELD)
public class TransactionBlk
{
#XmlElement(name = "Id")
private String id;
#XmlElement(name = "Originator")
private String Originator;
//Your getter and setter method.
}
TransactionBlk bean = new TransactionBlk();
//Set your parameter value here
StringWriter responseWriter = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(TransactionBlk.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.marshal(bean, responseWriter);
String xmlStr = responseWriter!=null?responseWriter.toString():null;
You can use XSLT to transform XML.
If all you're doing is printing a "boilerplate" document with changes in those two values, a, you could use the DPH (Desperate Perl Hacker) approach: simply assemble it as text, pausing to print the values at the appropriate places. To be safe, you should pre-scan the values to make sure they don't contain the <, >, or & characters and escape those if you find them.
For something more complex, or if you want to start learning how to do it "properly", look at the standard XML APIs for Java: DOM (the Document Object Model, an in-memory tree model of a document), SAX (an event-stream view of a document), and JAXP (tools to take an XML document and parse it into DOM or SAX so you can read it, and to take DOM or SAX and write those out as XML syntax). JAXP also provides standard APIs for invoking XPath to search a document and XSLT to apply a stylesheet to a document, so taken together these cover a huge percentage of the basic operations on XML.
You might want to look at some tutorials on using Java to manipulate XML. I'm certainly biased, not least because they published one of my articles, but in my experience IBM's DeveloperWorks website (https://www.ibm.com/developerworks/xml/) has had better-than-average material for learning about XML and other standards.

How to marshall JAXB object to a different schema?

I unmarshall an XML that comes in a specific format e.g.
<root>
<a/>
<b/>
<c>
<x/>
</c>
<d/>
</root>
After playing around with the Java object, I want to send it to another service that uses a different schema, e.g.
<anotherRoot>
<a/>
<x/>
<something>
<d/>
</something>
</anotherRoot>
Can this be done "easily" w/ JAXB?
Using any JAXB (JSR-222) implementation you could use XSLT on a JAXBSource and the javax.xml.transform APIs to produce a secondary XML structure:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
// Output XML conforming to first XML Schema
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(foo, System.out);
// Create Transformer on Style Sheet that converts XML to
// conform the second XML Schema
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xslt = new StreamSource(
"src/example/stylesheet.xsl");
Transformer transformer = tf.newTransformer(xslt);
// Source
JAXBSource source = new JAXBSource(jc, foo);
// Result
StreamResult result = new StreamResult(System.out);
// Transform
transformer.transform(source, result);
Full Example
http://blog.bdoughan.com/2012/11/using-jaxb-with-xslt-to-produce-html.html
You can create create a proxy for the other service and regard its beans as simple data transfer objects.
So when you wish to call the service, you manually fill the beans based on the values of your proper model objects (the one you play around with, the ones that contain business logic) and call the service using the beans.
If changes happen to the service's interface, you can recreate the proxy and the compiler will help you fix the transformation.

JAXB Fragmented Marshalling

I'm having some trouble successfully marshalling using the Marshaller.JAXB_FRAGMENT property. Here's a simple version of the XML i'm trying to output.
<Import>
<WorkSets>
<WorkSet>
<Work>
<Work>
...
..
...
</WorkSet>
<WorkSet>
<Work>
<Work>
...
</WorkSet>
<WorkSets>
<Import>
The <Import> and <WorkSets> elements are essentially just container elements that enclose a large number of <WorkSet> & <Work> elements. I'm currently trying to marshall at the <WorkSet>.
Is it possible to initially marshal the <Import> and <WorkSets> elements and then from then on marshal at the <WorkSet> element and have the output be enclosed in the <Import><WorkSets> tags?
When I'm marshaling at the WorkSet level it attaches the xmlns='http://namespace.com' attribute to the WorkSet tag, is there a way to marshal without the namespace attribute being attached to Workset?
Basically, it sounds like rather than constructing a full object tree with the container objects, you want to be able to stream a collection of WorkSet instances to marshal using JAXB.
The approach I would take is to use an XMLStreamWriter and marshal the WorkSet objects by wrapping them in a JAXBElement. I don't have tested sample code close at hand, so here's the rough code snippet that should put you on the write track:
FileOutputStream fos = new FileOutputStream("foo.xml");
XMLStreamWriter writer = XMLOutputFactory.newFactory().createXMLStreamWriter(fos);
writer.writeStartDocument();
writer.writeStartElement("Import");
writer.writeStartElement("WorkSets");
JAXBContext context = JAXBContext.newInstance(WorkSet.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
for (WorkSet instance : instances)
{
JAXBElement<WorkSet> element = new JAXBElement<WorkSet>(QName.valueOf("WorkSet"), WorkSet.class, instance);
m.marshal(element, writer);
}
writer.writeEndDocument(); // this will close any open tags
writer.close();
Note: The above is completely untested and may be messing something up in the wrapping part to write each instance of WorkSet. You need to wrap the WorkSet instances because they will not be annotated with #XmlRootElement and JAXB will otherwise refuse to marshal the objects.

Categories