怎么校验JSON格式是否正确?使用ANTLR轻松实现
xsobi 2024-12-06 20:28 24 浏览
JSON (JavaScript Object Notation) 是一个轻量级的数据交互格式,对人类读写比较友好,并且生成和解析比较简单。是WEB传输和系统交互常用的数据格式。
JSON的数据格式比较简单,有两种结构:键值对的集合或者是值的数组,这两种格式又可以相互嵌套,下面是个简单的JSON字符串:
//{"persion":{"addr":[{"com":"北京朝阳"},{"home":"山东济南"}],"age":12,"name":"张三"}}
{
"persion": {
"addr": [
{
"com": "北京朝阳"
},
{
"home": "山东济南"
}
],
"age": 12,
"name": "张三"
}
}
下面使用ANTLR解析JSON字符串,如果不了解怎么安装ANLTR,请参考从零开始学习ANTLR4,Windows下搭建环境。
首先需要获取JSON的语法文件,如果不想自己写语法文件,可以在GITHUB上搜索"grammars-v4",然后找到JSON.g4文件即可,以下就是最新版本的JSON.g4。
//JOSN.g4
grammar JSON;
json
: value EOF
;
obj
: '{' pair (',' pair)* '}'
| '{' '}'
;
pair
: STRING ':' value
;
arr
: '[' value (',' value)* ']'
| '[' ']'
;
value
: STRING
| NUMBER
| obj
| arr
| 'true'
| 'false'
| 'null'
;
STRING
: '"' (ESC | SAFECODEPOINT)* '"'
;
fragment ESC
: '\\' (["\\/bfnrt] | UNICODE)
;
fragment UNICODE
: 'u' HEX HEX HEX HEX
;
fragment HEX
: [0-9a-fA-F]
;
fragment SAFECODEPOINT
: ~ ["\\\u0000-\u001F]
;
NUMBER
: '-'? INT ('.' [0-9] +)? EXP?
;
fragment INT
// integer part forbis leading 0s (e.g. `01`)
: '0' | [1-9] [0-9]*
;
// no leading zeros
fragment EXP
// exponent number permits leading 0s (e.g. `1e01`)
: [Ee] [+\-]? [0-9]+
;
// \- since - means "range" inside [...]
WS
: [ \t\n\r] + -> skip
;
下面就可以生成对应的Java文件了,有两种方式,一种是插件方式,一种是命令行模式,如果不熟悉也可以参考从零开始学习ANTLR4,Windows下搭建环境,下图就是生成后的文件:
先使用TestRig来生成语法树,TestRig是ANTLR内置的一个语法调试工具,使用参数-gui生成可视化的语法树:
java -cp .;./antlr-4.9.3-complete.jar org.antlr.v4.gui.TestRig JSON json -gui
{"persion":{"addr":[{"com":"北京朝阳"},{"home":"山东济南"}],"age":12,"name":"张三"}}
重点来了,使用测试程序来校验JSON的正确性,ANTLR内置了一个错误监听器ConsoleErrorListener,如果语法错误的时候会在控制台输出错误信息,还是使用上面的JSON字符串测试,先使用正确的格式测试,最终输出一颗正确语法树,并且没有输入语法错误信息。
package antlr4.json;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
public class TestJson {
public static void main(String[] args) {
String jsonStr = "{\"persion\":{\"addr\":[{\"com\":\"北京朝阳\"},{\"home\":\"山东济南\"}],\"age\":12,\"name\":\"张三\"}}";
CharStream charStream = CharStreams.fromString(jsonStr);
JSONLexer jsonLexer = new JSONLexer(charStream);
CommonTokenStream commonTokenStream = new CommonTokenStream(jsonLexer);
//语法分析器
JSONParser jsonParser = new JSONParser(commonTokenStream);
JSONParser.JsonContext jsonContext = jsonParser.json();
//打印语法树
System.out.println(jsonContext.toStringTree(jsonParser));
}
}
//输出结果
(json (value (obj { (pair "persion" : (value (obj { (pair "addr" : (value (arr [ (value (obj { (pair "com" : (value "北京朝阳")) })) , (value (obj { (pair "home" : (value "山东济南")) })) ]))) , (pair "age" : (value 12)) , (pair "name" : (value "张三")) }))) })) <EOF>)
把JSON稍微改一下,删除最后的一个},测试结果如下,在控制台打印JSON语法的错误信息,你还会发现此时也打印了一颗语法树,但是这个语法树跳过了最后的词法符合}。如果有必要可以实现自定义的错误监听器,只要在解析前添加到语法分析器中即可,有时间的可以试试。
//JSON: {"persion":{"addr":[{"com":"北京朝阳"},{"home":"山东济南"}],"age":12,"name":"张三"}
line 1:73 mismatched input '<EOF>' expecting {',', '}'}
(json (value (obj { (pair "persion" : (value (obj { (pair "addr" : (value (arr [ (value (obj { (pair "com" : (value "北京朝阳")) })) , (value (obj { (pair "home" : (value "山东济南")) })) ]))) , (pair "age" : (value 12)) , (pair "name" : (value "张三")) }))))) <EOF>)
相关推荐
- 建站 | 从零开始打造自己的网站--以创意众筹网项目为例
-
文/跨界哥经过前几期的思考探索,跨界哥的创意众筹网项目的大概框架已经有了雏形,今天真正开始着手网站的建设。从零开始打造属于自己的网站,自己终于做了站长,想想还是有点小激动。简单描述下创意众筹网的核心业...
- MyEclipse应用服务器教程:应用程序服务器入门指南(上)
-
1.定义一个新的服务器定义一个新的服务器允许您选择需要使用的服务器连接,并提供配置信息,然后选择项目部署到服务器上。(1)在服务器视图工具栏上点击new_server_icon。或者右键单击服务器视...
- ABP异常为什么是403呢?
-
前言在ABP中使用UserFriendlyException抛出异常,HTTP状态码为什么是403?下面用这一段测试代码:[HttpPost]publicasyncTask<PeopleD...
- Web自动化测试:模拟鼠标操作(ActionChains)
-
在日常的测试中,经常会遇到需要鼠标去操作的一些事情,比如说悬浮菜单、拖动验证码等,这一节我们来学习如何使用webdriver模拟鼠标的操作首页模拟鼠标的操作要首先引入ActionChains的包fro...
- webapi 全流程
-
C#中的WebAPIMinimalApi没有控制器,普通api有控制器,MinimalApi是直达型,精简了很多中间代码,广泛适用于微服务架构MinimalApi一切都在组控制台应用程序类【Progr...
- SpringBoot日志处理之Logback
-
日志处理是一个正式项目必备的功能,日志要能够根据时间、类型等要素,根据指定格式来保存指定的日志,方便我们观察程序运行情况、定位程序bug。SpringBoot中推荐使用Logback日志框架。slf4...
- ASP.NET Core Web API 接口限流
-
一.前言ASP.NETCoreWebAPI接口限流、限制接口并发数量,我也不知道自己写的有没有问题,抛砖引玉、欢迎来喷!二.需求写了一个接口,参数可以传多个人员,也可以传单个人员,时间范围...
- 高德打车通用可编排订单状态机引擎设计
-
一背景订单状态流转是交易系统的最为核心的工作,订单系统往往都会存在状态多、链路长、逻辑复杂的特点,还存在多场景、多类型、多业务维度等业务特性。在保证订单状态流转稳定性的前提下、可扩展性和可维护性是我...
- .Net6基础功能封装分享12(统一参数校验)
-
开发后台webapi接口,需要对接口传入的参数进行校验,如果传入的参数不符合验证规则,就直接返回参数错误,就需要封装统一参数校验过滤器;在.net6中,内置了DataAnnotations实现通过数据...
- Path to prosperity for US and the world lies in cooperation, not confrontation
-
ThisisaneditorialfromChinaDaily.Turningadeafeartothe"handsoff"criesofprotestersnot...
- C++ strategy策略模式
-
策略模式策略模式是一种行为设计模式,它定义了一组算法,他们可以以相同的接口共享。这种模式使用场景最多的就是在根据不同的条件选择不同的行为时,可以使用此模式进行解耦,使得你的代码更加易于维护和扩展,当然...
- 万字图文详解24种设计模式
-
一直想写一篇介绍设计模式的文章,让读者可以很快看完,而且一看就懂,看懂就会用,同时不会将各个模式搞混。自认为本文还是写得不错,花了不少心思来写这文章和做图,力求让读者真的能看着简单同时有所收获。设计模...
- 25000 字详解 23 种设计模式(多图 + 代码)
-
文章来源:https://javadoop.com/post/design-pattern目录创建型模式结构型模式行为型模式总结前言一直想写一篇介绍设计模式的文章,让读者可以很快看完,而且一看就懂,看...
- C# 设计模式之-状态模式
-
问题引入仓库管理系统中,堆垛机任务的状态的变更,一般会引起一系列相关的的变更,如入库完成,就需要修改库位状态为:工作中;出库完成,则需要将任务对应的库位状态修改为:空闲;此时可以使用状态模式来将堆垛机...
- seata-golang 接入指南
-
作者|刘晓敏来源|阿里巴巴云原生公众号seata-golang是一个分布式事务框架,实现了AT模式和TCC模式,AT模式相较TCC模式对代码的入侵性更小、需要开发的接口更少;但A...
- 一周热门
- 最近发表
- 标签列表
-
- grid 设置 (58)
- 移位运算 (48)
- not specified (45)
- 导航栏 (58)
- context xml (46)
- scroll (43)
- dedecms模版 (53)
- c 视频教程下载 (33)
- listview排序 (33)
- characterencodingfilter (33)
- getmonth (34)
- label换行 (33)
- android studio 3 0 (34)
- html转js (35)
- 索引的作用 (33)
- checkedlistbox (34)
- xmlhttp (35)
- mysql更改密码 (34)
- 权限777 (33)
- htmlposition (33)
- 学校网站模板 (34)
- textarea换行 (34)
- 轮播 (34)
- asp net三层架构 (38)
- bash (34)