工作中的坑——dom4j解析含有命名空間的XML的坑

雖然網上有很多類似的文章,可都描述的不是特別清楚且都是很老的文章了,讓人走很多彎路,這裏完整記錄下。

說在前面

網上大多數分析的帖子都說dom4j解析xml性能最好,所以在碰到實際業務場景中就着手使用dom4j來解析xml了。

在業務場景中解析xml基本上兩種,一種是配置,另一種是調用外部項目接口反饋的xml。前者這裏不多說,自己的配置隨心所欲,通常xml的結構也相對比較簡單。而後者就比較糟心了,比如我遇到的,一邊接對應的接口一邊不停的吐槽,淚崩中啊。

至於dom4j如何使用和一些基本概念,這裏就不過多描述,網上隨便一搜就是一大堆。

這裏主要說下解析含有命名空間的XML。

具體實現

先看要我要解析的XML格式,如下截圖,其實也不是很複雜:

截圖1

在瞭解完dom4j基本概念之後,我就開始着手開發了,發現在獲取完根節點之後,我需要遞歸幾次才能獲取我需要的record這個節點,顯然比較麻煩。

於是繼續google發現可以使用selectNode(xpath)的方式來直接獲取,這個纔是我想要的。

原以爲幾行代碼輕鬆搞定,可最後發現selectNode始終獲取不到對應的節點,起初還以爲是我的路徑有問題,後來才知道dom4j不能識別帶命名空間的節點,所以在讀取帶命名空間的XML時,要在每個節點前加上命名空間。

好吧,我只想安安靜靜地解析個XML,居然這麼繞,頓時心裏又在吐槽這個接口本身了,非要用什麼webservice返回個xml,http+json多好呀。

吐槽歸吐槽,接還是得接啊,網上找些資料之後也大致明白,只要在節點前加上命名空間即可。

可好事多磨啊,我接的那個接口居然有兩個命名空間,soapenvresponse兩個節點上都有,好吧,我忍。

大體思路就是,先獲取根節點,取到對應的命名空間,然後selectSingleNode到response這個節點取第二個命名空間,最後再組裝xpath取到自己想要的節點。核心代碼如下:

Document doc = XmlUtil.strToDocument(responseStr);

Map map = new HashMap();
// 獲得命名空間
String firstUrl = doc.getRootElement().getNamespaceURI();
map.put("firstUrl", firstUrl);

XPath x = doc.createXPath("//firstUrl:Body");
x.setNamespaceURIs(map);
//獲取第二層xml的命名空間
String secendUrl = ((Element) x.selectSingleNode(doc)).element("response").getNamespaceURI();

map.put("secendUrl", secendUrl);

x = doc.createXPath("//firstUrl:Body/secendUrl:response/"
        + "secendUrl:responseBody/secendUrl:records/secendUrl:record");
x.setNamespaceURIs(map);

List<Element> nodes = x.selectNodes(doc);

說在後面

在開發一段時間的java之後,突然開始懷念起 .net了,尤其在處理一些細節方面的時候,總感覺java有點囉嗦,明明可以一行代碼搞定的事情,需要寫個三四行。

java10終於支持var關鍵字了,java11要開始收費了,不懂是福還是禍啊~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章