您好,登錄后才能下訂單哦!
這篇文章主要介紹解析XML和JSON內容的技巧有哪些,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
在沒有統一標準的情況下,一個系統對接多個外部系統往往會遇到請求接口響應數據異構的情況,有可能返回的是XML,也有可能返回
JSON。除了返回類型不同,內容結構也不盡相同。以XML類型為例,
接口1返回內容
<root> <bizKey>16112638767472747178067</bizKey> <returnMsg>OK</returnMsg> <returnCode>200</returnCode> ... </root>
接口2返回內容
<root> <bid>16112638767472747178068</bid> <note>成功</note> <returnStatus>1</returnStatus> ... </root>
如果在我們系統中為每種格式的內容針對處理顯然是不合理的,上面的內容中我們只是關心三種信息,分別是業務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 Map<String,Object> parse(String param, Map<String,String> paths) throws Exception{ InputSource inputSource = new InputSource(new StringReader(param)); Document document = dbFactory.newDocumentBuilder().parse(inputSource); Map<String,Object> 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<String,String>
,暫且用Map<String,Object>
。
這一步稍稍有點麻煩,不過我們先不考慮代碼實現,反正你能想到的可能別人已經幫你實現了。首先我們根據接口文檔定義規則,寫出規則表達式(或者其他的什么),
又是表達式。假設接口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, Map<String,Object> 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, Map<String,Object> context) 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
緩存起來。
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函數或工具類,在模板中調用。
以上是“解析XML和JSON內容的技巧有哪些”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。