zoukankan      html  css  js  c++  java
  • 【Java/Json】Java对Json进行建模,分词,递归向下解析构建Json对象树

    伸手党的福音 代码下载:https://files.cnblogs.com/files/xiandedanteng/JsonLexerBuilder20191202.rar

    互联网上成型的对Json进行解析的工具包不少,可用来用去就觉得没意思了,哪怕它是大厂出品,可作为一个API的使用者,用得再爽也觉得缺点什么。

    于是就有以下的小小作品,稍微填补一下职业生涯的遗憾,其中代码刚写就,还没时间优化,权且放在这里,算是一条小板凳吧。

    先看看解析效果:

    效果一:

    Raw json={    "status": "0000",    "message": "success",    "data": {        "title": {            "id": "001",            "name" : "白菜"        },        "content": [            {                "id": "001",                "value":"你好 白菜"            },            {                "id": "002",                 "value":"你好 萝卜"             }        ]    }}
    Formatted json={
        "data":{
            "content":[
                {
                    "id":"001",
                    "value":"你好白菜"
                },
                {
                    "id":"002",
                    "value":"你好萝卜"
                }
            ],
            "title":{
                "id":"001",
                "name":"白菜"
            }
        },
        "message":"success",
        "status":"0000"
    }

    效果二:

    Raw json={"employees": [{ "firstName":"Bill" , "lastName":"Gates" },{ "firstName":"George" , "lastName":"Bush" },{ "firstName":"Thomas" , "lastName":"Carter" }]}
    Formatted json={
        "employees":[
            {
                "firstName":"Bill",
                "lastName":"Gates"
            },
            {
                "firstName":"George",
                "lastName":"Bush"
            },
            {
                "firstName":"Thomas",
                "lastName":"Carter"
            }
        ]
    }

    效果三:

    Raw json={ "name": "username", "age": 20, "admin": true }
    Formatted json={
        "admin":true,
        "age":20,
        "name":"username"
    }

     效果四:

    Raw json={    "HeWeather6": [{        "basic": {            "cid": "CN101010100",            "location": "北京",            "parent_city": "北京",            "admin_area": "北京",            "cnty": "中国",            "lat": "39.90498734",            "lon": "116.40528870",            "tz": "8.0"        },        "daily_forecast": [{            "cond_code_d": "103",            "cond_code_n": "101",            "cond_txt_d": "晴间多云",            "cond_txt_n": "多云",            "date": "2017-10-26",            "hum": "57",            "pcpn": "0.0",            "pop": "0",            "pres": "1020",            "tmp_max": "16",            "tmp_min": "8",            "uv_index": "3",            "vis": "16",            "wind_deg": "0",            "wind_dir": "无持续风向",            "wind_sc": "微风",            "wind_spd": "5"        }, {            "cond_code_d": "101",            "cond_code_n": "501",            "cond_txt_d": "多云",            "cond_txt_n": "雾",            "date": "2017-10-27",            "hum": "56",            "pcpn": "0.0",            "pop": "0",            "pres": "1018",            "tmp_max": "18",            "tmp_min": "9",            "uv_index": "3",            "vis": "20",            "wind_deg": "187",            "wind_dir": "南风",            "wind_sc": "微风",            "wind_spd": "6"        }, {            "cond_code_d": "101",            "cond_code_n": "101",            "cond_txt_d": "多云",            "cond_txt_n": "多云",            "date": "2017-10-28",            "hum": "26",            "pcpn": "0.0",            "pop": "0",            "pres": "1029",            "tmp_max": "17",            "tmp_min": "5",            "uv_index": "2",            "vis": "20",            "wind_deg": "2",            "wind_dir": "北风",            "wind_sc": "3-4",            "wind_spd": "19"        }],        "status": "ok",        "update": {            "loc": "2017-10-26 23:09",            "utc": "2017-10-26 15:09"        }    }]}
    Formatted json={
        "HeWeather6":[
            {
                "basic":{
                    "admin_area":"北京",
                    "cid":"CN101010100",
                    "cnty":"中国",
                    "lat":"39.90498734",
                    "location":"北京",
                    "lon":"116.40528870",
                    "parent_city":"北京",
                    "tz":"8.0"
                },
                "daily_forecast":[
                    {
                        "cond_code_d":"103",
                        "cond_code_n":"101",
                        "cond_txt_d":"晴间多云",
                        "cond_txt_n":"多云",
                        "date":"2017-10-26",
                        "hum":"57",
                        "pcpn":"0.0",
                        "pop":"0",
                        "pres":"1020",
                        "tmp_max":"16",
                        "tmp_min":"8",
                        "uv_index":"3",
                        "vis":"16",
                        "wind_deg":"0",
                        "wind_dir":"无持续风向",
                        "wind_sc":"微风",
                        "wind_spd":"5"
                    },
                    {
                        "cond_code_d":"101",
                        "cond_code_n":"501",
                        "cond_txt_d":"多云",
                        "cond_txt_n":"雾",
                        "date":"2017-10-27",
                        "hum":"56",
                        "pcpn":"0.0",
                        "pop":"0",
                        "pres":"1018",
                        "tmp_max":"18",
                        "tmp_min":"9",
                        "uv_index":"3",
                        "vis":"20",
                        "wind_deg":"187",
                        "wind_dir":"南风",
                        "wind_sc":"微风",
                        "wind_spd":"6"
                    },
                    {
                        "cond_code_d":"101",
                        "cond_code_n":"101",
                        "cond_txt_d":"多云",
                        "cond_txt_n":"多云",
                        "date":"2017-10-28",
                        "hum":"26",
                        "pcpn":"0.0",
                        "pop":"0",
                        "pres":"1029",
                        "tmp_max":"17",
                        "tmp_min":"5",
                        "uv_index":"2",
                        "vis":"20",
                        "wind_deg":"2",
                        "wind_dir":"北风",
                        "wind_sc":"3-4",
                        "wind_spd":"19"
                    }
                ],
                "status":"ok",
                "update":{
                    "loc":"2017-10-2623:09",
                    "utc":"2017-10-2615:09"
                }
            }
        ]
    }

    效果五:

    Raw json={    "data": [        {            "deliveryListId": "20180001",            "shipperCode": "0030",            "shortShipperName": "RB",            "orderNo": "102018032001",            "deliveryOrder": 1,            "receiverName": "吉田 XXX",            "receiverTelNo": "07012340303",            "receiverAddress1": "東京都足立区足立1-1",            "receiverAddress2": "東京都足立区足立1-2",            "isCod": true,            "billAmount": 5,            "geocodingScore": 50,            "latitudeJP": "56789.33",            "longitudeJP": "123456.33",            "latitude": "20180001.22",            "longitude": "20180001.33",            "vehicleId": "239",            "orderDetails": [                {                    "trackingNo": "201803200001",                    "quantity": 1,                    "lapCount": null,                    "statusCode": null,                    "statusNameMobile": null                },                {                    "trackingNo": "201803200002",                    "quantity": 1,                    "lapCount": 4,                    "statusCode": "100",                    "statusNameMobile": "配送準備中"                },                {                    "trackingNo": "201803200003",                    "quantity": 1,                    "lapCount": 4,                    "statusCode": "300",                    "statusNameMobile": "持出し"                },                {                    "trackingNo": "201803200004",                    "quantity": 1,                    "lapCount": 4,                    "statusCode": "100",                    "statusNameMobile": "配送準備中"                },                {                    "trackingNo": "201803200005",                    "quantity": 1,                    "lapCount": 4,                    "statusCode": "100",                    "statusNameMobile": "配送準備中"                }            ]        }    ]}
    Formatted json={
        "data":[
            {
                "billAmount":5,
                "deliveryListId":"20180001",
                "deliveryOrder":1,
                "geocodingScore":50,
                "isCod":true,
                "latitude":"20180001.22",
                "latitudeJP":"56789.33",
                "longitude":"20180001.33",
                "longitudeJP":"123456.33",
                "orderDetails":[
                    {
                        "lapCount":null,
                        "quantity":1,
                        "statusCode":null,
                        "statusNameMobile":null,
                        "trackingNo":"201803200001"
                    },
                    {
                        "lapCount":4,
                        "quantity":1,
                        "statusCode":"100",
                        "statusNameMobile":"配送準備中",
                        "trackingNo":"201803200002"
                    },
                    {
                        "lapCount":4,
                        "quantity":1,
                        "statusCode":"300",
                        "statusNameMobile":"持出し",
                        "trackingNo":"201803200003"
                    },
                    {
                        "lapCount":4,
                        "quantity":1,
                        "statusCode":"100",
                        "statusNameMobile":"配送準備中",
                        "trackingNo":"201803200004"
                    },
                    {
                        "lapCount":4,
                        "quantity":1,
                        "statusCode":"100",
                        "statusNameMobile":"配送準備中",
                        "trackingNo":"201803200005"
                    }
                ],
                "orderNo":"102018032001",
                "receiverAddress1":"東京都足立区足立1-1",
                "receiverAddress2":"東京都足立区足立1-2",
                "receiverName":"吉田XXX",
                "receiverTelNo":"07012340303",
                "shipperCode":"0030",
                "shortShipperName":"RB",
                "vehicleId":"239"
            }
        ]
    }

    下面是三个类的代码:

    Json对象类:

    package com.hy;
    
    import java.util.Collections;
    import java.util.LinkedList;
    import java.util.List;
    
    /**
     * Json对象类
     * @author 逆火
     *
     * 2019年12月2日 下午8:17:06
     */
    public class Json implements Comparable<Json>{
        
        // There are value types
        public static final int Type_String=1;
        public static final int Type_Array=2;
        public static final int Type_List=3;
        
        // Key always is String
        private String key;
        private Json parent;
    
        // There are three types of value
        private int valueType;
        private String valueString;
        private List<Json> valueList;
        
        // indent depth
        private int depth;
        
        public Json() {
            
        }
        
        /**
         * Contructor1
         */
        public Json(String key,String value) {
            this.key=key;
            this.valueType=Type_String;
            this.valueString=value;
            this.depth=0;
        }
        
        public Json(String key,int type) {
            this.key=key;
            
            if(type==Type_List) {
                this.valueType=Type_List;
                this.valueList=new LinkedList<Json>();
            }else if(type==Type_Array) {
                this.valueType=Type_Array;
                this.valueList=new LinkedList<Json>();
            }
        }
        
        public List<Json> getValueList() {
            return valueList;
        }
        
        public void addJsonToList(Json json) {
            if(valueList!=null) {
                valueList.add(json);
                json.parent=this;
                
                adjustDepth();
            }
        }
        
        public void addJsonToArray(Json json) {
            if(valueList!=null) {
                valueList.add(json);
                json.parent=this;
                adjustDepth();
            }
        }
        
        private void adjustDepth() {
            if(valueType==Type_List) {
                for(Json json:valueList) {
                    json.depth=this.depth+1;
                    json.adjustDepth();
                }
                
                
            }
            
            if(valueType==Type_Array) {
                for(Json json:valueList) {
                    json.depth=this.depth+1;
                    json.adjustDepth();
                }
            }
        }
        
        public String toString() {
            StringBuilder sb=new StringBuilder();
            
            // key
            String tabs=getIndentSpace();
            sb.append(tabs);
            //sb.append("""+(key==null?"":key)+""");
            
            if(key!=null) {
                //sb.append("""+key+""");// 以对象构建时恢复
                sb.append(key);// 以文件构建时打开
                sb.append(":");
            }else {
                
            }
            
            // value
            if(valueType==Type_String) {
                //sb.append("""+valueString+""");// 以对象构建时恢复
                sb.append(valueString);// 以文件构建时打开
            }else if(valueType==Type_Array) {
                sb.append("[
    ");
                
                int n=valueList.size();
                for(int i=0;i<n;i++) {
                    Json json=valueList.get(i);
                    if(i!=n-1) {
                        sb.append(json.toString()+",
    ");
                    }else {
                        sb.append(json.toString()+"
    ");
                    }
                }
                
                sb.append(tabs+"]");
            }else if(valueType==Type_List) {
                sb.append("{
    ");
                
                Collections.sort(valueList);
                
                int n=valueList.size();
                for(int i=0;i<n;i++) {
                    Json json=valueList.get(i);
                    if(i!=n-1) {
                        sb.append(json.toString()+",
    ");
                    }else {
                        sb.append(json.toString()+"
    ");
                    }
                }
                
                sb.append(tabs+"}");
            }
            
            return sb.toString();
        }
        
        public int compareTo(Json other) {
            return this.key.compareTo(other.key);
        }
        
        private String getIndentSpace() {
            return String.join("", Collections.nCopies(this.depth, "    "));
        }
        
        public String getKey() {
            return key;
        }
    
        public void setKey(String key) {
            this.key = key;
        }
        
        public Json getParent() {
            return parent;
        }
    
        public void setParent(Json parent) {
            this.parent = parent;
        }
        
        public static void main(String[] args) {
            Json id1=new Json("id","001");
            Json name1=new Json("name","鐧借彍");
            
            Json title=new Json("title",3);
            title.addJsonToList(id1);
            title.addJsonToList(name1);
            
            Json empty1=new Json(null,3);
            empty1.addJsonToList(new Json("id","001"));
            empty1.addJsonToList(new Json("id","浣犲ソ鐧借彍"));
            
            Json empty2=new Json(null,3);
            empty2.addJsonToList(new Json("id","001"));
            empty2.addJsonToList(new Json("id","浣犲ソ钀濆崪"));
            
            Json content=new Json("content",2);
            content.addJsonToArray(empty1);
            content.addJsonToArray(empty2);
            
            Json data=new Json("data",3);
            data.addJsonToList(title);
            data.addJsonToList(content);
            
            Json status=new Json("status","0000");
            Json message=new Json("message","success");
            
            Json root=new Json(null,3);
            root.addJsonToList(status);
            root.addJsonToList(message);
            root.addJsonToList(data);
            
            System.out.println(root.toString());
        }
    }

    分词器类:

    package com.hy;
    
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    
    import org.apache.commons.lang.StringUtils;
    
    
    class Token{
        static final int TYPE_LBRACE=0;// 宸﹀ぇ鎷�彿
        static final int TYPE_RBRACE=1;// 鍙冲ぇ鎷�彿
        static final int TYPE_TEXT=2;// 鏂囨湰
        static final int TYPE_COMMA=3;// 閫楀彿
        static final int TYPE_COLON=4;// 鍐掑彿
        static final int TYPE_LBRACKET=5;// 宸︿腑鎷�彿
        static final int TYPE_RBRACKET=6;// 鍙充腑鎷�彿
        
        int type;
        String text;
        
        public Token(char c,int type) {
            this.text=String.valueOf(c);
            this.type=type;
        }
        
        public Token(String word,int type) {
            this.text=word;
            this.type=type;
        }
    }
    /**
     * Json鏂囨湰鍒嗚瘝鍣�
     * @author 閫嗙伀
     *
     * 2019骞�12鏈�1鏃� 涓婂崍11:35:43
     */
    public class Lexer {
        private List<Token> tokenList;
    
        /**
         * Contructor
         * @param jsonStr
         */
        public Lexer(String jsonStr) {
            tokenList=new ArrayList<Token>();
            
            String line="";
            for(int i=0;i<jsonStr.length();i++){
                char c=jsonStr.charAt(i);
                
                if(Character.isWhitespace(c)){
                    continue;
                }else if(c=='{'){
                    Token t=new Token(c,Token.TYPE_LBRACE);
                    tokenList.add(t);
                }else if(c=='}'){
                    if(StringUtils.isNotEmpty(line)) {
                        Token w=new Token(line,Token.TYPE_TEXT);
                        tokenList.add(w);
                        line="";
                    }
                    
                    
                    Token t=new Token(c,Token.TYPE_RBRACE);
                    tokenList.add(t);
                }else if(c=='['){
                    Token t=new Token(c,Token.TYPE_LBRACKET);
                    tokenList.add(t);
                }else if(c==']'){
                    Token t=new Token(c,Token.TYPE_RBRACKET);
                    tokenList.add(t);
                }else if(c==',') {
                    if(StringUtils.isNotEmpty(line)) {
                        Token w=new Token(line,Token.TYPE_TEXT);
                        tokenList.add(w);
                        line="";
                    }
                    
                    Token t=new Token(c,Token.TYPE_COMMA);
                    tokenList.add(t);
                }else if(c==':') {
                    if(StringUtils.isNotEmpty(line)) {
                        Token w=new Token(line,Token.TYPE_TEXT);
                        tokenList.add(w);
                        line="";
                    }
                    
                    Token t=new Token(c,Token.TYPE_COLON);
                    tokenList.add(t);
                }else {
                    line+=c;
                }
            }
        }
        
        public List<Token> getTokenList() {
            return tokenList;
        }
        
        public void printTokens() {
            int idx=0;
            for(Token t:tokenList) {
                idx++;
                System.out.println("#"+idx+" "+t.text);
            }
        }
        
        /**
         * Entry point
         */
        public static void main(String[] args) {
            String filePathname="D:\logs\20191126-1.json";
            try {
                StringBuilder sb=new StringBuilder();
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePathname), "UTF-8"));  
                String line = null;  
                while( ( line = br.readLine() ) != null ) {
                    sb.append(line);
                }
                br.close();  
                
                String jsonStr=sb.toString();
                System.out.println("Raw json="+jsonStr);
                
                Lexer l=new Lexer(jsonStr);
                l.printTokens();
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            } 
        }
        
    }

    Json对象构建类:

    package com.hy;
    
    import java.io.BufferedReader;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.List;
    import java.util.Stack;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /**
     * Json对象构建器
     * @author 逆火
     *
     * 2019年12月2日 下午8:22:59
     */
    public class Builder {
        private Json root;
        private int index;
        private List<Token> tokens;
        
        public Json getRoot() {
            return root;
        }
        
        public Builder(List<Token> tokens) {
            this.root=null;
            this.tokens=tokens;
            this.index=1;
            
            root=createObjJson();
            build(root);
        }
    
        /**
         * 递归向下
         * @param parent
         */
        private void build(Json parent) {
            if(parent==null) {
                return;
            }
            
            Stack<Token> stack=new Stack<Token>();
            
            while(index<this.tokens.size()) {
                Token token=tokens.get(index);
                
                if(token.type==Token.TYPE_LBRACE) {
                    Json obj=new Json(null,Json.Type_List);
                    
                    if(stack.size()>=2) {
                        Token left1=stack.pop();
                        Token left2=stack.pop();
                        
                        if(left1.type==Token.TYPE_COLON && left2.type==Token.TYPE_TEXT) {
                            obj.setKey(left2.text);
                        }
                    }
                    
                    parent.addJsonToList(obj);
                    
                    index++;
                    build(obj);
                }else if(token.type==Token.TYPE_RBRACE) {
                    StringBuilder sb=new StringBuilder();
                    for(int i=0;i<stack.size();i++) {
                        Token t=stack.elementAt(i);
                        sb.append(t.text);
                    }
                    
                    if(sb.length()>0) {
                        java.util.regex.Pattern pattern=Pattern.compile("("([_a-zA-Z]+[_a-zA-Z0-9]*)")[:]([^,}]+)");
                        Matcher matcher=pattern.matcher(sb.toString());
                        while(matcher.find()) {
                            Json txt=new Json(matcher.group(1),matcher.group(3));
                            parent.addJsonToArray(txt);
                        }
                    }
                    
                    stack.clear();
                    index++;
                    
                    build(parent.getParent());
                }else if(token.type==Token.TYPE_LBRACKET) {
                    Json obj=new Json(null,Json.Type_Array);
                    
                    if(stack.size()>=2) {
                        Token left1=stack.pop();
                        Token left2=stack.pop();
                        
                        if(left1.type==Token.TYPE_COLON && left2.type==Token.TYPE_TEXT) {
                            obj.setKey(left2.text);
                        }
                    }
                    
                    parent.addJsonToList(obj);
                    
                    index++;
                    build(obj);
                }else if(token.type==Token.TYPE_COMMA) {
                    StringBuilder sb=new StringBuilder();
                    for(int i=0;i<stack.size();i++) {
                        Token t=stack.elementAt(i);
                        sb.append(t.text);
                    }
                    
                    if(sb.length()>0) {
                        java.util.regex.Pattern pattern=Pattern.compile("("([_a-zA-Z]+[_a-zA-Z0-9]*)")[:]([^,}]+)");
                        Matcher matcher=pattern.matcher(sb.toString());
                        while(matcher.find()) {
                            Json txt=new Json(matcher.group(1),matcher.group(3));
                            parent.addJsonToList(txt);
                        }
                    }
                    
                    stack.clear();
                    index++;
                }else if(token.type==Token.TYPE_RBRACKET) {
                    StringBuilder sb=new StringBuilder();
                    for(int i=0;i<stack.size();i++) {
                        Token t=stack.elementAt(i);
                        sb.append(t.text);
                    }
                    
                    if(sb.length()>0) {
                        java.util.regex.Pattern pattern=Pattern.compile("("([_a-zA-Z]+[_a-zA-Z0-9]*)")[:]([^,}]+)");
                        Matcher matcher=pattern.matcher(sb.toString());
                        while(matcher.find()) {
                            Json txt=new Json(matcher.group(1),matcher.group(3));
                            parent.addJsonToList(txt);
                        }
                    }
                    
                    stack.clear();
                    index++;
                    build(parent.getParent());
                }else {
                    stack.push(token);
                    index++;
                 }
                
                
            }
        }
        
        private Json createObjJson() {
            return new Json(null,Json.Type_List);
        }
        
        
        /**
         * Entry point
         */
        public static void main(String[] args) {
            String filePathname="D:\logs\train.json";// 注意暂时不接受根为数组的文件
            try {
                StringBuilder sb=new StringBuilder();
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePathname), "UTF-8"));  
                String line = null;  
                while( ( line = br.readLine() ) != null ) {
                    sb.append(line);
                }
                br.close();  
                
                String jsonStr=sb.toString();
                System.out.println("Raw json="+jsonStr);
                
                Lexer l=new Lexer(jsonStr);
                //l.printTokens();
                Builder b=new Builder(l.getTokenList());
                Json root=b.getRoot();
                System.out.println("Formatted json="+root);
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            } catch (IOException ex) {
                ex.printStackTrace();
            } 
        }
    }

    嵌套结构解析用递归就对了,栈结构也是利器之一。

    --END-- 2019年12月2日20:36:46

  • 相关阅读:
    移动端rem布局
    父子组件通信
    拦截器
    Vue路由教程
    使用var和let的区别
    数组去重的几种方法
    利用位运算进行权限控制
    线程基础
    关于get请求的乱码问题
    nuxt.js Navigating to current location ("/xxx") is not allowed
  • 原文地址:https://www.cnblogs.com/heyang78/p/11973129.html
Copyright © 2011-2022 走看看