通过映射关系 动态转义为统一格式的数据 (支持 JSON 和 XML )
在很多的时候 我们都会 需要 将不同格式的数据 转换为 统一的数据格式
比如 将Json 源数据
{ "b": [ { "c": "reference", "a": "atliwen", "t": "Sayings of the Century", "p": 8.95 } ] }
转换为
<book>
<category>reference</category>
<author>atliwen</author>
<title>Sayings of the Century</title>
<price>8.95</price>
<remark>种类:reference | 作者:atliwen | 标题:Sayings of the Century |定 价:8.95</remark>
<type>1</type>
<default>默认数据</default>
</book>
由于客户提供的数据源格式不确定 或 其他服务提供的数据格式是我们需要的, 那么通常的做法是 为每个客户或服务 提供的数据 都写一遍 数据的转换 方法
存在的问题是:
如果客户或服务很多 , 而且还在不停的增长 。 我们将会不挺的 写 数据转换的方法
需求:
一个统一的转换数据的方法, 只需要配置一下字段映射关系 就可以 接收不同结构的数据 自动转换为统一的数据结构。 不需要我们写任何代码。
根据 这个需求,我通过 XML 的 Xpath 和 JSON 第三方的 jsonPath 写出了这个统一转换数据结构的方法
package com.thoth.Conversion; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.internal.JsonContext; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.List; public class OrderToXmlOrder { /** * 将下单数据 转换 成EDI 数据 * * @param order 订单数据 * @param User 用户配置数据 * @return * @throws Exception */ public static String outEdiOrder(String order, String User, Integer type) throws Exception { Long startLong = System.currentTimeMillis(); Document ediUserDocument = DocumentHelper.parseText(User);// 用户配置数据 Element ediUserRoot = ediUserDocument.getRootElement(); Element Edi = DocumentHelper.createDocument().addElement(ediUserRoot.getName());// 数据 // Out(order, Edi, ediUserRoot, type); System.out.println("时间:" + (System.currentTimeMillis() - startLong)); return Edi.asXML(); } /** * 根据 用户配置节点 自动从数据源 查找数据 生成 EDI 数据节点 * * @param order 数据源 * @param Edi EDI 数据节点 * @param requestorders 用户配置节点 * @param type 1 是 Xml 2 是 json */ public static void Out(String order, Element Edi, Element requestorders, Integer type) throws DocumentException { // Xml 值 <![CDATA[444]]> List<Element> listElements = requestorders.elements(); Document orderDocument = DocumentHelper.createDocument(); DocumentContext de = new JsonContext(); if (type == 1) { orderDocument = DocumentHelper.parseText(order);// 订单数据 } else { de = JsonPath.parse(order); } for (Element e : listElements) { getEdiXml(Edi, type, orderDocument, de, e); } } /** * 获取 数据源转换成 Edi 的XML * * @param Edi EDI Xml * @param type type 1 是 Xml 2 是 json * @param orderDocument Xml 数据 源 * @param de JSON 数据源 * @param e 映射数据 */ private static void getEdiXml(Element Edi, Integer type, Document orderDocument, DocumentContext de, Element e) { // 是否有下级节点 if (e.nodeCount() != 1) return; String TestValuse = e.getTextTrim(); if (TestValuse == null || TestValuse == "") return; //default_ 默认值 如果映射表达式 前缀 为default_ 那么 后面的 直接赋值 if (TestValuse.contains("default_")) { Edi.addElement(e.getName()).addText(TestValuse.replace("default_", "")); return; } String text = ""; String[] strings = TestValuse.split(":"); if (strings.length > 1) { text = strings[0] + " : "; TestValuse = strings[1]; } // 获取 字段值 List<String> nodesString = getStrings(type, orderDocument, de, TestValuse); // 表达式 判断是否 有 //Udf23[text()=N] Udf23 节点的值等于 N if ("type".equals(e.getName().trim())) { if (nodesString.size() == 0) { Edi.addElement(e.getName()).addText("0"); return; } Edi.addElement(e.getName()).addText("1"); return; } orElement(Edi, e, text, nodesString); } /** * EDI Xml 字段值 生成 * * @param Edi Edi Xml * @param e * @param text * @param nodesString */ private static void orElement(Element Edi, Element e, String text, List<String> nodesString) { if (nodesString.size() > 1) { for (String et : nodesString) text = text + "," + et; text = text.substring(1, text.length()); } else text = text + nodesString.get(0); Element element = Edi.element(e.getName()); if (element != null) { if (StringUtils.isEmpty(element.getText())) { element.addText(text.trim()); } else { element.addText(" | " + text.trim()); } } else { Edi.addElement(e.getName()).addText(text.trim()); } } /** * 赋值 * * @param type * @param orderDocument * @param de * @param testValuse * @return */ private static List<String> getStrings(Integer type, Document orderDocument, DocumentContext de, String testValuse) { List<String> nodesString = new ArrayList<>(); if (type == 1) { List<Element> nodesList = orderDocument.selectNodes(testValuse); if (nodesList.size() > 0) { for (Element ea : nodesList) nodesString.add(ea.getTextTrim()); } } else { try { List<Object> list= de.read(testValuse); for (Object o:list) nodesString.add(o.toString()); } catch (Exception ea) { Object o=de.read(testValuse); nodesString.add(o.toString()); } } return nodesString; } }
测试 JSON
/** * 通过 映射 将 json 结构转换为统一的 Xml 结构 * @throws Exception */ @Test public void jsonToXml() throws Exception { //{ // b: [ // { // c: "reference", // a: "atliwen", // t: "SayingsoftheCentury", // p: 8.95 // } // ] //} String json ="{\"b\":[{\"c\":\"reference\",\"a\":\"atliwen\",\"t\":\"SayingsoftheCentury\",\"p\":8.95}]}"; //<book> // <category>$.b..c</category> // <author>$.b..a</author> // <title>$.b..t</title> // <price>$.b..p</price> // <remark>种类:$.b..c</remark> // <remark>作者:$.b..a</remark> // <remark>标题:$.b..t</remark> // <remark>定价:$.b..p</remark> // <type><![CDATA[$.b.[?(@.p>100)]]]></type> // <default>default_默认数据</default> //</book> String userMapper="<book><category>$.b..c</category><author>$.b..a</author><title>$.b..t</title><price>$.b..p</price><remark>种类:$.b..c</remark><remark>作者:$.b..a</remark><remark>标题:$.b..t</remark><remark>定价:$.b..p</remark><type><![CDATA[$.b.[?(@.p>100)]]]></type><default>default_默认数据</default> </book>"; String out= OrderToXmlOrder.outEdiOrder(json,userMapper,2); System.out.println(out); //<book> // <category>reference</category> // <author>atliwen</author> // <title>SayingsoftheCentury</title> // <price>8.95</price> // <remark>种类 : reference | 作者 : atliwen | 标题 : SayingsoftheCentury | 定价 : 8.95</remark> // <type>0</type> // <default>默认数据</default> //</book> }
测试XML
@Test public void XmlToOrderXml() throws Exception { //<b> // <c>reference</c> // <a>atliwen</a> // <t>SayingsoftheCentury</t> // <p>8.95</p> //</b> String xml= "<b><c>reference</c><a>atliwen</a><t>SayingsoftheCentury</t><p>8.95</p></b>"; //<book> // <category>//c</category> // <author>//a</author> // <title>//t</title> // <price>//p</price> // <remark>种类://c</remark> // <remark>作者://a</remark> // <remark>标题://t</remark> // <remark>定价://p</remark> // <type><![CDATA[//p[text()>100]]]></type> // <default>default_默认数据</default> //</book> String userMapper="<book><category>//c</category><author>//a</author><title>//t</title><price>//p</price><remark>种类://c</remark><remark>作者://a</remark><remark>标题://t</remark><remark>定价://p</remark><type><![CDATA[//p[text()>100]]]></type><default>default_默认数据</default></book>"; String out= OrderToXmlOrder.outEdiOrder(xml,userMapper,1); System.out.println(out); //<book> // <category>reference</category> // <author>atliwen</author> // <title>SayingsoftheCentury</title> // <price>8.95</price> // <remark>种类 : reference | 作者 : atliwen | 标题 : SayingsoftheCentury | 定价 : 8.95</remark> // <type>0</type> // <default>默认数据</default> //</book> }
当前代码还未在正式环境使用, 可能会有 异常。 请注意!