Java讀取多層級xml檔案

賢和兄發表於2017-10-23
       最近在做國際客服北京職場的專案,需要提供一個介面服務端的能力,也就是需要開發一個http+xml的協議,入參和出參均為Map格式,各系統間的請求或應答是以xml格式封裝的。在將返回報文(xml)解析為Map輸出時遇到一個難點:Java對於多層級xml的解析。現以一個客戶資料查詢介面為例將解析過程記錄如下:

返回xml報文的簡化形式:

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <ROOT>  
  3.       <HEAD>  
  4.             <ORIGIN_DOMAIN>kefuxitongbianma</ORIGIN_DOMAIN>  
  5.             <HOME_DOMAIN>CUGCRM</HOME_DOMAIN>  
  6.             <ACTION_CODE>1</ACTION_CODE>  
  7.             <BUSI_CODE>QUERYCUST</BUSI_CODE>  
  8.             <TRANS_ID>20160220160635123456</TRANS_ID>  
  9.             <RET_CODE>0000</RET_CODE>  
  10.             <RET_MSG>success</RET_MSG>  
  11.       </HEAD>  
  12.       <BODY>  
  13.             <TOTAL_RECORDS>20</TOTAL_RECORDS>  
  14.             <TOTAL_PAGE>10</TOTAL_PAGE>  
  15.             <CURRENT_PAGE>1</CURRENT_PAGE>  
  16.             <CUSTINFOLIST>  
  17.                   <CUSTINFO>  
  18.                         <CUST_TYPE>001</CUST_TYPE>  
  19.                         <VIP_FLAG>true</VIP_FLAG>  
  20.                   </CUSTINFO>  
  21.                   <CUSTINFO>  
  22.                         <CUST_TYPE>002</CUST_TYPE>  
  23.                         <VIP_FLAG>false</VIP_FLAG>  
  24.                   </CUSTINFO>  
  25.                   <CUSTINFO>  
  26.                         <CUST_TYPE>003</CUST_TYPE>  
  27.                         <VIP_FLAG>false</VIP_FLAG>  
  28.                   </CUSTINFO>  
  29.             </CUSTINFOLIST>  
  30.       </BODY>  
  31. </ROOT>  

[java] view plain copy
  1. import java.util.ArrayList;  
  2. import java.util.HashMap;  
  3. import java.util.List;  
  4. import java.util.Map;  
  5. import java.util.Set;  
  6. import net.sf.json.JSONObject;  
  7. import org.apache.log4j.Logger;  
  8. import org.dom4j.Document;  
  9. import org.dom4j.DocumentException;  
  10. import org.dom4j.DocumentHelper;  
  11. import org.dom4j.Element;  
  12. import org.dom4j.Namespace;  
  13. import org.dom4j.QName;  
  14. /** 
  15.  * 解析xml的工具類 
  16.  * 1、將多層級xml解析為Map 
  17.  * 2、將多層級xml解析為Json 
  18.  * 
  19.  * @author lmb 
  20.  * 
  21.  */  
  22. public class ParseXmlUtil {  
  23.         
  24.       public static Logger logger = Logger.getLogger(ParseXmlUtil.class);  
  25.       public static void main(String[] args) {   
  26.               // 獲取一個xml檔案   
  27.               String textFromFile = MyXmlUtil.XmlToString();  
  28.               //將xml解析為Map  
  29.               Map resultMap = xml2map(textFromFile);  
  30.               //將xml解析為Json  
  31.               String resultJson = xml2Json(textFromFile);  
  32.       }   
  33.         
  34.         
  35.       /** 
  36.        * 將xml格式響應報文解析為Json格式 
  37.        * @param responseXmlTemp 
  38.        * @return 
  39.        */  
  40.       public static String xml2Json(String responseXmlTemp) {  
  41.             Document doc = null;  
  42.             try {  
  43.                   doc = DocumentHelper.parseText(responseXmlTemp);  
  44.             } catch (DocumentException e) {  
  45.                   logger.error("parse text error : " + e);  
  46.             }  
  47.             Element rootElement = doc.getRootElement();  
  48.             Map<String,Object> mapXml = new HashMap<String,Object>();  
  49.             element2Map(mapXml,rootElement);  
  50.             String jsonXml = JSONObject.fromObject(mapXml).toString();  
  51.             System.out.println("Json >>> " + jsonXml);  
  52.             return jsonXml;  
  53.       }  
  54.       /** 
  55.        * 將xml格式響應報文解析為Map格式 
  56.        * @param responseXmlTemp 
  57.        * @param thirdXmlServiceBean 
  58.        * @return 
  59.        * @throws DocumentException 
  60.        */  
  61.       public static Map<String, Object> xml2map(String responseXmlTemp) {  
  62.             Document doc = null;  
  63.             try {  
  64.                   doc = DocumentHelper.parseText(responseXmlTemp);  
  65.             } catch (DocumentException e) {  
  66.                   logger.error("parse text error : " + e);  
  67.             }  
  68.             Element rootElement = doc.getRootElement();  
  69.             Map<String,Object> mapXml = new HashMap<String,Object>();  
  70.             element2Map(mapXml,rootElement);  
  71.             System.out.println("Map >>> " + mapXml);  
  72.             return mapXml;  
  73.       }  
  74.       /** 
  75.        * 使用遞迴呼叫將多層級xml轉為map 
  76.        * @param map 
  77.        * @param rootElement 
  78.        */  
  79.       public static void element2Map(Map<String, Object> map, Element rootElement) {  
  80.               
  81.             //獲得當前節點的子節點  
  82.             List<Element> elements = rootElement.elements();  
  83.             if (elements.size() == 0) {  
  84.                   //沒有子節點說明當前節點是葉子節點,直接取值  
  85.                   map.put(rootElement.getName(),rootElement.getText());  
  86.             }else if (elements.size() == 1) {  
  87.                   //只有一個子節點說明不用考慮list的情況,繼續遞迴  
  88.                   Map<String,Object> tempMap = new HashMap<String,Object>();  
  89.                   element2Map(tempMap,elements.get(0));  
  90.                   map.put(rootElement.getName(),tempMap);  
  91.             }else {  
  92.                   //多個子節點的話就要考慮list的情況了,特別是當多個子節點有名稱相同的欄位時  
  93.                   Map<String,Object> tempMap = new HashMap<String,Object>();  
  94.                   for (Element element : elements) {  
  95.                         tempMap.put(element.getName(),null);  
  96.                   }  
  97.                   Set<String> keySet = tempMap.keySet();  
  98.                   for (String string : keySet) {  
  99.                         Namespace namespace = elements.get(0).getNamespace();  
  100.                         List<Element> sameElements = rootElement.elements(new QName(string,namespace));  
  101.                         //如果同名的數目大於1則表示要構建list  
  102.                         if (sameElements.size() > 1) {  
  103.                               List<Map> list = new ArrayList<Map>();  
  104.                               for(Element element : sameElements){  
  105.                                     Map<String,Object> sameTempMap = new HashMap<String,Object>();  
  106.                                     element2Map(sameTempMap,element);  
  107.                                     list.add(sameTempMap);  
  108.                               }  
  109.                               map.put(string,list);  
  110.                         }else {  
  111.                               //同名的數量不大於1直接遞迴  
  112.                               Map<String,Object> sameTempMap = new HashMap<String,Object>();  
  113.                               element2Map(sameTempMap,sameElements.get(0));  
  114.                               map.put(string,sameTempMap);  
  115.                         }  
  116.                   }  
  117.             }  
  118.       }  
  119. }  

