2

I have a camel route that converts documents from JSON to XML; the XML must be valid regarding a schema which is defined in XSD. Currently, the conversion is done with camel-xmljson (and I have some custom java processing for the list types).

The only thing that does not match the schema is the sequence of elements as the conversion changes the order to alphabetical because JSON per definition does not care about order. Since several document types that are subject to change need to be converted, it is important that the conversion and subsequent processing is as generic as possible (I'd like it to work with only XSD files and not with classes generated from XSD).

So, I'm looking for a way to convert to the valid XML from JSON and XSD or a way to change the sequence of XML elements to match the definition from the XSD. Can anybody point something out?

Namphibian
  • 12,046
  • 7
  • 46
  • 76
fred-d
  • 21
  • 1
  • 4
  • Hi welcome to the site. See this link for using XSLT to convert JSON to XML. This might be something that can point you in the right direction.https://stackoverflow.com/questions/13007280/how-to-convert-json-to-xml-using-xslt – Namphibian Aug 21 '18 at 23:58
  • Thanks. Unfortunately, it does not have a complete solution and I lack the XSLT expertise to do that. – fred-d Aug 22 '18 at 07:43

1 Answers1

0

JSON does not care about order in objects (key-value pairs) but it does in arrays, so maybe you should use JSON array where the order matters. Anyway, you can do that kind of JSON/XML transformation with standard XSLT 3.0 which introduced functions for JSON-to-XML and XML-to-JSON conversion. In Java, the SAXON XSLT library supports them (in all editions including the free one) since v9.7.

Here is an excerpt from a XSLT stylesheet applying transformation from JSON input (link to full XSLT ):

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.w3.org/2005/xpath-functions" expand-text="yes"
    xmlns:my-prefix="urn:the:namespace:of:my:xsd">
    <!-- Reference example for JSON to XML transformation: https://www.saxonica.com/papers/xmlprague-2016mhk.pdf -->
    <!-- expand-text option allows to use text value templates in XSLT 3.0 -->
    <xsl:output encoding="UTF-8" indent="yes" method="xml" />

    <xsl:template name="xsl:initial-template">
        <xsl:apply-templates select="json-to-xml(.)" />
    </xsl:template>

<!-- This is just an example of applying a template when matching some key from JSON. --> 
    <xsl:template match="map[@key='key_of_something_to_change']">
        <!-- Fill in whith whatever transformation you want to apply in this case. Plenty of examples to change order of XML elements, such as:
         https://stackoverflow.com/questions/37442799/xslt-change-element-order
          -->
        ...
    </xsl:template>
...

</xsl:stylesheet>

Then some sample code to use that XSLT from Java, assuming that SAXON XSLT >= 9.7 is on your classpath (this example takes input JSON as a String and outputs the result to System.out just for testing but you can adapt to handle other kinds of input/output with SAXON API easily):

import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmAtomicValue;
import net.sf.saxon.s9api.Xslt30Transformer;
import net.sf.saxon.s9api.XsltExecutable;
import net.sf.saxon.trace.XSLTTraceListener;

...

    private static final XsltExecutable JSON_TO_XML_XSLT_EXEC;
    static
    {
        try
        {
            final Processor xsltProc = new Processor(false);
            JSON_TO_XML_XSLT_EXEC = xsltProc.newXsltCompiler().compile(new StreamSource(new File("/path/to/my/xslt/stylesheet/file"));
        }
        catch (final SaxonApiException e)
        {
            throw new RuntimeException("Cannot create XSLT processor for my stylesheet", e);
        }
   }

   private static void convertJsonToXml(final String inputJson, final Path outXmlFile)
    {
        final Xslt30Transformer xslt = JSON_TO_XML_XSLT_EXEC.load30();
        /*
         * Line below is useful for debugging, esp. to see what the output from the json-to-xml function looks like before further processing. Else remove it.
         */
        xslt.setTraceListener(new XSLTTraceListener());

        try
        {
            xslt.setGlobalContextItem(new XdmAtomicValue(inputJson));
            /*
             * Call default template "xsl:initial-template"
             */
            xslt.callTemplate(null, xslt.newSerializer(System.out));
        }
        catch (final SaxonApiException e)
        {
            throw new RuntimeException("Failed to apply XSLT", e);
        }
   }
cdan
  • 3,470
  • 13
  • 27
  • Regarding the use of JSON array where the order matters: This would entail changes at too many other systems relying on the format. The linked XSLT doesn't create elements in the generated xml or am I missing something? – fred-d Aug 23 '18 at 12:35
  • The linked XSLT on github I mentioned is for a specific use case, and yes it does create XML elements in the XACML namespace ([XACML schema](https://docs.oasis-open.org/xacml/3.0/XSD/)). Whenever you see a `` in there, it is an output XML element. Actually, in general, any element that is not in the XSL namespace should be output. – cdan Aug 23 '18 at 23:34