【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("[\n"); int n=valueList.size(); for(int i=0;i<n;i++) { Json json=valueList.get(i); if(i!=n-1) { sb.append(json.toString()+",\n"); }else { sb.append(json.toString()+"\n"); } } sb.append(tabs+"]"); }else if(valueType==Type_List) { sb.append("{\n"); 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()+",\n"); }else { sb.append(json.toString()+"\n"); } } 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
【Java/Json】Java对Json进行建模,分词,递归向下解析构建Json对象树的更多相关文章
- 【JSON解析】JSON解析
前三篇博客分别介绍了xml的三种解析方法,分别是SAX,DOM,PULL解析XML,兴趣的朋友可以去看一下这[XML解析(一)]SAX解析XML,[XML解析(二)]DOM解析XML,[XML解析(三 ...
- Python 解析构建数据大杂烩 -- csv、xml、json、excel
Python 可以通过各种库去解析我们常见的数据.其中 csv 文件以纯文本形式存储表格数据,以某字符作为分隔值,通常为逗号:xml 可拓展标记语言,很像超文本标记语言 Html ,但主要对文档和数据 ...
- 使用cJSON库解析和构建JSON字符串
使用cJSON库解析和构建JSON字符串 前言 其实之前的两篇博文已经介绍了json格式和如何使用cJSON库来解析JSON: 使用cJSON库解析JSON JSON简介 当时在MCU平台上使用时,会 ...
- 【golang】json数据解析 - 嵌套json解析
@ 目录 1. 通过结构体映射解析 2. 嵌套json解析-map 1. 通过结构体映射解析 原数据结构 解析 // 结构体 type contractJson struct { Data []tra ...
- Java数据解析之JSON
文章大纲 一.JSON介绍二.常见框架介绍与实战三.Studio中GsonFormat插件使用四.项目源码下载(含参考资料)五.参考文档 一.JSON介绍 1. 简介 JSON 的全称是 Ja ...
- objective-c和java下解析对象类型和数组类型JSON字符串
首先讲objective-c如何实现: 这里需要用到2个插件,一个是JSONKit,另一个是Jastor,一共包含6个文件,3个.h头文件和3个.m实现文件.在ARC的工程中如何导入不支持ARC的第三 ...
- 【java/Json】用Java对象构建Json语法树
本文后续:https://www.cnblogs.com/xiandedanteng/p/11973129.html 编译第一步:将文本解析成Java对象构成的语法树 第二步:将语法树输出整形好的Js ...
- JSON — Java与JSON数据互转
转换时Bean所要求的: 被转换的Bean必需是public的. Bean被转换的属性一定要有对应的get方法,且一定要是public的. Bean中不能用引用自身的this的属性,否则运行时出现et ...
- JSON——Java中的使用
1. 构建JSON方法(数据——>JSON) 这里使用Maven构建项目 在pom.xml中添加如下依赖 <dependency> <groupId>org.json&l ...
随机推荐
- Linux在丢失的情况下重置密码
1.开机菜单是 移动光标到第一行 --敲击e 2.找到UTF-8,加上空格rd.break,敲击ctrl+x 3.输入以下命令 mount -o remount,rw /sysroot chroot ...
- Flink源码阅读(二)——checkpoint源码分析
前言 在Flink原理——容错机制一文中,已对checkpoint的机制有了较为基础的介绍,本文着重从源码方面去分析checkpoint的过程.当然本文只是分析做checkpoint的调度过程,只是尽 ...
- 基于yum的方式安装Cloudera Manager Server(使用Mysql 8.0版本)
基于yum的方式安装Cloudera Manager Server(使用Mysql 8.0版本) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.安装和配置元数据库 1>. ...
- 个性化排序算法实践(三)——deepFM算法
FM通过对于每一位特征的隐变量内积来提取特征组合,最后的结果也不错,虽然理论上FM可以对高阶特征组合进行建模,但实际上因为计算复杂度原因,一般都只用到了二阶特征组合.对于高阶特征组合来说,我们很自然想 ...
- Python通过lxml库遍历xml通过xpath查询(标签,属性名称,属性值,标签对属性)
xml实例: 版本一: <?xml version="1.0" encoding="UTF-8"?><country name="c ...
- 样条插值法(Java)--在本地执行
该程序主要实现样条插值的目的,为本地执行java文件 该程序包含:样条插值法.读取文件,写入文件,字符型转double型方法等: 适合初学Java的人学习: 首次使用eclipse打jar包,中间很曲 ...
- tomcat绑定项目classes路径
在Host中加入如下内容: <Context path="" docBase="D:\svn\MainSource\WebRoot" debug=&quo ...
- C#技巧与解析(部分)
DesignMode 以下项目在设计器界面,需判断DesignMode OnPaint(e)/Form_Paint 自定义控件中需要特殊方法进行判断,如下: public partial class ...
- 2019红帽杯部分wp
xx 程序首先取输入的前4个字符作为xxtea加密的密钥之后进行xxtea加密.接着进行位置置换操作,然后又进行了以3个为一组的异或 首先逆向解出xxtea加密之后的结果 #include<st ...
- 查看java的jar包源码
1.jd-gui (windows环境) 下载地址 https://files.cnblogs.com/files/indifferent/jd-gui-windows-1.5.1.zip 下载并解压 ...