xml檔案讀取工具類:

[java] view plain copy
  1. import java.io.File;  
  2. import java.io.IOException;  
  3. import java.io.StringWriter;  
  4. import org.jdom.Document;  
  5. import org.jdom.input.SAXBuilder;  
  6. import org.jdom.output.Format;  
  7. import org.jdom.output.XMLOutputter;  
  8. /** 
  9.  * 讀取一個xml檔案返回string 
  10.  * @author lmb  
  11.  * 
  12.  */  
  13. public class MyXmlUtil {  
  14.       /** 
  15.        * 載入xml檔案 
  16.        * @return Document 
  17.        */  
  18.       public static Document load(){  
  19.             Document document=null;   
  20.         String url="E://2.xml";   
  21.         try {   
  22.             SAXBuilder reader = new SAXBuilder();    
  23.             document=reader.build(new File(url));   
  24.        } catch (Exception e) {   
  25.             e.printStackTrace();   
  26.        }   
  27.         return document;  
  28.       }  
  29.         
  30.       /** 
  31.        * 將xml檔案轉換為String串 
  32.        * @return 
  33.        */  
  34.       public static String XmlToString(){  
  35.             Document document=null;   
  36.         document=load();   
  37.            
  38.         Format format =Format.getPrettyFormat();       
  39.         format.setEncoding("UTF-8");//設定編碼格式    
  40.            
  41.         StringWriter out=null//輸出物件   
  42.         String sReturn =""//輸出字串   
  43.         XMLOutputter outputter =new XMLOutputter();    
  44.         out=new StringWriter();    
  45.         try {   
  46.            outputter.output(document,out);   
  47.         } catch (IOException e) {   
  48.            e.printStackTrace();   
  49.         }    
  50.         sReturn=out.toString();    
  51.         return sReturn;   
  52.     }   
  53. }  

控制檯列印結果:

