How to convert a given XML snippet to an equivalent JSON format and vice-versa


In WEB based applications RESTful APIs are used to manipulate data between the browser and the server. User may enter some data which is formatted to a valid JSON object (Java Script Object Notation) before sending it to the server for processing. However at the server side this data may be stored in an XML format, which means we need to now convert this data from JSON to XML and vice-versa while sending data from server to the browser.

Below is a screenshot showing a sample XML on the left side and the generated JSON on the right side:


Conversion of JSON to XML isn't straight forward since they don't share common aspects about their structure. One may write a parser to read JSON elements one by one and then generate an XML but its a tedious job. Thanks to the power of Java Architecture for XML Binding (JAXB) which can easily parsing of XML (based on its dtd - document type definition) ie: convert an XML string into a java object and vice-versa. However pure jaxb implemetation isin't sufficient to solve our problem. We need a third party library named eclipselink.jar (download from here) which has the jaxb implementation to convert XML to JSON and vice versa. Alternatively we can use 3 sub jars from the eclipselink.jar - org.eclipse.persistence.core-2.5.1.jar, org.eclipse.persistence.antlr-2.5.1.jar, org.eclipse.persistence.moxy-2.5.1.jar

Steps:
1. Generate java classes using the dtd file of the XML
/usr/java/jdk1.7.0_60/bin/xjc
-dtd /home/cubicrace/workspace/json2xml/samples/DatabaseInventory.dtd
-d /home/cubicrace/workspace/json2xml/src/
-p com.utilities.jaxb

parsing a schema...
compiling a schema...
com/utilities/jaxb/Administrator.java
com/utilities/jaxb/DatabaseAttributes.java
com/utilities/jaxb/DatabaseInventory.java
com/utilities/jaxb/DatabaseName.java
com/utilities/jaxb/ObjectFactory.java


2. Create a jaxb.properties file with the below content:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Ensure that this file exists at the same location as the .class files of the above generated java files.

3. Add the eclipselink.jar to the classpath or project's java build path

4. Write a simple class to perform the conversion.
Below is a working standlone class:


package com.utilities;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;

import com.utilities.jaxb.DatabaseInventory;

public class JsonXmlConverter {

 public static final String base = "/home/cubicrace/workspace";
 
 static String srcJsonFile = base + "/json2xml/samples/dbInventory.json";
 static String srcXmlFile = base +  "/json2xml/samples/dbInventory.xml";    
 static String convertedJsonFile = base + "/json2xml/samples/convertedFile.json";
 static String convertedXmlFile = base + "/json2xml/samples/convertedFile.xml";
 
 public boolean createFile(String filePath) {
  File file = new File(filePath);
  file.delete();
  try {
   return file.createNewFile();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   return false;
  }
 }
 
 private void jsonToXml(String jsonFile) throws Exception{
  File jsonObj = new File(jsonFile);
  JAXBContext jc = JAXBContext.newInstance(DatabaseInventory.class);
  Unmarshaller unmarshaller = jc.createUnmarshaller();
  unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
  DatabaseInventory activity = (DatabaseInventory) unmarshaller.unmarshal(jsonObj);
  
  Marshaller xmlM = jc.createMarshaller();
  xmlM.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
  FileOutputStream fos = new FileOutputStream(new File(convertedXmlFile));
  xmlM.marshal(activity, fos);
  fos.close();
 }
 
 private void xmlToJson(String xmlFile) throws Exception{
  File xml = new File(xmlFile);
  JAXBContext jc = JAXBContext.newInstance(DatabaseInventory.class);
  Unmarshaller unmarshaller = jc.createUnmarshaller();
  DatabaseInventory activity = (DatabaseInventory) unmarshaller.unmarshal(xml);

  Marshaller marshaller = jc.createMarshaller();
  marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true);
  marshaller.setProperty( MarshallerProperties.MEDIA_TYPE, "application/json");
  marshaller.setProperty( MarshallerProperties.JSON_INCLUDE_ROOT, true);
  FileOutputStream fos = new FileOutputStream(new File(convertedJsonFile));
  marshaller.marshal(activity, fos);
  fos.close();
 }
 
 public static void main(String[] args) {

  JsonXmlConverter jxc = new JsonXmlConverter();
    
  try {
   jxc.createFile(convertedJsonFile);
   System.out.println("Source XML: " +  srcXmlFile);
   jxc.xmlToJson(srcXmlFile);
   System.out.println("Converted Output JSON: " + convertedJsonFile);
   
   jxc.createFile(convertedXmlFile);
   System.out.println("Source JSON: " + srcJsonFile);
   jxc.jsonToXml(srcJsonFile);
   System.out.println("Converted Output XML: " + convertedXmlFile);
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
 }

}


Note: Ensure to update the workspace variable in the above java class before executing in your local environment.

If you see the below error, it means the jaxb.properties file (step2 above) is missing at the expected location or has incorrect property value pair.
javax.xml.bind.PropertyException: name: eclipselink.media-type value: application/json
at javax.xml.bind.helpers.AbstractMarshallerImpl.setProperty(AbstractMarshallerImpl.java:337)
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.setProperty(MarshallerImpl.java:539)

Download the dtd, sample files, eclipselink.jar and source code as single zip: here
+