天天看點

Java讀取多層級xml檔案

         最近在做國際客服北京職場的項目,需要提供一個接口服務端的能力,也就是需要開發一個http+xml的協定,入參和出參均為Map格式,各系統間的請求或應答是以xml格式封裝的。在将傳回封包(xml)解析為Map輸出時遇到一個難點:Java對于多層級xml的解析。現以一個客戶資料查詢接口為例将解析過程記錄如下:

傳回xml封包的簡化形式:

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
      <HEAD>
            <ORIGIN_DOMAIN>kefuxitongbianma</ORIGIN_DOMAIN>
            <HOME_DOMAIN>CUGCRM</HOME_DOMAIN>
            <ACTION_CODE>1</ACTION_CODE>
            <BUSI_CODE>QUERYCUST</BUSI_CODE>
            <TRANS_ID>20160220160635123456</TRANS_ID>
            <RET_CODE>0000</RET_CODE>
            <RET_MSG>success</RET_MSG>
      </HEAD>
      <BODY>
            <TOTAL_RECORDS>20</TOTAL_RECORDS>
            <TOTAL_PAGE>10</TOTAL_PAGE>
            <CURRENT_PAGE>1</CURRENT_PAGE>
            <CUSTINFOLIST>
                  <CUSTINFO>
                        <CUST_TYPE>001</CUST_TYPE>
                        <VIP_FLAG>true</VIP_FLAG>
                  </CUSTINFO>
                  <CUSTINFO>
                        <CUST_TYPE>002</CUST_TYPE>
                        <VIP_FLAG>false</VIP_FLAG>
                  </CUSTINFO>
                  <CUSTINFO>
                        <CUST_TYPE>003</CUST_TYPE>
                        <VIP_FLAG>false</VIP_FLAG>
                  </CUSTINFO>
            </CUSTINFOLIST>
      </BODY>
</ROOT>
           
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
/**
 * 解析xml的工具類
 * 1、将多層級xml解析為Map
 * 2、将多層級xml解析為Json
 *
 * @author lmb
 *
 */
public class ParseXmlUtil {
      
      public static Logger logger = Logger.getLogger(ParseXmlUtil.class);
      public static void main(String[] args) { 
              // 擷取一個xml檔案 
              String textFromFile = MyXmlUtil.XmlToString();
              //将xml解析為Map
              Map resultMap = xml2map(textFromFile);
              //将xml解析為Json
              String resultJson = xml2Json(textFromFile);
      } 
      
      
      /**
       * 将xml格式響應封包解析為Json格式
       * @param responseXmlTemp
       * @return
       */
      public static String xml2Json(String responseXmlTemp) {
            Document doc = null;
            try {
                  doc = DocumentHelper.parseText(responseXmlTemp);
            } catch (DocumentException e) {
                  logger.error("parse text error : " + e);
            }
            Element rootElement = doc.getRootElement();
            Map<String,Object> mapXml = new HashMap<String,Object>();
            element2Map(mapXml,rootElement);
            String jsonXml = JSONObject.fromObject(mapXml).toString();
            System.out.println("Json >>> " + jsonXml);
            return jsonXml;
      }
      /**
       * 将xml格式響應封包解析為Map格式
       * @param responseXmlTemp
       * @param thirdXmlServiceBean
       * @return
       * @throws DocumentException
       */
      public static Map<String, Object> xml2map(String responseXmlTemp) {
            Document doc = null;
            try {
                  doc = DocumentHelper.parseText(responseXmlTemp);
            } catch (DocumentException e) {
                  logger.error("parse text error : " + e);
            }
            Element rootElement = doc.getRootElement();
            Map<String,Object> mapXml = new HashMap<String,Object>();
            element2Map(mapXml,rootElement);
            System.out.println("Map >>> " + mapXml);
            return mapXml;
      }
      /**
       * 使用遞歸調用将多層級xml轉為map
       * @param map
       * @param rootElement
       */
      public static void element2Map(Map<String, Object> map, Element rootElement) {
            
            //獲得目前節點的子節點
            List<Element> elements = rootElement.elements();
            if (elements.size() == 0) {
                  //沒有子節點說明目前節點是葉子節點,直接取值
                  map.put(rootElement.getName(),rootElement.getText());
            }else if (elements.size() == 1) {
                  //隻有一個子節點說明不用考慮list的情況,繼續遞歸
                  Map<String,Object> tempMap = new HashMap<String,Object>();
                  element2Map(tempMap,elements.get(0));
                  map.put(rootElement.getName(),tempMap);
            }else {
                  //多個子節點的話就要考慮list的情況了,特别是當多個子節點有名稱相同的字段時
                  Map<String,Object> tempMap = new HashMap<String,Object>();
                  for (Element element : elements) {
                        tempMap.put(element.getName(),null);
                  }
                  Set<String> keySet = tempMap.keySet();
                  for (String string : keySet) {
                        Namespace namespace = elements.get(0).getNamespace();
                        List<Element> sameElements = rootElement.elements(new QName(string,namespace));
                        //如果同名的數目大于1則表示要建構list
                        if (sameElements.size() > 1) {
                              List<Map> list = new ArrayList<Map>();
                              for(Element element : sameElements){
                                    Map<String,Object> sameTempMap = new HashMap<String,Object>();
                                    element2Map(sameTempMap,element);
                                    list.add(sameTempMap);
                              }
                              map.put(string,list);
                        }else {
                              //同名的數量不大于1直接遞歸
                              Map<String,Object> sameTempMap = new HashMap<String,Object>();
                              element2Map(sameTempMap,sameElements.get(0));
                              map.put(string,sameTempMap);
                        }
                  }
            }
      }
}
           

xml檔案讀取工具類:

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import org.jdom.Document;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
/**
 * 讀取一個xml檔案傳回string
 * @author lmb 
 *
 */
public class MyXmlUtil {
      /**
       * 加載xml檔案
       * @return Document
       */
      public static Document load(){
            Document document=null; 
        String url="E://2.xml"; 
        try { 
            SAXBuilder reader = new SAXBuilder();  
            document=reader.build(new File(url)); 
       } catch (Exception e) { 
            e.printStackTrace(); 
       } 
        return document;
      }
      
      /**
       * 将xml檔案轉換為String串
       * @return
       */
      public static String XmlToString(){
            Document document=null; 
        document=load(); 
         
        Format format =Format.getPrettyFormat();     
        format.setEncoding("UTF-8");//設定編碼格式  
         
        StringWriter out=null; //輸出對象 
        String sReturn =""; //輸出字元串 
        XMLOutputter outputter =new XMLOutputter();  
        out=new StringWriter();  
        try { 
           outputter.output(document,out); 
        } catch (IOException e) { 
           e.printStackTrace(); 
        }  
        sReturn=out.toString();  
        return sReturn; 
    } 
}
           

控制台列印結果:

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}}}

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"}}}
           

格式化之後的結果如下:

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}
    }
}

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"}
    }
}