[html] view plain copy
  1. Map >>> {BODY={TOTAL_RECORDS={TOTAL_RECORDS=20}, CUSTINFOLIST={CUSTINFO=[{CUST_TYPE={CUST_TYPE=001}, VIP_FLAG={VIP_FLAG=true}}, {CUST_TYPE={CUST_TYPE=002}, VIP_FLAG={VIP_FLAG=false}}, {CUST_TYPE={CUST_TYPE=003}, VIP_FLAG={VIP_FLAG=false}}]}, TOTAL_PAGE={TOTAL_PAGE=10}, CURRENT_PAGE={CURRENT_PAGE=1}}, HEAD={ACTION_CODE={ACTION_CODE=1}, ORIGIN_DOMAIN={ORIGIN_DOMAIN=kefuxit}, BUSI_CODE={BUSI_CODE=QUERYCUST}, HOME_DOMAIN={HOME_DOMAIN=CUGCRM}, TRANS_ID={TRANS_ID=20160220160635123456}, RET_MSG={RET_MSG=success}, RET_CODE={RET_CODE=0000}}}  
  2.   
  3. Json >>> {"BODY":{"TOTAL_RECORDS":{"TOTAL_RECORDS":"20"},"CUSTINFOLIST":{"CUSTINFO":[{"CUST_TYPE":{"CUST_TYPE":"001"},"VIP_FLAG":{"VIP_FLAG":"true"}},{"CUST_TYPE":{"CUST_TYPE":"002"},"VIP_FLAG":{"VIP_FLAG":"false"}},{"CUST_TYPE":{"CUST_TYPE":"003"},"VIP_FLAG":{"VIP_FLAG":"false"}}]},"TOTAL_PAGE":{"TOTAL_PAGE":"10"},"CURRENT_PAGE":{"CURRENT_PAGE":"1"}},"HEAD":{"ACTION_CODE":{"ACTION_CODE":"1"},"ORIGIN_DOMAIN":{"ORIGIN_DOMAIN":"kefuxit"},"BUSI_CODE":{"BUSI_CODE":"QUERYCUST"},"HOME_DOMAIN":{"HOME_DOMAIN":"CUGCRM"},"TRANS_ID":{"TRANS_ID":"20160220160635123456"},"RET_MSG":{"RET_MSG":"success"},"RET_CODE":{"RET_CODE":"0000"}}}  

格式化之後的結果如下:

[html] view plain copy
  1. <strong>map :</strong>  
  2. {  
  3.     BODY={  
  4.         TOTAL_RECORDS={TOTAL_RECORDS=20},  
  5.         CUSTINFOLIST={  
  6.             CUSTINFO=[  
  7.                 {  
  8.                     CUST_TYPE={CUST_TYPE=001},  
  9.                     VIP_FLAG={VIP_FLAG=true}  
  10.                 },  
  11.                 {  
  12.                     CUST_TYPE={CUST_TYPE=002},  
  13.                     VIP_FLAG={VIP_FLAG=false}  
  14.                 },  
  15.                 {  
  16.                     CUST_TYPE={CUST_TYPE=003},  
  17.                     VIP_FLAG={VIP_FLAG=false}  
  18.                 }  
  19.             ]  
  20.         },  
  21.         TOTAL_PAGE={TOTAL_PAGE=10},  
  22.         CURRENT_PAGE={CURRENT_PAGE=1}  
  23.     },  
  24.     HEAD={  
  25.         ACTION_CODE={ACTION_CODE=1},  
  26.         ORIGIN_DOMAIN={ORIGIN_DOMAIN=kefuxit},  
  27.         BUSI_CODE={BUSI_CODE=QUERYCUST},  
  28.         HOME_DOMAIN={HOME_DOMAIN=CUGCRM},  
  29.         TRANS_ID={TRANS_ID=20160220160635123456},  
  30.         RET_MSG={RET_MSG=success},  
  31.         RET_CODE={RET_CODE=0000}  
  32.     }  
  33. }  
  34.   
  35. <strong>Json:</strong>  
  36. {  
  37.     "BODY":{  
  38.         "TOTAL_RECORDS":{"TOTAL_RECORDS":"20"},  
  39.         "CUSTINFOLIST":{  
  40.             "CUSTINFO":[  
  41.                 {  
  42.                     "CUST_TYPE":{"CUST_TYPE":"001"},  
  43.                     "VIP_FLAG":{"VIP_FLAG":"true"}  
  44.                 },  
  45.                 {  
  46.                     "CUST_TYPE":{"CUST_TYPE":"002"},  
  47.                     "VIP_FLAG":{"VIP_FLAG":"false"}  
  48.                 },  
  49.                 {  
  50.                     "CUST_TYPE":{"CUST_TYPE":"003"},  
  51.                     "VIP_FLAG":{"VIP_FLAG":"false"}  
  52.                 }  
  53.             ]  
  54.         },  
  55.         "TOTAL_PAGE":{"TOTAL_PAGE":"10"},  
  56.         "CURRENT_PAGE":{"CURRENT_PAGE":"1"}  
  57.     },  
  58.     "HEAD":{  
  59.         "ACTION_CODE":{"ACTION_CODE":"1"},  
  60.         "ORIGIN_DOMAIN":{"ORIGIN_DOMAIN":"kefuxit"},  
  61.         "BUSI_CODE":{"BUSI_CODE":"QUERYCUST"},  
  62.         "HOME_DOMAIN":{"HOME_DOMAIN":"CUGCRM"},  
  63.         "TRANS_ID":{"TRANS_ID":"20160220160635123456"},  
  64.         "RET_MSG":{"RET_MSG":"success"},  
  65.         "RET_CODE":{"RET_CODE":"0000"}  
  66.     }  

相關文章