前段时间,老王在写项目代码的时候,要用到JSON。但是每次用的时候,因为都是压缩的,所以要去做一次格式化。到网上一搜在线JSON格式化工具,找到几个感觉还不错,不过因为我的JSON串很大,一贴进去,网页就卡死了。于是乎,作为程序员的老王,就萌发了写一个JSON解析和格式化的工具。咱说干就干,老王花了几天晚上,就写了这样一个。今天整好借着机会分享给大家~

这里先把地址发给大家,代码和效果地址:SimpleMain.com(老王自己去申请了一个域名,做了ICP备案,买了一个阿里云最便宜的服务器,现在把文章都放上去了。后面准备把自己开发中想用的工具都放上去&开源。现在没有做手机版兼容,所以大家用PC打开效果最好),有兴趣的同学可以敲下这个域名体验一下(订阅号不能贴链接, T_T)。

言归正传,做JSON格式化,大体上是分两步:JSON的解析 + JSON的格式化输出。

1JSON的解析:

这一步的主要工作,就是将一个字符串(比如:“[100,44.5]”)转化成内存中的数据结构(比如:arraynumber等)。这一步基本就是类似做编译原理里面的词法、语法、语意的分析。为了保证JSON解析的完整性,老王参照了JSON官方标准(http://json.org/)来编写。不过,在此基础上做了一个升级。就是如果遇到错误,只要还有往下解析的可能,老王的程序就不会停留在错误的地方,而是会尽量解析完所有的字符串。最后将所有错误的地方,报告出来。类似现在流行的编译器。

上图就显示了,在一个JSON-Object里面,遇到引号不规范、数字不规范的时候,解析器会尽量往下解析,而不是一遇到错误就停止。

好了,那我们具体来看看老王是如何来设计这个解析器的。

A、字符串中获取有效字符。

老王先设计了一个Symbol类,这个类的目的,就是管理输入的字符串,并从中提取一个个有效的字符。我在这里偷了些懒,借用了java.nio.CharBuffer的一些功能。他有两个很重要的方法:nextnextWithoutSpace,用来获取下一个字符。为什么要有这两个方法呢,因为我们在解析的时候,类似{“a” : “I love this game”}冒号前后的空格符对于解析是没有意义的,而引号里面的空格是有意义的。所以获取的时候,要根据上下文的情况,来调用不同的函数获取相应的字符。

B、解析

老王定义了一个主解析类:JsonParser。他只是一个壳儿,用来接收用户的JSON字符串输入,然后调用可能的真正的解析类:ObjectParserArrayParser去尝试着解析。如果其中一个能解析,就返回;否则,尝试完所有可能以后,还是不能解析,就报错返回。

如果这个时候,字符串是以“[“作为第一个有效字符,ArrayParser就开始工作。这个代码主要是四大段:

a、检查是否是“[“开始;

b、依次调用ValueParser去识别每一个Value

c、检查是否是“,”分隔。如果是,则跳回到b重复执行;否则就跳出执行下一步;

d、检查是否是“]”结束。

有兴趣的朋友可以详细看看这段代码,老王觉得写的还是比较清晰的。而ValueParser也是按照标准,用不同类型的Parser去尝试解析:

如果能解析成功,则直接返回;否则继续尝试下一个Parser直到尝试完毕。

如果一开始是以“{“这个字符开始的,则用ObjectParser来尝试解析。具体解析的方法和ArrayParser是类似的。

好了,通过以上的工作,我们最终就得到了一个JsonElement。他本来应该是一个接口,但是为了方便做格式化遍历的工作,老王把他设计成了一个抽象类,继承和实现了Iterator接口。他包含很多子类:JsonObjectJsonArrayJsonNumberJsonBooleanJsonString等等。

每个元素都是通过对应的Parser识别产生出来的。他们的工作主要是用来表明类型,以及格式化输出的时候,做对应的自我展示。

好了,解析的过程大体就是这样。每一个类型的详细解释老王就不再赘述,具体要看的话,可以看看老王的源代码(simplemain.com)。

2JSON的格式化:

如果一切顺利,没有太大的问题,我们就将一个字符串转化成了内存里那个JsonElement根对象了(他可能包含更多的子对象:儿子、孙子、重孙子等等)。那我们格式化输出的时候,就是采用这种顺藤摸瓜的逻辑,从这个根开始,深度优先的遍历这棵树,输出这个JsonElement

为了在不同场景下实现格式化,比如:在shellcmd的情况下,是需要输出纯文本的;在web的情况下,是要输出html的等等,老王抽象了一个JsonFormatter的接口,输入是JsonElement这个根元素,以及一个PrintWriter(用于作为抽象的输出流)。另外,实现了一个MetaFormatter,这个类用来做原始格式化,他会将JsonElement组织成一行一行的,每行多少个缩进、有多少个异常等等Meta信息都会被提取出来。

最后我们做逻辑实现的时候,只需要调用这个MetaFormatter就可以轻松实现我们大多数场景下的格式化需求。

上面这个就是老王实现的一个纯文本的格式化类TextJsonFormatter。在SimpleMain.com的网页上,老王也是从简单的调用MetaFormatter来实现了Html的生成。

MetaFormatter的实现,比较麻烦的一点就是深度优先遍历JsonElement树。为了让代码写起来好看一些,老王用了Iterator接口,将深度遍历变成了一个递归迭代的过程,每个JsonElement实体对象负责做自己的Iterator,这样就从代码层面上尽量降低了耦合。有兴趣的同学可以看看这一部分的代码,还是有些意思。

另外,最近很流行emoji表情符,老王也在代码里对实体字符做了转义,支持了emoji表情的展示,感觉还是很有意思的,哈哈哈~

以上就是一个调用的代码和纯文本的JSON格式化效果,输出中包含了行号、错误的行、错误的信息等等。大家有兴趣的话,就去下载代码试试吧。

因为代码是开源的,大家可以尽情的去改。如果发现bug,可以提给老王哈~ 对应的地址大家别忘了:SimpleMain.com

声明:本站为非盈利性赞助网站,本站所有软件来自互联网,版权属原著所有,如有需要请购买正版。如有侵权,敬请来信联系我们,我们立即删除。