摘要:解析和內容的一點技巧概述在沒有統一標準的情況下,一個系統對接多個外部系統往往會遇到請求接口響應數據異構的情況,有可能返回的是,也有可能返回。解析內容也是同理的,只不過定義的是表達式。
解析XML和JSON內容的一點技巧 概述
在沒有統一標準的情況下,一個系統對接多個外部系統往往會遇到請求接口響應數據異構的情況,有可能返回的是XML,也有可能返回
JSON。除了返回類型不同,內容結構也不盡相同。以XML類型為例,
接口1返回內容
16112638767472747178067 OK 200 ...
接口2返回內容
16112638767472747178068 成功 1 ...
如果在我們系統中為每種格式的內容針對處理顯然是不合理的,上面的內容中我們只是關心三種信息,分別是業務ID、狀態值和描述信息,那么可不可以抽象這三種信息,
獲得這些信息后再進行業務邏輯處理。
根據業務抽象我們需要從XML或者JSON內容中獲得三種信息,我們這里將會使用XPath和JSONPath的方式來解析。比如獲得接口1的重要信息,
我們可以設定三個XPath表達式,
{ bid: "/root/bizKey", code: "/root/returnCode", description: "/root/returnMsg" }
bid,code和description對應我們系統自己定義的字段名。
解析JSON內容也是同理的,只不過定義的是JSONPath表達式。
假設我們從原始的XML和JSON數據中獲得了bid,code和description信息,
從接口1獲得
{ bid: "16112638767472747178067", code: "200", description: "OK" }
從接口2獲得
{ bid: "16112638767472747178068", code: "1", description: "成功" }
假設我們從接口1文檔獲知狀態值200表示請求成功,從接口2文檔獲知狀態值1表示請求成功,雖然他們都表示請求成功,但是我們還是不能
把他們原原本本地保存到我們的業務相關表中(當然這些響應數據還是需要保存到另外的記錄表中的,至少方便排查問題)。
假設我們的業務相關表是這樣設計的
字段名 | 類型 | 描述 |
---|---|---|
bid | string | 業務ID |
code | int | 狀態值,0=初始,1=請求中,2=成功,3=失敗 |
description | string | 描述 |
因此,我們還必須定義規則把接口1返回的狀態值200轉換為我們系統的2,把接口2返回的狀態值1轉換為我們系統的2。
總結一下,兩步走解析XML和JSON數據內容
根據XPath或者JSONPath表達式解析獲得重要信息
根據規則轉換狀態值
第一步解析數據獲得重要信息以XML為例,
public class XmlParseUtils { private DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); private XPathFactory xpathFactory = XPathFactory.newInstance(); /** * * @param param 數據內容 * @param paths 表達式 * @return * @throws Exception */ public Mapparse(String param, Map paths) throws Exception{ InputSource inputSource = new InputSource(new StringReader(param)); Document document = dbFactory.newDocumentBuilder().parse(inputSource); Map map = Maps.newHashMap(); for(String key : paths.keySet()) { XPath xpath = xpathFactory.newXPath(); Node node = (Node) xpath.evaluate(paths.get(key), document, XPathConstants.NODE); if(node == null) { throw new Exception("node not found, xpath is " + paths.get(key)); } map.put(key, node.getTextContent()); } return map; } }
parse函數的返回類型也可以是Map
這一步稍稍有點麻煩,不過我們先不考慮代碼實現,反正你能想到的可能別人已經幫你實現了。首先我們根據接口文檔定義規則,寫出規則表達式(或者其他的什么),
又是表達式。假設接口1的返回的狀態值比較簡單,只有200表示成功,其他情況都是失敗,那么我們可以這樣定義規則,
code.equals("200") ? 2: 3
或者
<#if code == "200"> 2 <#else> 3 <#/if>
亦或者
function handle(arg) { if(arg == 200) { return 2; } return 3; } handle(${code})
以上根據同一份文檔定義了三種不同類型的狀態值轉換規則,肯定需要三種不同的實現。下面一一說明,
三目表達式code.equals("200") ? 2: 3是一個三目表達式,我們將使用jexl引擎來解析,利用第一步解析數據獲得重要信息的結果,我們可以這樣做
public Object evaluateByJexl(String expression, MapFreeMarker模板context) { JexlEngine jexl = new JexlBuilder().create(); JexlExpression e = jexl.createExpression(expression); JexlContext jc = new MapContext(context); return e.evaluate(jc); }
<#if code == "200"> 2 <#else> 3 <#/if>
處理這段模板我們可以這么做
/** * * @param param FreeMarker模板 * @param context * @return * @throws Exception */ public String render(String param, Mapcontext) throws Exception { Configuration cfg = new Configuration(); StringTemplateLoader stringLoader = new StringTemplateLoader(); stringLoader.putTemplate("myTemplate",param); cfg.setTemplateLoader(stringLoader); Template template = cfg.getTemplate("myTemplate","utf-8"); StringWriter writer = new StringWriter(); template.process(context, writer); return writer.toString(); }
如果FreeMarker模板比較復雜,從模板預編譯成Template可能會消耗更多的性能,就要考慮把Template緩存起來。
JavaScript代碼段function handle(arg) { if(arg == 200) { return 2; } return 3; } handle(${code})
這段js代碼中存在${code},首先它需要使用FreeMarker渲染得到真正的handle方法的調用參數,然后
public Object evaluate(String expression) throws Exception { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine engine = manager.getEngineByName("javascript"); return engine.eval(expression); }
ScriptEngineManager的性能估計不太樂觀,畢竟是一個語言的引擎。
不同轉換規則實現的比較類型 | 實現 | 優點 | 缺點 |
---|---|---|---|
三目表達式 | Jexl | 簡單(easy) | 簡單(simple) |
FreeMarker模板 | FreeMarker | -- | -- |
JavaScript代碼段 | FreeMarker + ScriptEngine | 直觀 | 過程復雜,性能問題 |
看起來Freemarker是一個不錯的選擇。
至此兩步走小技巧已經實現了,都是利用了現成的代碼實現。
或許我們會這樣的挑戰,在做狀態值轉換時需要知道當前系統某個業務狀態值的情況,
此時Freemarker表達式可能是這樣的,
<# assign lastCode = GetLastCode(code)> <#if lastCode == "2"> 2 <#elseif code == "200"> 2 <#else> 3 <#/if>
這里我們可以使用Freemarker的特性,自定義Java函數或工具類,在模板中調用。
代碼地址https://github.com/Honwhy/xml...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66263.html
摘要:解析和內容的一點技巧概述在沒有統一標準的情況下,一個系統對接多個外部系統往往會遇到請求接口響應數據異構的情況,有可能返回的是,也有可能返回。解析內容也是同理的,只不過定義的是表達式。 解析XML和JSON內容的一點技巧 概述 在沒有統一標準的情況下,一個系統對接多個外部系統往往會遇到請求接口響應數據異構的情況,有可能返回的是XML,也有可能返回JSON。除了返回類型不同,內容結構也不盡...
摘要:使用的思考使用過對象的程序員最常做的一項工作便是,將對象轉化為字符串。該字符串的用途很多,例如可以使用在的中,在多個頁面間進行傳遞。因為模式是固定的,那么定義模式的空間開銷一定比使用該模式生成字符串的時間開銷代價要小很多。 使用JSON.stringify的思考 使用過JSON對象的程序員最常做的一項工作便是,將JSON對象轉化為字符串。該字符串的用途很多,例如可以使用在WEB的URL...
摘要:學編程真的不是一件容易的事不管你多喜歡或是多會編程,在學習和解決問題上總會碰到障礙。熟練掌握核心內容,特別是和多線程初步具備面向對象設計和編程的能力掌握基本的優化策略。 學Java編程真的不是一件容易的事,不管你多喜歡或是多會Java編程,在學習和解決問題上總會碰到障礙。工作的時間越久就越能明白這個道理。不過這倒是一個讓人進步的機會,因為你要一直不斷的學習才能很好的解決你面前的難題...
閱讀 1911·2021-09-23 11:21
閱讀 1699·2019-08-29 17:27
閱讀 1056·2019-08-29 17:03
閱讀 724·2019-08-29 15:07
閱讀 1920·2019-08-29 11:13
閱讀 2379·2019-08-26 12:14
閱讀 919·2019-08-26 11:52
閱讀 1732·2019-08-23 17:09