Live2D

xml转为map工具类,可直接使用

  1. 背景:业务场景中遇见一个解读xml文件的需求,在搜索引擎泡了好久,都没能找到理想的解决方案,最终决定集大家之所长,将cv工程师的能力发挥到极致image
    ,创立如下工具类,如有不足之处,还望多多补充!!!

  2. 工具类代码如下:

    package com.central.ls.utils;
    
    import cn.hutool.core.util.IdUtil;
    import cn.hutool.core.util.ObjectUtil;
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.annotation.Nullable;
    import javax.validation.constraints.NotNull;
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.atomic.AtomicBoolean;
    
    /**
     * xml解析工具类
     *
     * @author: lix
     * @Date:2023-02-18 13:15:29
     */
    public class XmlAnalysisUtil {
    
        /**
         * 将xml文件转化为 map
         * @param multipartFile xml文件
         * @param nodeNames 名称重复的,不属于最小子节点的节点名(解释:此节点还有子节点)
         * @param minimumNodeNames 名称重复的,属于最小子节点的节点名(解释:最小子节点意为此节点没有任何子节点)
         * @return
         * @throws IOException
         * @throws DocumentException
         */
        public static Map<String,Object> xmlToLinkedMap(MultipartFile multipartFile,
                                                        @Nullable Set<String> nodeNames,
                                                        @Nullable Set<String> minimumNodeNames)
                throws IOException, DocumentException {
            // 获取文件名
            String fileName = multipartFile.getOriginalFilename();
            // 获取文件后缀
            String prefix = fileName.substring(fileName.lastIndexOf("."));
            //若须要防止生成的临时文件重复,能够在文件名后添加随机码
            //转化为File
            File file = File.createTempFile(fileName, prefix);
            multipartFile.transferTo(file);
            //解析xml
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);
            Element root = document.getRootElement();
            Map<String, Object> res = new LinkedHashMap<>();
            return recursionXmlToMap(root, res,nodeNames,minimumNodeNames);
        }
    
        /**
         * multilayerXmlToMap核心方法,递归调用
         *
         * @param element 节点元素
         * @param outMap 用于存储xml数据的map
         */
        @SuppressWarnings("unchecked")
        private static Map recursionXmlToMap(Element element, Map<String, Object> outMap,
                                             @Nullable Set<String> nodeNames,
                                             @Nullable Set<String> minimumNodeNames) {
            // 得到根元素下的子元素列表
            List<Element> list = element.elements();
            int size = list.size();
            if (size == 0) {
                // 如果没有子元素,则将其存储进map中
                if (ObjectUtil.isNotNull(minimumNodeNames)) {
                    //节点名称重复,为了避免数据丢失,重命名节点,
                    if (strEqualCollection(element.getName(),minimumNodeNames))
                        outMap.put(IdUtil.fastSimpleUUID(), element.getTextTrim());
                    else
                        outMap.put(element.getName(), element.getTextTrim());
                } else
                    outMap.put(element.getName(), element.getTextTrim());
            } else{
                // 遍历子元素
                Map<String, Object> innerMap = new LinkedHashMap<>();
                list.forEach(childElement -> recursionXmlToMap(childElement, innerMap,nodeNames,minimumNodeNames) );
                //名称重复的节点使用list保存
                if (ObjectUtil.isNotNull(nodeNames)) {
                    if (strEqualCollection(element.getName(), nodeNames)) {
                        List<Map<String, Object>> insert = (List<Map<String, Object>>) outMap.get(element.getName());
                        innerMap.put(element.getName(), innerMap);
                        if (!ObjectUtil.isNotEmpty(insert)) {
                            insert = new ArrayList<>();
                        }
                        insert.add(innerMap);
                        outMap.put(element.getName(), insert);
                    } else
                        outMap.put(element.getName(), innerMap);
                }else
                    outMap.put(element.getName(), innerMap);
            }
            return outMap;
        }
    
        /**
         * 判断一组字符串和某个字符串内容是否相等
         * @param content 某个字符串
         * @param compared 一组字符串
         * @return  都不相等返回false,只要有一个相等则返回true
         */
        private static boolean strEqualCollection (@NotNull String content, @NotNull Set<String> compared) {
            AtomicBoolean res = new AtomicBoolean(false);
            compared.forEach(c -> {
                if (content.equals(c))
                    res.set(true);
            });
            return res.get();
        }
    }
    
    

3.如何使用:
a. 所有节点名称都没有重复的情况:

/**
*此处的xml文件中所有节点的名称都不重复,所以nodeNames和minimunNodeNames都为空
**/
Map<String,Object> test = XmlAnalysisUtil.xmlToLinkedMap(xml,null,null);

附图:
image

b. 有重复节点名称,且该节点不为最小子节点

Set<String> nodeNames = new HashSet<>();
        nodeNames.add("Test");
        Map<String,Object> oae = XmlAnalysisUtil.xmlToLinkedMap(xml,nodeNames,null);

附图:image
附图(xml文件):
image
c. 有重复节点名称,且该节点为最小子节点

/**
*xml 解释:MultipartFile xml参数
**/
Set<String> minimumNodeNames = new HashSet<>();
        nodeNames.add("Test");
Map<String,Object> oae = XmlAnalysisUtil.xmlToLinkedMap(xml,null,minimumNodeNames);

该类情况没有遇到,不附图了;
d.有重复节点名称,且包含了最小子节点和非最小子节点

/**
*xml 解释:MultipartFile xml参数
**/
Set<String> nodeNames = new HashSet<>();
        nodeNames.add("Test");
Set<String> minimumNodeNames = new HashSet<>();
        nodeNames.add("Test");
Map<String,Object> oae = XmlAnalysisUtil.xmlToLinkedMap(xml,nodeNames,minimumNodeNames);

该类情况同c
简单说明一下,虽然没有自己测试过,但是代码肯定是没问题的,这点自信还是有的~~~,欢迎各位大神亲测!
其中的原理我的注释应该是写的很清楚了,如有不足之处,欢迎各位大神指出,感谢!!!

posted @ 2023-02-20 12:04  六爻呈乾  阅读(648)  评论(0编辑  收藏  举报