Project

Profile

Help

RE: JSON-XML round trip using java API ยป JsonXmlRoundTrip_main.java

Rob Brown, 2022-05-21 20:42

 
package saxon.demo;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.transform.dom.DOMSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import net.sf.saxon.Configuration;
import net.sf.saxon.dom.NodeOverNodeInfo;
import net.sf.saxon.event.PipelineConfiguration;
import net.sf.saxon.expr.XPathContextMajor;
import net.sf.saxon.expr.instruct.Executable;
import net.sf.saxon.expr.parser.ExplicitLocation;
import net.sf.saxon.ma.json.JsonHandlerXML;
import net.sf.saxon.ma.json.JsonParser;
import net.sf.saxon.ma.json.JsonReceiver;
import net.sf.saxon.om.Item;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.Serializer;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.tiny.TinyDocumentImpl;

public class JsonXmlRoundTrip_main {

public static void main(String[] args) {
Logger logger = Logger.getAnonymousLogger();
String json = "{\"foo\":\"bar\"}";

Element convertedElement = convertJsonToXml(json, logger);
if (convertedElement == null) {
return;
}
String markup = serializeToString(convertedElement, logger);
System.out.println("convertedElement:");
System.out.println(markup);

String convertedJson = convertXmlToJson(convertedElement, logger);
if (convertedJson == null) {
return;
}
System.out.println("convertedJson:");
System.out.println(convertedJson);

System.out.println("compare json:");
System.out.println(json.equals(convertedJson));
}

private static Element convertJsonToXml(String json, Logger logger) {
//adapted from saxon JsonToXMLFn
JsonParser parser = new JsonParser();
int flags = 0;
// Map<String, Sequence> checkedOptions = null;
// if (options != null) {
// checkedOptions = getDetails().optionDetails.processSuppliedOptions(options, context);
// flags = JsonParser.getFlags(checkedOptions, true, context.getController().getExecutable().isSchemaAware());
// if ((flags & JsonParser.DUPLICATES_LAST) != 0) {
// throw new XPathException("json-to-xml: duplicates=use-last is not allowed", "FOJS0005");
// }
// if ((flags & JsonParser.DUPLICATES_SPECIFIED) == 0) {
// if ((flags & JsonParser.VALIDATE) != 0) {
// flags |= JsonParser.DUPLICATES_REJECTED;
// } else {
// flags |= JsonParser.DUPLICATES_RETAINED;
// }
// }
// } else {
flags = JsonParser.DUPLICATES_RETAINED;
// }

Processor proc = new Processor(false);
XPathContextMajor context = createDisposableXpathContext(proc);
String baseUri = null;
try {
JsonHandlerXML handler = new JsonHandlerXML(context, baseUri, flags);
// if (options != null) {
// handler.setFallbackFunction(checkedOptions, context);
// }
parser.parse(json, flags, handler, context);
Item<?> resultItem = handler.getResult();
if (resultItem instanceof TinyDocumentImpl) {
Node domNode = convertTinyDocToDom((TinyDocumentImpl)resultItem);
if (domNode instanceof Document) {
return ((Document)domNode).getDocumentElement();
} else if (domNode instanceof Element) {
return (Element)domNode;
}
}
logger.severe("unable to convert JSON to XML");
return null;
} catch (XPathException e) {
logger.log(Level.SEVERE, "an error occurred while converting JSON to XML", e);
return null;
}
}

private static String convertXmlToJson(Node node, Logger logger) {
//adapted from saxon XMLToJsonFn

Processor proc = new Processor(false);
XdmNode item = proc.newDocumentBuilder().wrap(node);
XPathContextMajor context = createDisposableXpathContext(proc);
PipelineConfiguration pipe = context.getController().makePipelineConfiguration();
pipe.setXPathContext(context);
JsonReceiver receiver = new JsonReceiver(pipe);
receiver.setIndenting(true);
// if (options.numberFormatter != null) {
// receiver.setNumberFormatter(options.numberFormatter);
// }
// Receiver r = receiver;
// if (xml.getNodeKind() == Type.DOCUMENT) {
// r = new DocumentValidator(r, "FOJS0006");
// }

try {
receiver.open();
//this causes IllegalStateException in JsonReceiver
item.getUnderlyingNode().copy(
receiver,
0,
new ExplicitLocation(null, -1, -1));
receiver.close();
return receiver.getJsonString();
} catch (XPathException e) {
logger.log(Level.SEVERE, "unable to convert XML to JSON", e);
return null;
}
}
private static XPathContextMajor createDisposableXpathContext(Processor proc) {
Executable exec = new Executable(proc.getUnderlyingConfiguration());
return new XPathContextMajor(null, exec);
}

private static String serializeToString(
Node node,
Logger logger) {
Configuration config = new Configuration();
Processor processor = new Processor(config);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Serializer serializer = processor.newSerializer(baos);
boolean success = serialize(
node,
processor.newDocumentBuilder(),
serializer,
logger);
if (success) {
return new String(baos.toByteArray(), StandardCharsets.UTF_8);
} else {
return null;
}
}

private static boolean serialize(
Node node,
DocumentBuilder docBldr,
Serializer serializer,
Logger logger) {
try {
XdmNode xdmNode = docBldr.build(new DOMSource(node));
serializer.setOutputProperty(Serializer.Property.INDENT, "yes");
serializer.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes");
serializer.setOutputProperty(Serializer.Property.ENCODING, "UTF-8");
serializer.serializeNode(xdmNode);
return true;
} catch (SaxonApiException e) {
logger.log(Level.SEVERE, "an error occurred while saving data", e);
return false;
}
}

private static Node convertTinyDocToDom(TinyDocumentImpl tinyDoc) {
//saxon no longer implements w3 dom in TinyTree, so NodeOverNodeInfo
//provides a read-only w3 dom api over tiny node
//https://www.saxonica.com/documentation9.5/changes/v8.3/external-object-models.html
return NodeOverNodeInfo.wrap(tinyDoc.getRootNode());
}
}
    (1-1/1)