zoukankan      html  css  js  c++  java
  • xml/map转换器,递归设计思路【纯原】

    xml/map转换器

      xml转换: xml/map转换器

      xml合并: xml合并

      snagit图片:http://pan.baidu.com/s/1nuKJD13

      git样例: https://gitee.com/KingBoBo/XmlMapBeanTool/tree/master/XmlMapBeanTool

    应用场景,为什么要把xml转map?我直接用jdom,dom4j操作不行吗?

    • 如果你了解模板引擎(像velocity,mvel,httl等),会发现map形式在模板中取数可以如下所示直接取值,而xml字符串或dom则没有这样取值的便利和易理解特性.
    <爸爸的小狗毛色>PACKET.MASTER_LIST.MASTER[1].DOG.COLOR</爸爸的小狗毛色>

      以上语句中文翻译为取得PACKET报文中的第2个MASTER主人拥有的狗狗的毛色.

    • 而map.get("key")取值的性能远胜于其它方式,针对报文中部分指定节点做类似于md5的重复性校验(查重)也非常合适.

    比如我们在库中指定以下节点作为查重节点:

    节点中文名
    关键节点(查重节点)
    地址 PACKET/FAMILY/ADDESS
    主人名 PACKET/MASTER_LIST/MASTER/NAME

    之后可以通过以下方式取值

    map.get("PACKET").get("FAMILY").get("ADDRESS") ;

    map.get("PACKET").get("MASTER_LIST").get("MASTER").get("NAME"); // 考虑到有list,在取到get("MASTER")时做instanceof LIST,之后遍历取出3个NAME

    再把它们各自的value拼成 "绍兴兰亭MamaBabaSon",  最终后续来的报文也提取类似"杭州江干MamaBabaDaughter"进行历史比对,就能马上发现存在差异,至于有没有差异的后续处理得根据业务需要了. (为了更高的性能先用length,再用equals,该点很重要,属于性能优化点.)

    设计思路

    1. 有上下层次关系,必然递归最适合
    2. 递归原则 : 一个map对应一个xml节点,key为当前xml节点名,value为当前xml节点子集
    3.1 如果xml节点没有子节点(叶子节点),那么map的key为xml节点名,value为xml节点文本内容
    3.2 如果xml节点有一个子节点,那么map的key为xml节点名,value为xml节点子集
    3.3.1 如果xml节点有多个子节点,对应map的key不存在(每一次),map的key为xml节点名,value为xml节点子集
    3.3.2 如果xml节点有多个子节点,对应map的key已存在,且value为map类型(第二次),map的key为xml节点名,值从map类型转为list,而list中添加2份当前xml节点子集
    3.3.3 如果xml节点有多个子节点,对应map的key已存在,且value为list类型(第三/多次),那么直接加到list中去.

    原始xml:

    <?xml version="1.0" encoding="utf-8"?>
    <PACKET>
        <FAMILY>
            <COLOR>red</COLOR>
            <ADDRESS>绍兴兰亭</ADDRESS>
        </FAMILY>
        <MASTER_LIST>
            <MASTER>
                <NAME>Mama</NAME>
                <CAT>
                    <COLOR>yellow</COLOR>
                </CAT>
                <CAT>
                    <COLOR>grey</COLOR>
                </CAT>
            </MASTER>
            <MASTER>
                <NAME>Baba</NAME>
                <DOG>
                    <COLOR>black</COLOR>
                </DOG>
            </MASTER>
            <MASTER>
                <NAME>Son</NAME>
                <RABBIT>
                    <COLOR>white</COLOR>
                </RABBIT>
            </MASTER>
        </MASTER_LIST>
    </PACKET>

    期望map:

    {
        PACKET={
            FAMILY={
                ADDRESS=绍兴兰亭,
                COLOR=red
            },
            MASTER_LIST={
                MASTER=[
                    {
                        NAME=Mama,
                        CAT=[
                            {
                                COLOR=yellow
                            },
                            {
                                COLOR=grey
                            }
                        ]
                    },
                    {
                        NAME=Baba,
                        DOG={
                            COLOR=black
                        }
                    },
                    {
                        NAME=Son,
                        RABBIT={
                            COLOR=white
                        }
                    }
                ]
            }
        }
    }

    图文思路解析

     总map结构

    叶子节点map结构

    list层次结构第一次生成时

     

    list层次结构第二次生成时

    list层次结构第三/多次生成时

     

    初版原码

    先理解初版,最重要版本.

    package test.king;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    
    import test.king.tool.FileTool;
    
    public class XmlMapTool {
        public static void main(String[] args) {
            String input = FileTool.readStringFromFile("d://input.txt", "gbk");
            Map<String, Object> map = xml2map(input);
            System.out.println("最终生成的map如下:
    "+map);
        }
    
        public static Map<String, Object> xml2map(String xml) {
            Document doc = null;
            try {
                doc = DocumentHelper.parseText(xml);
            } catch (DocumentException e) {
                e.printStackTrace();
            }
            Map<String, Object> map = new HashMap<String, Object>();
            if (doc == null)
                return map;
            Element rootElement = doc.getRootElement();
            element2map(rootElement,map);
            return map;
        }
        
        public static Map element2map (Element outele,Map outmap) {
            System.out.println("当前位于"+outele.getName()+"节点");
            List<Element> list = outele.elements();//必定返回0,1,2,3,....... 不会异常
            int size = list.size();
            if(size == 0){//当前节点是叶子节点
                outmap.put(outele.getName(), outele.getTextTrim());
            }else if(size == 1){
                Map<String, Object> innermap = new HashMap<String, Object>();
                Element ele1 = list.get(0);
                element2map(ele1,innermap);
                outmap.put(outele.getName(), innermap);
            }else if(size > 1){
                Map<String, Object> innermap = new HashMap<String, Object>();
                for(Element ele1 : list){
                    String eleName = ele1.getName();
                    Object obj =  innermap.get(eleName);//获取MASTER
                    if(obj == null){//如果该MASTER不存在,现在有一个MASTER过来
                        element2map(ele1,innermap);
                    }else{
                        if(obj instanceof java.util.Map){//如果没有生成过list,把原来的单个map合并到新的list
                            innermap.remove(eleName);
                            List<Map> list1 = new ArrayList<Map>();
                            list1.add((Map) obj);
                            Map<String, Object> map1 = new HashMap<String, Object>();
                            element2map(ele1,map1);
                            list1.add((Map) map1.get(eleName));
                            innermap.put(eleName, list1);
                        }else if(obj instanceof java.util.List){//如果已经生成过list
                            element2map(ele1,innermap);
                            ((List)obj).add(innermap);
                        }
                    }
                }
                outmap.put(outele.getName(), innermap);
            }
            return outmap;
        }
    
        
    }

    优化后原码

    最终发现else if( size == 1 ){...... }的功能在 else if( size >1 ) 中已完全包含,所以可以舍掉 (size == 1) 这个多余处理.

    且这里没有使用Iterator<Element> eleItor = outele.elementIterator();用法,因为亲自经过10000次大报文自测发现还是size()判断更快.

    size用法(推荐):

    package test.king;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    
    import test.king.tool.FileTool;
    import test.king.tool.TLTimeContainer;
    
    public class XmlMapToolIngenious {
        public static void main(String[] args) {
            String input = FileTool.readStringFromFile("d://input.txt", "gbk");
            Map<String, Object> map = null;
            TLTimeContainer.recordTime();
            for(int i = 0 ; i < 10000 ; i++){
                map = xml2map(input);
            }
            TLTimeContainer.recordTime();
            TLTimeContainer.print();
            System.out.println("最终生成的map如下:
    "+map);
        }
    
        public static Map<String, Object> xml2map(String xml) {
            Document doc = null;
            try {
                doc = DocumentHelper.parseText(xml);
            } catch (DocumentException e) {
                e.printStackTrace();
            }
            Map<String, Object> map = new HashMap<String, Object>();
            if (doc == null)
                return map;
            Element rootElement = doc.getRootElement();
            element2map(rootElement,map);
            return map;
        }
        
        public static Map element2map (Element outele,Map outmap) {
            List<Element> list = outele.elements();//必定返回0,1,2,3,....... 不会异常
            int size = list.size();
            if(size == 0){//当前节点是叶子节点(outele如果为叶子节点,是不可能有子节点的,因为它里面是纯文本)
                outmap.put(outele.getName(), outele.getTextTrim());
            }else{
                Map<String, Object> innermap = new HashMap<String, Object>();
                for(Element ele1 : list){
                    String eleName = ele1.getName();
                    Object obj =  innermap.get(eleName);//获取MASTER
                    if(obj == null){//如果该MASTER不存在,现在有一个MASTER过来
                        element2map(ele1,innermap);
                    }else{
                        if(obj instanceof java.util.Map){//如果没有生成过list,把原来的单个map合并到新的list
                            List<Map> list1 = new ArrayList<Map>();
                            list1.add((Map) innermap.remove(eleName));
                            element2map(ele1,innermap);
                            list1.add((Map) innermap.remove(eleName));
                            innermap.put(eleName, list1);
                        }else{//如果不是map,必然是list,只有这两种情况,所以不再else if 条件判断
                            element2map(ele1,innermap);
                            ((List)obj).add(innermap);
                        }
                    }
                }
                outmap.put(outele.getName(), innermap);
            }
            return outmap;
        }
    
        
    }

    同事施明方法,比我的更优雅更简洁更高效(强烈推荐)

    1. 有上下层次关系,必然递归最适合
    2. 递归原则 : 一个map对应一个xml节点,key为当前xml节点名,value为当前xml节点子集
    3. 如果xml节点没有子节点(叶子节点),那么map的key为xml节点名,value为xml节点内文本内容
    4. 如果xml节点有子节点,那么让子节点和新生成子map去递归(子节点和新map会关联到一起)
    5. 然后就要把子map或子list置入上一层map中
    5.2如果子map第一次生成,用上层map直接添加子map
    5.3如果子map第二次生成,用新list把两份子map添加,再用上一层map添加新list
    5.4如果子map第三/多次,用list把第三/多次子map直接添加

    public void element2map(Element elmt, Map<Object, Object> map) {
            if (null == elmt) {
                return;
            }
            String name = elmt.getName();
            if (elmt.isTextOnly()) {
                map.put(name, elmt.getText());
            } else {
                Map<Object, Object> mapSub = new HashMap<Object, Object>();
                List<Element> elements = (List<Element>) elmt.elements();
                for (Element elmtSub : elements) {
                    element2map(elmtSub, mapSub);
                }
                Object first = map.get(name);
                if (null == first) {
                    map.put(name, mapSub);
                } else {
                    if (first instanceof List<?>) {
                        ((List) first).add(mapSub);
                    } else {
                        List<Object> listSub = new ArrayList<Object>();
                        listSub.add(first);
                        listSub.add(mapSub);
                        map.put(name, listSub);
                    }
                }
            }
        }

     微整后

    /**
         * 
         * @param elmt 当前元素
         * @param map 主键为当前元素的节点名,值为当前元素的所有直接子元素
         */
        public static void element2map(Element elmt, Map<String, Object> map) {
            if (null == elmt) {
                return;
            }
            String name = elmt.getName();
            if (elmt.isTextOnly()) {
                map.put(name, elmt.getText());
            } else {
                Map<String, Object> mapSub = new HashMap<String, Object>();
                List<Element> elements = (List<Element>) elmt.elements();
                for (Element elmtSub : elements) {
                    element2map(elmtSub, mapSub);
                }
                Object first = map.get(name);
                if (null == first) {
                    map.put(name, mapSub);
                } else {
                    if (first instanceof List<?>) {
                        ((List) first).add(mapSub);
                    } else {
                        List<Object> listSub = new ArrayList<Object>();
                        listSub.add(first);
                        listSub.add(mapSub);
                        map.put(name, listSub);
                    }
                }
            }
        }

     iterator用法(不推荐):

    因为在10000次循环时间对比中,还没有size()判断比iterator()快1秒左右. 起码在dom4j中是这样的情况.

    package test.king;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    
    import test.king.tool.FileTool;
    import test.king.tool.TLTimeContainer;
    
    public class XmlMapToolIngenious {
        public static void main(String[] args) {
            String input = FileTool.readStringFromFile("d://input.txt", "gbk");
            Map<String, Object> map = null;
            TLTimeContainer.recordTime();
            for(int i = 0 ; i < 10000 ; i++){
                map = xml2map(input);
            }
            TLTimeContainer.recordTime();
            TLTimeContainer.print();
            System.out.println("最终生成的map如下:
    "+map);
        }
    
        public static Map<String, Object> xml2map(String xml) {
            Document doc = null;
            try {
                doc = DocumentHelper.parseText(xml);
            } catch (DocumentException e) {
                e.printStackTrace();
            }
            Map<String, Object> map = new HashMap<String, Object>();
            if (doc == null)
                return map;
            Element rootElement = doc.getRootElement();
            element2map(rootElement,map);
            return map;
        }
        
        public static Map element2map (Element outele,Map outmap) {
            List<Element> list = outele.elements();//必定返回0,1,2,3,....... 不会异常
            int size = list.size();
            Iterator<Element> eleItor = outele.elementIterator();
            if(!eleItor.hasNext()){//当前节点是叶子节点(outele如果为叶子节点,是不可能有子节点的,因为它里面是纯文本)
                outmap.put(outele.getName(), outele.getTextTrim());
            }else{
                Map<String, Object> innermap = new HashMap<String, Object>();
                for(;eleItor.hasNext();){
                    Element ele1 = eleItor.next();
                    String eleName = ele1.getName();
                    Object obj =  innermap.get(eleName);//获取MASTER
                    if(obj == null){//如果该MASTER不存在,现在有一个MASTER过来
                        element2map(ele1,innermap);
                    }else{
                        if(obj instanceof java.util.Map){//如果没有生成过list,把原来的单个map合并到新的list
                            List<Map> list1 = new ArrayList<Map>();
                            list1.add((Map) innermap.remove(eleName));
                            element2map(ele1,innermap);
                            list1.add((Map) innermap.remove(eleName));
                            innermap.put(eleName, list1);
                        }else{//如果不是map,必然是list,只有这两种情况,所以不再else if 条件判断
                            element2map(ele1,innermap);
                            ((List)obj).add(innermap);
                        }
                    }
                }
                outmap.put(outele.getName(), innermap);
            }
            return outmap;
        }
    
        
    }
    View Code

     相关类

    FileTool.java工具类  (用于读取文件内容)

     备用

        
        
        
        
        
    //     IteRator<Element> eles = root.elementIterator(); 
    //     while(eles.hasNext()){ 
    //         
             
    //     }
    View Code

    本文纯原创,开源精神,欢迎转载,请说明出处 by 金墨痴 http://www.cnblogs.com/whatlonelytear/p/5797979.html

  • 相关阅读:
    【转-整理】win764bit plsql 登录oracle11g ora-12154 问题汇总
    【转-整理】log4j 简单解释,配置
    sparsity and density
    转:Recsys2013论文导读
    学院研究生论坛-如何做研究
    推荐系统开源软件列表
    linux下如何用GDB调试c++程序
    全国大学生数据挖掘邀请赛中的NDCG
    网络科学自学资料
    科普文:从人人网看网络科学(Network Science)的X个经典问题
  • 原文地址:https://www.cnblogs.com/whatlonelytear/p/5797979.html
Copyright © 2011-2022 走看看