Dom4j解析多层级XML为MAP对象,其中列表第一个空节点过滤

1、Dom4j解析多层级XML为MAP对象,其中列表第一个空节点过滤,这种情况,在处理系统之间以报文交互的方式居多。

2、由于交互的报文类型多种多样,不能每一种都创建一个对象,所以解析为通用的map格式,转换为不同的Bean对象。

3、在映射为Bean对象时,需要处理列表的第一个空节点对象,才能正常映射成Bean,所以需要特殊处理。

4、如有不足之处,烦请谅解

java源码如下:

import io.micrometer.core.instrument.util.StringUtils;
import org.dom4j.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

public class XmlUtil {
    public static Logger logger = LoggerFactory.getLogger(XmlUtil.class);
    /**
     * 需要调整的节点
     */
    private static Map<String, String> NODE_NAME_MAP = new HashMap<>();

    /**
     * 将xml格式响应报文解析为Map格式(并去掉List列表中的第一个空节点,防止转换成javabean时报错)
     *
     * @param xml xml原始报文
     * @return Map 解析结果
     */
    public static Map<String, Object> xmlToMap(String xml) {
        logger.info("开始执行xmlToMap方法,解析Xml为map");
        try {
            Document doc = DocumentHelper.parseText(xml);
            Element rootElement = doc.getRootElement();
            Map<String, Object> resultMap = new HashMap<>();
            parseElementToMap(resultMap, rootElement);
            logger.info("执行xmlToMap方法,解析Xml为map完成,解析结果为:resultMap = [{}]", resultMap);
            return resultMap;
        } catch (DocumentException e) {
            logger.error("开始执行xmlToMap方法,解析Xml为map异常", e);
        }
        return null;
    }

