利用JsonSchema校验json数据内容的合规性(转)
原文地址:Json schema
背景:
复杂的AJAX应用程序可以与数百个不同的JSON服务进行交互,因此,引入对客户端验证的需求。
在处理校验问题方面有着很多的工具,但是通常可以将它们归为以下几类:
* 判断数据是否已被正确格式化* 手动检查形式有误的数据并尝试纠正* 手动检查形式有误的数据并将有误数据丢弃* 自动检查形式有误的数据
在这里只讨论自动校验方面的可用工具包中的json schema,son schema项目首页:http://json-schema.org/
JSON schema是一个帮助你定义、校验甚至是修复json数据格式的解决方案。它定义了一整套规则,允许我们通过定义一个schema(本身也是JSON)来描述一个JSON串的数据格式。它有如下优点:
* 描述你现有的JSON数据的格式; * 清晰的、人类/机器可读的文档结构; * 完全的结构校验,尤其适用于 自动测试 或 验证客户端提交的数据格式。
下面为一个定位信息的json schema例子
//json传输值 {"data" : {"id" : 851,"detail" : "琴千线长征路-万盛南路附近","area" : 9480,"province" : "浙江省","parentArea" : 2819,"lng" : 120.32438,"district" : "东阳市","lat" : 29.136176,"city" : "金华"} } //定位接口返回值的JSON schema {"type" : "object","properties" : {"data" : {"type" : "object","properties" : {"id" : {"type" : "integer","minimum": 0},"detail" : {"type" : "string"},"area" : {"type" : "integer"},"province" : {"type" : "string","pattern" : "^(北京市|天津市|....|浙江省)$"},"parentArea" : {"type" : "integer"},"lng" : {"type" : "number","minimum" : 73,"maximum" : 135},"district" : {"type" : "string"},"lat" : {"type" : "number","minimum" : 4,"maximum" : 54},"city" : {"type" : "string"}},"required" : ["id","detail","area","province","parentArea","lng","district","lat","city"]}},"required" : ["data"] }
可以看出:
1、json schema 本身也是一个json串
2、每个schema可以描述一个json实例,并且该json实例里每一个节点都可以用一个schema来描述,因此schema与json一样,本身也是一个层级结构,一个schema中可能嵌套着另外若干层schema
3、json schema 定义的检查规则以数据格式验证为主(字段存在性、字段类型),并可以支持一些简单的数据正确性验证(例如数值范围、字符串的模式等),但不能进行复杂的逻辑校验(例如进价必须小于售价等)。
JS JSON Schema库
表1中简要概述了4个JSON Schema库的特性
表 1. 针对 JavaScript 的 JSON Schema 验证库
库(作者) | 草案版本支持 | 库的大概规模 |
---|---|---|
JSV: JSON Schema 验证器 (Gary Court) | draft-01、draft-02 和 draft-03 | 120KB |
json-schema (Kris Zyp) | draft-03 | 10KB(需要 CommonJS) |
dojox.json.schema (Kris Zyp) | draft-02 | 10KB(需要 Dojo) |
schema.js (Andreas Kalsch) | draft-02(部分) | 10KB(需要 CommonJS) |
基于 Dojo 的应用程序可能会使用 dojox.json.schema 库,因为该库包含在工具箱中。支持多个版本的(草案)标准的应用程序可能会使用 JSV。
dojox.json.schema 看上去像是 json-schema 的一个分支,所以它们的用法非常相似。schema.js 只实现 draft-02 的一个子集。所以主要关注的是使用 dojox.json.schema 和 JSV 。
1. dojox.json.schema的使用
<html> <head><title>dojox.json.schema</title><script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.0/dojo/dojo.js"type="text/javascript"></script><script type="text/javascript">require(["dojox/json/schema"], function() {// Object to validatevar successObj = { "foo" : "bar"};var failureObj = {"foo" : 1234};// Schemavar schema = { "type": "object","properties" : {"foo" : {"type" : "string"}}};//var result = dojox.json.schema.validate(failureObj, schema);var result = dojox.json.schema.validate(successObj, schema);// Check resultsif (result.valid) {alert("Object is valid");} else {var errorArr = result.errors;alert("property : " + errorArr[0].property + "\nmessage : " + errorArr[0].message);}});</script> </head> <body> Hello, World! </body> </html>
dojox.json.schema这种方法只需要引入一个js包,不过必须是线上的,将dojo那个js下载下来后就报错不能执行。
2. JSV的使用
<head><title>JSV</title><!-- <script src="https://raw.github.com/garycourt/JSV/master/lib/uri/uri.js" type="text/javascript"></script><script src="https://raw.github.com/garycourt/JSV/master/lib/jsv.js" type="text/javascript"></script><script src="https://raw.github.com/garycourt/JSV/master/lib/json-schema-draft-03.js" type="text/javascript"></script> --><script src="js/uri.js" type="text/javascript"></script><script src="js/jsv.js" type="text/javascript"></script><script src="js/json-schema-draft-03.js" type="text/javascript"></script><script type="text/javascript">// Object to validatevar successObj = { "foo" : "bar"};var failureObj = {"foo" : 1234};// Schemavar schema = { "type": "object","properties" : {"foo" : {"type" : "string"}}};var env = JSV.createEnvironment("json-schema-draft-03"); // validatevar result = env.validate(successObj, schema);if (result.errors.length === 0) {alert("Object is valid");} else {var errorArr = result.errors;alert("uri : " + errorArr[0].uri + "\nmessage : " + errorArr[0].message);}</script> </head> <body> Hello, World! </body> </html>
JSV这种方法,需要导入3个js包,这是必须下载后才能使用。
JSV 在 errors 数组中提供了一些高级故障信息。每个错误可能包含以下属性:
* message:人类可读的错误消息。* uri:失败对象所在位置的 URI。* schemaUri:引起故障的模式的所在位置的 URI。* Attribute:引起故障的模式约束。* Details:包含更多详细信息的自由格式数组,比如预期值。
使用对比:
dojox.json.schema只需要引入一个js包,基于 Dojo 的应用程序可能会使用 dojox.json.schema 库,因为该库包含在工具箱中。校验的时候也只需要一行代码即可:var result = dojox.json.schema.validate(successObj, schema); 其中successObj为传入的JSON串,schema为校验规则。
JSV需要引入三个js包,JSV支持draft-01,draft-02,draft-03三种草案,支持多个版本的(草案)标准的应用程序可能会使用 JSV。校验的时候需要根据草案创建环境,然后再进行校验。var env = JSV.createEnvironment(“json-schema-draft-03”);
var result = env.validate(successObj, schema); 其中successObj为传入的JSON串,schema为校验规则。JSV在errors数组中提供了一些高级的故障信息,包括message:可读的错误信息;uri:失败对象所在位置的URI;schemaUri:引起故障的模式所在位置的URI;Attribute:引起故障的模式约束;Details:包含更多详细信息的自由格式数组,如果预期值。
性能对比:
一共执行50次,成功和失败分开执行,每种情况执行25次。然后记录下每次的执行时间,执行10次,取平均值。
dojox.json.schema:0.52, 4.28, 3.54, 4, 3.82, 3.64, 3.76, 4.12, 4.16, 5.6
JSV:4.5, 3.96, 3.88, 3.82, 3.98, 3.96, 3.9, 3.8, 4.1, 4.04
json schema类型 | 每次执行时间(ms) |
---|---|
dojox.json.schema | 3.744 |
JSV | 3.994 |
发现时间相差不多,JSV由于js包在本地,所以每次时间比较稳定;dojox.json.schema由于需要从网络上去加载js包,导致执行时间有时会波动很大。整体来说,就执行过程,dojox.json.schema要快不少。
Java JSON Schema库
表2给出了两种java中使用的JSON Schema库
库名称 | 地址 | 支持草案 |
---|---|---|
fge | https://github.com/daveclayton/json-schema-validator | draft-04 draft-03 |
everit | https://github.com/everit-org/json-schema | draft-04 |
建议:
- 如果在项目中使用了jackson json,那么使用fge是一个好的选择,因为fge就是使用的jackson json。
- 如果项目中使用的是org.json API,那么使用everit会更好。
- 如果是使用以上两个库以外的库,那么就使用everit,因为everit会比fge的性能好上两倍。
fge的使用:
maven配置
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.3.0</version> </dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.3.0</version> </dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.3.0</version> </dependency><dependency><groupId>com.github.fge</groupId><artifactId>json-schema-validator</artifactId><version>2.2.6</version> </dependency>
测试代码:
@Test public void testJsonSchema1() {JsonNode schema = readJsonFile("src/main/resources/Schema.json");JsonNode data = readJsonFile("src/main/resources/failure.json");ProcessingReport report = JsonSchemaFactory.byDefault().getValidator().validateUnchecked(schema, data);Assert.assertTrue(report.isSuccess()); }private JsonNode readJsonFile(String filePath) {JsonNode instance = null;try {instance = new JsonNodeReader().fromReader(new FileReader(filePath));} catch (IOException e) {e.printStackTrace();}return instance; }
真正的调用只有一行代码,需要传入验证规则和数据。分别有validate和validateUnchecked两种方法,区别在于validateUnchecked方法不会抛出ProcessingException异常。
还可以从字符串中读取json,代码如下:
@Test public void testJsonSchema2() {String failure = new String("{\"foo\":1234}");String Schema = "{\"type\": \"object\", \"properties\" : {\"foo\" : {\"type\" : \"string\"}}}";ProcessingReport report = null;try {JsonNode data = JsonLoader.fromString(failure);JsonNode schema = JsonLoader.fromString(Schema);report = JsonSchemaFactory.byDefault().getValidator().validateUnchecked(schema, data);} catch (IOException e) {e.printStackTrace();}//Assert.assertTrue(report.isSuccess());Iterator<ProcessingMessage> it = report.iterator();while (it.hasNext()) {System.out.println(it.next());} }
其中ProcessingReport对象中维护了一共迭代器,如果执行失败(执行成功时没有信息),其提供了一些高级故障信息。每个错误可能包含以下属性:
* level: 错误级别(应该就是error) * schema:引起故障的模式的所在位置的 URI * instance:错误对象 * domain:验证域 * keyword:引起错误的约束key * found:现在类型 * expected:期望类型
以上代码的json信息为:
failure.json : {"foo" : 1234}Schema.json : {"type": "object","properties" : {"foo" : {"type" : "string"}} }
执行错误信息为:
error: instance type (integer) does not match any allowed primitive type (allowed: ["string"])level: "error"schema: {"loadingURI":"#","pointer":"/properties/foo"}instance: {"pointer":"/foo"}domain: "validation"keyword: "type"found: "integer"expected: ["string"]
everit的使用:
maven配置(获取最新版本)
<dependency><groupId>org.everit.json</groupId><artifactId>org.everit.json.schema</artifactId><version>1.3.0</version> </dependency>
测试代码
@Test public void testJsonSchema3() {InputStream inputStream = getClass().getResourceAsStream("/Schema.json");JSONObject Schema = new JSONObject(new JSONTokener(inputStream));JSONObject data = new JSONObject("{\"foo\" : 1234}");Schema schema = SchemaLoader.load(Schema);try {schema.validate(data);} catch (ValidationException e) {System.out.println(e.getAllMessage());} }
如果验证失败会抛出一个ValidationException异常,然后在catch块中打印出错误信息。everit中的错误信息想比fge来说比较简单,相同的json测试文件,打印的信息如下:
#/foo: expected type: String, found: Integer
性能测试:
1、一共执行1000次,成功和失败分开执行,每种情况执行250次。然后记录下每次的执行时间,执行10次,取平均值。
fge每1000次的执行时间(ms):1158, 1122, 1120, 1042, 1180, 1254, 1198,1126,1177,1192
everit每1000次的执行时间(ms):33, 49, 54, 57, 51, 47, 48, 52, 53, 44
2、一共执行10000次,成功和失败分开执行,每种情况执行2500次。
方法/场景 | 每次执行时间(ms) |
---|---|
fge/场景1 | 1.1569 |
fge/场景2 | 0.3407 |
everit/场景1 | 0.0488 |
everit/场景2 | 0.0206 |
使用对比:
从性能上来说everit完全是碾压fge,官方说的至少两倍,实际测试过程中,差不多有20倍的差距。虽然fge使用的是jackson json,相对来说学习成本可能较低,但是使用下来发现everit的使用也并不复杂,需要注意的是包需要导入正确(org.json)。fge唯一的优势在于错误信息比较详细。还有一点区别在于,everit验证失败是抛出异常,而fge是判断返回一个boolean类型的值。
转载于:https://www.cnblogs.com/huanghongbo/p/8628607.html
利用JsonSchema校验json数据内容的合规性(转)相关推荐
- Linux7081端口,bash,linux_利用shell将json数据解析后排序问题,bash,linux,ubuntu,json - phpStudy...
利用shell将json数据解析后排序问题 最近在写一个模仿dropbox_uploader的百度网盘的shell脚本.通过调用pcs的api返回一个目录下的所有文件.返回的json数据如下: {&q ...
- python json 转csv_利用python将json数据转换为csv格式的方法
假设.json文件中存储的数据为: {"type": "Point", "link": "http://www.dianping. ...
- 【Power Automate系列教程】利用API获取JSON数据定时每日自动写入List
利用API获取JSON数据定时每日自动写入List 在知识星球的后台有个看数据的界面: 通过简单的抓包可以看到是个json数据,那么就有了想法! 获取到请求的api,发现规律: https://api ...
- MVC中利用ViewBag传递Json数据时的前端处理方法
** MVC中利用ViewBag传递Json数据时的前端处理方法 ** 用viewBag传递Json字符串到前端时,json字符串中的"会被转义为& quot,前端处理方法为@Htm ...
- 利用JSON-schema校验请求报文,封装转换错误信息,提示前台
JSON-chema的语法就不讲述了,可自行查阅相关文档. 需求场景:前台请求接口的报文,为防止被非法拦截,需要后台再校验一遍报文合法性,之前都是在java代码中,用java代码来判断,查阅资料找到了 ...
- 利用pyecharts对JSON数据进行可视化操作
由于pyecharts背后封装的js库,会涉及到数据类型转化.它暂时要求输入数据必须是python的基础数据类型,比如字符串,列表,字典,而不能是序列这样的数据类型.因此序列输入量需要事先被转化为li ...
- Android利用Gson解析Json数据
其实,要创建和解析JSON数据,也可以使用GSON来完成.GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库.使用GSON,可以很容易的将一串JSON数据转换为一个 ...
- python读单行文本求平均值_利用Python读取json数据并求数据平均值
要做的事情:一共十二个月的json数据(即12个json文件),json数据的一个单元如下所示.读取这些数据,并求取各个(100多个)城市年.季度平均值. { "time_point&quo ...
- 利用python将json数据转换为csv格式
假设.json文件中存储的数据为: {"type": "Point", "link": "http://www.dianping. ...
最新文章
- 用 Python 实现隐身,我可以
- python流程图-使用Graphviz快速绘制流程图
- SQL Server中的角色(服务器级别和数据库级别角色)
- Ubuntu常见问题配置
- php mysql事务处理回滚操作
- vue 插件 滑块验证_VUE接入腾讯验证码功能(滑块验证)备忘
- 视频语义显著实例分割数据集SESIV
- 陆奇下下选,YC上上签
- chart控件怎么使x轴标签全部显示出来
- C# 编译器选项 /platform(指定输出平台)32位程序运行到x64平台的问题
- 优化神器 beamoff
- TRIMMEAN函数实例:评委打分计算最后得分
- 题目0121-机器人走迷宫
- 图像处理技术-基本运算
- 市场份额正在“迅速衰退”!华为将如何纾困?
- 计算机研究生搞理论出来找工作,一个计算机专业研究生的迷茫
- 【愚公系列】2022年04月 微信小程序-实时音视频录制
- verilog——74HC85四位数值比较器并扩展为16位数值比较器
- 【Linux基础】Ubuntu 20.04系统安装(完整版)
- 各个公司项目阶段划分
热门文章
- QQ给附近的人群发消息,需要验证的自动申请为好友 按键精灵源码
- Echarts主题更换
- 科技自主研发的FCRM-壹脉销客智能名片系统
- 考公第二轮 | 资料分析
- 百度竞价账户选对关键词究竟有多重要?如何进行关键词筛选
- nes模拟器java怎么用_PC版FC模拟器怎么用 VirtuaNES使用设置教程
- 安卓逆向系列教程 4.10 玄奥八字
- 朋友今天问俺,日文输入法无法打出日语汉字?
- github.io地址
- 华为emui3.1 android,华为EMUI3.1开发版怎么升级?升级EMUI3.1开发版5.9.1的方法