app开发者平台在数字化时代的重要性与发展趋势解析
772
2022-11-14
json字段选取器介绍和实现
最近为了工作方便写了一个小工具,这个小工具作用很简单,就是从一个json字符串中筛出你想要的部分。
介绍
背景是这样的,我们为了线上调试方便,有个工具可以模拟发起一次数据请求,然后将结果以json的形式展示到页面上。但问题是这个数据包含的信息非常多,动不动就上千行(如上图),但每次debug的时候,只想看里面特定的几个字段,平常只能依赖于浏览器搜索工具一行一行搜,可能想看的字段会间隔好几屏,一行行看即低效还容易漏。 如果要看JsonArray的数据,我之前是拷贝出来,然后用grep把字段筛出来,但这样又丢失了层级信息。。。。。如果我们想把某些字段列一起用于数据分析的话,就更难了,只能人肉筛选记录。。。
我这个工具采用很简单的语法来标识目标json的层级结构,以及每一层中你想要的字段。语法类似yaml的层级结果,用相同的缩减标识同一层,每一层的关键词是你想要的字段key,不区分大小写,为了更方便使用,也支持正则表达式。 当然这里有几个特殊规则: 1.如果当前层级是个jsonArray的话字段后面需要加后缀:[]来标识出来(后续我可能会在中括号中支持范围)。 2. 第一行必须随便写个字段,保留这个字段的目的还是怕一上来就是个JsonArray。 3. 目前暂时不能加空行,尤其是多行之间,会导致筛选有问题。
示例如下,也可以试用demo。
json menu id popup menuitem:[] value
实现
如果你了解json数据格式的话,就知道它是一个层级嵌套的结构,而层级嵌套结构它其实很容易去转换成一种树形的结构。事实上现在市面上所有的json解析器,其实都是将这些数据转换成树形结构存储的。知道json是一个树形结构之后,我们是不是构造一个同构的子树,同构子树的含义树每一层包含更少的节点,但有的节点和原树的节点同构。
如何构造或者说描述这样一个同构的树形结构? 这里我选用了类似yaml的描述,它采用了不同缩进来标识层级关系。
1 2 3 4 5 6
比如这个,2 4 节点为1的子节点,3是2的子节点,5 6是4的子节点。 有了描述语言,接下来的一步就是将描述语言转化为抽象语法树。这里我采用编译原理中的递归下降算法,用递归的方式构造每个节点的子节点。
为了方便,我首先将语法描述预处理下,主要是将缩进转化为层级深度,然后递归解析,解析代码如下。
public class Node { public int type = 0; //jsonObject or jsonArray Map
整个解析完之后就是一颗抽象语法树。json字符串我用fastjson解析后也是树形层级结构,因为我们新生成的语法树和json语法树是同构的关系,所以我们可以同时递归遍历新语法树和抽象语法树,并同时生成一个筛选后的json字符串,这样我们完成了匹配筛选的过程,代码如下。
public Object getSelected(Object object) { // 无子节点 if (children.size() == 0) { return object; } JSONObject res = new JSONObject(true); JSONObject json = (JSONObject)object; for (Map.Entry
最后写个类封装下所有API即可。
public class JsonSelector { private Node startNode; private JsonSelector() {}; // 编译生成语法树 public static JsonSelector compile(String txt) { // 预处理 txt = txt.replace("\t", " "); String[] arr = txt.split("\n"); int[] deeps = new int[arr.length]; String[] keys = new String[arr.length]; for (int i = 0; i < arr.length; i++) { String str = arr[i]; deeps[i] = getSpaceCnt(str); keys[i] = rmSpace(str); } JsonSelector selector = new JsonSelector(); selector.startNode = new Node(keys, deeps, 0); return selector; } public String getSelectedString(String jsonStr) { JSONObject json = JSONObject.parseObject(jsonStr, Feature.OrderedField); JSONObject res = (JSONObject) startNode.getSelected(json); return res.toJSONString(); } private static int getSpaceCnt(String str) { int cnt = 0; for (cnt = 0; cnt < str.length(); cnt++) { if (str.charAt(cnt) != ' ') { break; } } return cnt; } private static String rmSpace(String str) { String res = str.trim(); int end = res.length(); while(end > 0 && res.charAt(end - 1) == ' ') { end--; } return res.substring(0, end); }}
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~