Last active
March 1, 2018 06:38
-
-
Save Stwissel/900acc8ed6a46131530ab89bb70b9f9d to your computer and use it in GitHub Desktop.
Json to XML and Back with vert.x
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.wissel.json2xml; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.PrintStream; | |
import java.io.PrintWriter; | |
import java.util.Date; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.Map.Entry; | |
import java.util.Scanner; | |
import java.util.Stack; | |
import javax.xml.parsers.ParserConfigurationException; | |
import javax.xml.parsers.SAXParser; | |
import javax.xml.parsers.SAXParserFactory; | |
import javax.xml.transform.OutputKeys; | |
import javax.xml.transform.Transformer; | |
import javax.xml.transform.TransformerConfigurationException; | |
import javax.xml.transform.TransformerFactory; | |
import javax.xml.transform.sax.SAXTransformerFactory; | |
import javax.xml.transform.sax.TransformerHandler; | |
import javax.xml.transform.stream.StreamResult; | |
import org.xml.sax.Attributes; | |
import org.xml.sax.SAXException; | |
import org.xml.sax.helpers.AttributesImpl; | |
import org.xml.sax.helpers.DefaultHandler; | |
import io.vertx.core.buffer.Buffer; | |
import io.vertx.core.json.JsonArray; | |
import io.vertx.core.json.JsonObject; | |
public class Json2XmlMain { | |
private class SimpleXMLDoc { | |
private TransformerHandler hd = null; | |
private boolean documentStarted = false; | |
final private ByteArrayOutputStream out = new ByteArrayOutputStream(); | |
private final Stack<String> xmlTagStack = new Stack<String>(); | |
public void addEmptyTag(final String tagName, final Map<String, String> attributes) | |
throws TransformerConfigurationException, SAXException { | |
this.openTag(tagName, attributes); | |
this.closeTag(1); | |
} | |
public void closeDocument() throws SAXException { | |
this.closeTag(-1); // Make sure all tages are closes | |
// Closing of the document, | |
this.hd.endDocument(); | |
} | |
public void closeTag(final int howMany) throws SAXException { | |
if (howMany < 0) { | |
while (!this.xmlTagStack.empty()) { | |
final String closeTag = this.xmlTagStack.pop(); | |
this.hd.endElement("", "", closeTag); | |
} | |
} else { | |
for (int i = 0; i < howMany; i++) { | |
if (!this.xmlTagStack.empty()) { | |
final String closeTag = this.xmlTagStack.pop(); | |
this.hd.endElement("", "", closeTag); | |
} else { | |
break; // No point looping | |
} | |
} | |
} | |
} | |
public void openTag(final String tagName) throws SAXException, TransformerConfigurationException { | |
this.openTag(tagName, null, null); | |
} | |
public void openTag(final String tagName, final Map<String, String> attributes) | |
throws SAXException, TransformerConfigurationException { | |
AttributesImpl atts = null; | |
if (!this.documentStarted) { | |
this.initializeDoc(); | |
} | |
// This creates attributes that go inside the element, all | |
// encoding is | |
// taken care of | |
if ((attributes != null) && !attributes.isEmpty()) { | |
atts = new AttributesImpl(); | |
for (final Entry<String, String> curAtt : attributes.entrySet()) { | |
atts.addAttribute("", "", curAtt.getKey(), "CDATA", curAtt.getValue()); | |
} | |
} | |
// This creates the element with the previously defined | |
// attributes | |
this.hd.startElement("", "", tagName, atts); | |
this.xmlTagStack.push(tagName); // Memorize that we opened it! | |
} | |
public void openTag(final String tagName, final String attributeName, final String attributValue) | |
throws SAXException, TransformerConfigurationException { | |
final Map<String, String> attributes = new HashMap<>(); | |
if ((attributeName != null) && (attributValue != null)) { | |
attributes.put(attributeName, attributValue); | |
} | |
this.openTag(tagName, attributes); | |
} | |
@Override | |
public String toString() { | |
return new String(this.out.toByteArray()); | |
} | |
private void initializeDoc() throws TransformerConfigurationException, SAXException { | |
final PrintWriter pw = new PrintWriter(this.out); // out comes from | |
// outside | |
final StreamResult streamResult = new StreamResult(pw); | |
// Factory pattern at work | |
final SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance(); | |
this.hd = tf.newTransformerHandler(); | |
final Transformer serializer = this.hd.getTransformer(); | |
serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); | |
serializer.setOutputProperty(OutputKeys.METHOD, "xml"); | |
serializer.setOutputProperty(OutputKeys.INDENT, "yes"); | |
this.hd.setResult(streamResult); | |
this.hd.startDocument(); | |
this.documentStarted = true; | |
} | |
} | |
private class Xml2JsonHandler extends DefaultHandler { | |
final Stack<Object> jStack = new Stack<>(); | |
final JsonObject json = new JsonObject(); | |
public Xml2JsonHandler() { | |
this.jStack.push(this.json); | |
} | |
/** | |
* @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, | |
* java.lang.String, java.lang.String) | |
*/ | |
@Override | |
public void endElement(final String uri, final String localName, final String qName) throws SAXException { | |
// Get rid of one element | |
this.jStack.pop(); | |
} | |
public final JsonObject getJson() { | |
return this.json; | |
} | |
/** | |
* @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, | |
* java.lang.String, java.lang.String, org.xml.sax.Attributes) | |
*/ | |
@Override | |
public void startElement(final String uri, final String localName, final String qName, | |
final Attributes attributes) | |
throws SAXException { | |
// We don't process the data cover element | |
if ("data".equals(qName)) { | |
return; | |
} | |
// Get name and value from the element. Value might be null | |
final String curName = attributes.getValue("name"); | |
final String curValueCandidate = attributes.getValue("value"); | |
final String curType = attributes.getValue("type"); | |
final Object curValue = this.extractValueWithType(curValueCandidate, curType); | |
// The current object on the stack | |
final Object o = this.jStack.peek(); | |
// Play through cases | |
// Parent is object and element has a value | |
if ((o instanceof JsonObject) && (curValue != null)) { | |
((JsonObject) o).put(curName, curValue); | |
this.jStack.push(o); | |
} else if ((o instanceof JsonObject) && (curValue == null) && "element".equals(qName)) { | |
final JsonObject jo = new JsonObject(); | |
((JsonObject) o).put(curName, jo); | |
this.jStack.push(jo); | |
} else if ((o instanceof JsonObject) && (curValue == null) && "array".equals(qName)) { | |
final JsonArray ja = new JsonArray(); | |
((JsonObject) o).put(curName, ja); | |
this.jStack.push(ja); | |
} else if ((o instanceof JsonArray) && (curValue != null)) { | |
((JsonArray) o).add(curValue); | |
this.jStack.push(o); | |
} else if ((o instanceof JsonArray) && (curValue == null) && "element".equals(qName)) { | |
final JsonObject jo = new JsonObject(); | |
((JsonArray) o).add(jo); | |
this.jStack.push(jo); | |
} else if ((o instanceof JsonArray) && (curValue == null) && "array".equals(qName)) { | |
final JsonArray ja = new JsonArray(); | |
((JsonArray) o).add(ja); | |
this.jStack.push(ja); | |
} | |
} | |
private Object extractValueWithType(String curValueCandidate, String curType) { | |
Object result = null; | |
try { | |
if (curType != null) { | |
switch (curType) { | |
case "Boolean": | |
result = Boolean.valueOf(curValueCandidate); | |
break; | |
case "Integer": | |
result = Integer.valueOf(curValueCandidate); | |
break; | |
case "Double": | |
result = Double.valueOf(curValueCandidate); | |
break; | |
case "Long": | |
result = Long.valueOf(curValueCandidate); | |
break; | |
default: | |
result = curValueCandidate; | |
break; | |
} | |
} | |
} catch (Throwable t) { | |
t.printStackTrace(); | |
} | |
return (result == null) ? curValueCandidate : result; | |
} | |
} | |
public static void main(final String[] args) throws Exception { | |
if (args.length < 1) { | |
System.err.println("Usage java net.wissel.json2xml.Main [filename]"); | |
System.exit(1); | |
} | |
final String fileName = args[0]; | |
final Json2XmlMain j2x = new Json2XmlMain(); | |
j2x.renderFile(fileName); | |
} | |
public void render(final InputStream in, final PrintStream out) | |
throws IOException, SAXException, TransformerConfigurationException, ParserConfigurationException { | |
// Get the JsonObject | |
final Scanner scanner = new Scanner(in); | |
final String source = scanner.useDelimiter("\\Z").next(); | |
scanner.close(); | |
in.close(); | |
final Buffer buffer = Buffer.buffer(source); | |
final JsonObject jo = new JsonObject(buffer); | |
jo.put("today", new Date().toString()); | |
// jo = this.createSample(); | |
out.println(jo.encodePrettily()); | |
out.println("-------------------------------------------------------------"); | |
final String xmlResult = this.json2xmlString(jo); | |
out.println(xmlResult); | |
out.println("-------------------------------------------------------------"); | |
final JsonObject jsonResult = this.xmlString2Json(xmlResult); | |
out.println(jsonResult.encodePrettily()); | |
} | |
private void extractValue(final String key, final Object value, final SimpleXMLDoc sd) throws Exception { | |
if (value instanceof JsonObject) { | |
final JsonObject nextJson = (JsonObject) value; | |
sd.openTag("element", "name", key); | |
this.parseToOutput(nextJson, sd); | |
sd.closeTag(1); | |
} else if (value instanceof JsonArray) { | |
final JsonArray oneArray = (JsonArray) value; | |
sd.openTag("array", "name", key); | |
oneArray.forEach(arrayElement -> { | |
try { | |
this.extractValue(key, arrayElement, sd); | |
} catch (final Exception e) { | |
e.printStackTrace(); | |
} | |
}); | |
sd.closeTag(1); | |
} else { | |
final Map<String, String> attributes = this.getAttributeMap(key, value); | |
sd.addEmptyTag("element", attributes); | |
} | |
} | |
private Map<String, String> getAttributeMap(String key, Object value) { | |
final Map<String, String> result = new HashMap<>(); | |
result.put("name", key); | |
result.put("value", String.valueOf(value)); | |
result.put("type", value.getClass().getSimpleName()); | |
return result; | |
} | |
private String json2xmlString(final JsonObject jo) throws SAXException, TransformerConfigurationException { | |
final SimpleXMLDoc sd = new SimpleXMLDoc(); | |
sd.openTag("data"); | |
this.parseToOutput(jo, sd); | |
sd.closeDocument(); | |
return sd.toString(); | |
} | |
private void parseToOutput(final JsonObject json, final SimpleXMLDoc sd) { | |
json.forEach(entry -> { | |
final String key = entry.getKey(); | |
final Object value = entry.getValue(); | |
try { | |
this.extractValue(key, value, sd); | |
} catch (final Exception e) { | |
e.printStackTrace(); | |
} | |
}); | |
} | |
private void renderFile(final String fileName) throws Exception { | |
final File file = new File(fileName); | |
if (!file.exists() || file.isDirectory()) { | |
System.err.println("File does not exist:" + fileName); | |
return; | |
} | |
final FileInputStream in = new FileInputStream(file); | |
this.render(in, System.out); | |
} | |
private JsonObject xmlString2Json(final String xmlResult) | |
throws SAXException, IOException, ParserConfigurationException { | |
final SAXParserFactory factory = SAXParserFactory.newInstance(); | |
final SAXParser saxParser = factory.newSAXParser(); | |
final Xml2JsonHandler dh = new Xml2JsonHandler(); | |
saxParser.parse(new ByteArrayInputStream(xmlResult.getBytes()), dh); | |
return dh.getJson(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment