首页 > 解决方案 > 从 JSON 转换为 XML XSD 有效(使用 Apache Camel 或 Java)

问题描述

我有一条骆驼路线,可以将文档从 JSON 转换为 XML;对于 XSD 中定义的模式,XML 必须是有效的。目前,转换是使用 camel-xmljson完成的 (我有一些针对列表类型的自定义 java 处理)。

唯一不匹配架构的是元素序列,因为转换将顺序更改为字母顺序,因为每个定义的 JSON 不关心顺序。由于需要转换几种可能发生变化的文档类型,因此转换和后续处理尽可能通用是很重要的(我希望它仅适用于 XSD 文件,而不适用于从 XSD 生成的类)。

因此,我正在寻找一种从 JSON 和 XSD 转换为有效 XML 的方法,或者一种改变 XML 元素序列以匹配 XSD 定义的方法。有人能指出点什么吗?

标签: javaxmlxsdapache-camel

解决方案


JSON 不关心对象(键值对)中的顺序,但它关心数组中的顺序,所以也许您应该在顺序重要的地方使用 JSON 数组。无论如何,您可以使用标准 XSLT 3.0 进行这种 JSON/XML 转换,该标准引入了 JSON 到 XML 和 XML 到 JSON 转换的功能。在 Java 中,自 v9.7 起,SAXON XSLT 库就支持它们(包括免费版本在内的所有版本)。

以下是从 JSON 输入应用转换的 XSLT 样式表的摘录(链接到完整的 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>

然后是一些示例代码以使用 Java 中的 XSLT,假设 SAXON XSLT >= 9.7 在您的类路径上(此示例将输入 JSON 作为字符串并将结果输出到 System.out 仅用于测试,但您可以适应处理其他类型使用 SAXON API 轻松实现输入/输出):

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);
        }
   }

推荐阅读