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


好的,以下是使用SAX解析器按节点层级读取XML文件Java代码示例: 首先,您需要导入SAX解析器: ```java import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; ``` 然后,您需要定义一个继承自DefaultHandler类的处理程序,该处理程序将在解析XML文件时被调用: ```java public class NodeHandler extends DefaultHandler { private String current_node; private int current_level = 0; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { current_node = qName; current_level++; System.out.println(String.format("%" + current_level + "s", "") + qName); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { current_level--; } @Override public void characters(char[] ch, int start, int length) throws SAXException { String content = new String(ch, start, length).trim(); if (!content.isEmpty()) { System.out.println(String.format("%" + (current_level + 1) + "s", "") + content); } } } ``` 在这个处理程序中,我们重写了三个方法:startElement、endElement和characters。这些方法在解析XML文件时被调用,以处理XML文件中的节点。 在startElement方法中,我们获取当前节点的名称,并将当前节点的层级设置为当前层级加一。然后,我们打印当前节点的名称,并在其前面添加与其层级相对应的空格。 在endElement方法中,我们将当前层级减一。 在characters方法中,我们获取当前节点的内容,并将其打印。我们还将其前面添加与其层级相对应的空格。 最后,您需要创建一个SAX解析器对象,并将处理程序分配给它。然后,您可以使用parse方法解析XML文件: ```java public static void main(String[] args) { try { SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxParserFactory.newSAXParser(); NodeHandler handler = new NodeHandler(); saxParser.parse(new File("example.xml"), handler); } catch (Exception e) { e.printStackTrace(); } } ``` 在这里,我们创建了一个SAX解析器对象,并将NodeHandler处理程序分配给它。然后,我们使用parse方法解析XML文件。 请注意,您需要将example.xml替换为您要读取的实际XML文件的路径。 希望这可以帮助您按节点层级读取XML文件
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值