    /**
     * 使用递归调用将多层级xml转为map,(xml中不能存在空节点)
     *
     * @param map         响应结果集
     * @param rootElement 节点元素
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static void parseElementToMap(Map<String, Object> map, Element rootElement) {
        //获得当前节点的子节点
        List<Element> elements = rootElement.elements();
        int elementsSize = elements.size();
        if (elementsSize == 0) {
            //没有子节点说明当前节点是叶子节点,直接取值
            String name = rootElement.getName();
            String value = rootElement.getText();
            map.put(name, value);
        } else if (elementsSize == 1) {
            String elementName = rootElement.getName();
            String textTrim = rootElement.getTextTrim();
            String parentName = rootElement.getParent().getName();
            if (parentName.endsWith("List") && StringUtils.isBlank(textTrim)) {
                if (!elementName.endsWith("List") && StringUtils.isNotBlank(elementName) && StringUtils.isBlank(textTrim)) {
                    NODE_NAME_MAP.put(parentName, elementName);
                    System.out.println("===>子节点名称为" + elementName);
                }
            }
            //只有一个子节点说明不用考虑list的情况,继续递归
            Map<String, Object> tempMap = new HashMap<>();
            parseElementToMap(tempMap, elements.get(0));
            map.put(elementName, tempMap);
        } else {
            //多个子节点的话就要考虑list的情况了,特别是当多个子节点有名称相同的字段时
            Map<String, Object> tempMap = new HashMap<>();
            for (Element element : elements) {
                String elementName = element.getName();
                String textTrim = element.getTextTrim();
                logger.info("循环当前节点名称为: {}, 对应的值为:{}",elementName,textTrim);
                String parentName = element.getParent().getName();
                System.out.println("循环当前节点名称为" + parentName);
                if (parentName.endsWith("List") && StringUtils.isBlank(textTrim)) {
                    if (!elementName.endsWith("List") && StringUtils.isNotBlank(elementName) && StringUtils.isBlank(textTrim)) {
                        String name = element.getName();
                        NODE_NAME_MAP.put(parentName, name);
                        System.out.println("===>子节点名称为" + name);
                    }
                }
                tempMap.put(element.getName(), null);
            }
            System.out.println("临时存储map----->" + tempMap);
            Set<String> keySet = tempMap.keySet();
            for (String nodeName : keySet) {
                System.out.println("当前节点名称为:" + nodeName);
                Namespace namespace = elements.get(0).getNamespace();
                List<Element> sameElements = rootElement.elements(new QName(nodeName, namespace));
                //如果同名的数目大于1则表示要构建list
                int sameElementSize = sameElements.size();
                if (sameElementSize > 1) {
                    List<Map> list = new ArrayList<Map>();
                    for (Element element : sameElements) {
                        Map<String, Object> sameTempMap = new HashMap<>();
                        parseElementToMap(sameTempMap, element);
                        list.add(sameTempMap);
                    }
                    map.put(nodeName, list);
                } else {
                    //同名的数量不大于1直接递归
                    Map<String, Object> sameTempMap = new HashMap<>();
                    parseElementToMap(sameTempMap, sameElements.get(0));
                    if (NODE_NAME_MAP.containsKey(nodeName)) {
                        logger.info("列表中第一个空节点为:{}", nodeName);
                        String childName = NODE_NAME_MAP.get(nodeName);
                        Object object = sameTempMap.get(childName);
                        if(object == null){
                            Object childObj = sameTempMap.get(nodeName);
                            Map<String, Object> childMap = null ;
                            if(childObj instanceof Map){
                                childMap = (Map<String, Object>)childObj;
                            }
                            map.put(nodeName,childMap.get(childName));
                        }else{
                            map.put(nodeName,sameTempMap.get(childName));
                        }
                    } else if (sameTempMap.containsKey(nodeName)) {
                        logger.info("列表去重第一个空节点为:{}", nodeName);
                        map.put(nodeName, sameTempMap.get(nodeName));
                    } else {
                        map.put(nodeName, sameTempMap);
                    }
                }
            }
        }
    }
}

4、解析为Map的列表参考案例:

示例:多层级XML



	
		A123456
		jack
		15
	
	
		张三
		25
		
			
				三年级一班
				50
				26
				24
				
					
						小寒
						
							
								第三层测试
							
						
					
				
			
			
				
					
						第三层测试
					
				
				三年级二班
				40
				23
				17
			
		
	

6 解析测试

public static void main(String[] args) {
        String xmlStr5 = "\n" +
                "\n" +
                "\t\n" +
                "\t\tA123456\n" +
                "\t\tjack\n" +
                "\t\t15\n" +
                "\t\n" +
                "\t\n" +
                "\t\t张三\n" +
                "\t\t25\n" +
                "\t\t\n" +
                "\t\t\t\n" +
                "\t\t\t\t三年级一班\n" +
                "\t\t\t\t50\n" +
                "\t\t\t\t26\n" +
                "\t\t\t\t24\n" +
                "\t\t\t\t\n" +
                "\t\t\t\t\t\n" +
                "\t\t\t\t\t\t小寒\n" +
                "\t\t\t\t\t\t\n" +
                "\t\t\t\t\t\t\t\n" +
                "\t\t\t\t\t\t\t\t第三层测试\n" +
                "\t\t\t\t\t\t\t\n" +
                "\t\t\t\t\t\t\n" +
                "\t\t\t\t\t\n" +
                "\t\t\t\t\n" +
                "\t\t\t\n" +
                "\t\t\t\n" +
                "\t\t\t\t\n" +
                "\t\t\t\t\t\n" +
                "\t\t\t\t\t\t第三层测试\n" +
                "\t\t\t\t\t\n" +
                "\t\t\t\t\n" +
                "\t\t\t\t三年级二班\n" +
                "\t\t\t\t40\n" +
                "\t\t\t\t23\n" +
                "\t\t\t\t17\n" +
                "\t\t\t\n" +
                "\t\t\n" +
                "\t\n" +
"";
try {
Map<String, Object> map = XmlUtil.xmlToMap(xmlStr5);
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
}

你可能感兴趣的:(xml,java,开发语言)