参考资料:
http://json-schema.org/
https://github.com/Julian/jsonschema
https://python-jsonschema.readthedocs.io/en/stable/
https://github.com/dmeranda/demjson
https://jsonschema.net/#/editor
https://github.com/json-path/JsonPath
1. 总体介绍
本文尝试通过json数据校验方法解决如下几个问题:
- 1.数据没有校验,系统处于裸奔状态,导致后期维护成本高;
- 2.编写一堆校验代码,混杂在业务代码中,导致代码可读性降低;
- 3.API交付的时候提供一大段接口描述文档,但用户还是要揣测文档意思。
- 4.自动校验json格式
- 5.自动纠正json错误格式
- 6.对于多层嵌套问题进行深入探讨
- 7.对于array拆分展开
- 8.特殊字符处理
2. Json Schema
Json Schema主要用在前后端Json数据交互校验上,一般解决的需求是1,2,3的问题,规定好每一个字段是什么类型比如:
from jsonschema import validate
schema = {
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/example.json",
"type": "object",
"title": "The Root Schema",
"required": [
"checked",
"dimensions",
"id",
"name",
"price",
"tags"
],
"properties": {
"checked": {
"$id": "/properties/checked",
"type": "boolean",
"title": "The Checked Schema",
"default": false,
"examples": [
false
]
},
"dimensions": {
"$id": "/properties/dimensions",
"type": "object",
"title": "The Dimensions Schema",
"required": [
"width",
"height"
],
"properties": {
"width": {
"$id": "/properties/dimensions/properties/width",
"type": "integer",
"title": "The Width Schema",
"default": 0,
"examples": [
5
]
},
"height": {
"$id": "/properties/dimensions/properties/height",
"type": "integer",
"title": "The Height Schema",
"default": 0,
"examples": [
10
]
}
}
},
"id": {
"$id": "/properties/id",
"type": "integer",
"title": "The Id Schema",
"default": 0,
"examples": [
1
]
},
"name": {
"$id": "/properties/name",
"type": "string",
"title": "The Name Schema",
"default": "",
"examples": [
"A green door"
],
"pattern": "^(.*)$"
},
"price": {
"$id": "/properties/price",
"type": "number",
"title": "The Price Schema",
"default": 0.0,
"examples": [
12.5
]
},
"tags": {
"$id": "/properties/tags",
"type": "array",
"title": "The Tags Schema",
"items": {
"$id": "/properties/tags/items",
"type": "string",
"title": "The 0 Schema",
"default": "",
"examples": [
"home",
"green"
],
"pattern": "^(.*)$"
}
}
}
}
test_json = {
"checked": false,
"dimensions": {
"width": 5,
"height": 10
},
"id": 1,
"name": "A green door",
"price": 12.5,
"tags": [
"home",
"green"
]
}
test_val = validate(instance=test_json,schema=test_schema)
具体用法可参考json schema的官方网站,比如自己写的json可以通过https://jsonschema.net/#/editor进行转换成schema格式做自动校验
3. JsonPath
JsonPath是一种简单的方法来提取给定JSON文档的部分内容。 JsonPath有许多编程语言,如Javascript,Python和PHP,Java。
JsonPath提供的json解析非常强大,它提供了类似正则表达式的语法,基本上可以满足所有你想要获得的json内容。下面我把官网介绍的每个表达式用代码实现,可以更直观的知道该怎么用它。
JsonPath表达式总是以与XPath表达式结合使用XML文档相同的方式引用JSON结构。
JsonPath中的“根成员对象”始终称为$,无论是对象还是数组。
JsonPath表达式可以使用点表示法
$.store.book [0].title
或括号表示法
$['store']['book'][0]['title']
3.1 操作符
操作 说明
$ 查询根元素。这将启动所有路径表达式。
@ 当前节点由过滤谓词处理。
* 通配符,必要时可用任何地方的名称或数字。
.. 深层扫描。 必要时在任何地方可以使用名称。
.<name> 点,表示子节点
['<name>' (, '<name>')] 括号表示子项
[<number> (, <number>)] 数组索引或索引
[start:end] 数组切片操作
[?(<expression>)] 过滤表达式。 表达式必须求值为一个布尔值。
3.2 函数
函数可以在路径的尾部调用,函数的输出是路径表达式的输出,该函数的输出是由函数本身所决定的。
函数 描述 输出
min() 提供数字数组的最小值 Double
max() 提供数字数组的最大值 Double
avg() 提供数字数组的平均值 Double
stddev() 提供数字数组的标准偏差值 Double
length() 提供数组的长度 Integer
3.3 过滤器运算符
过滤器是用于筛选数组的逻辑表达式。一个典型的过滤器将是[?(@.age > 18)],其中@表示正在处理的当前项目。 可以使用逻辑运算符&&和||创建更复杂的过滤器。 字符串文字必须用单引号或双引号括起来([?(@.color == ‘blue’)] 或者 [?(@.color == “blue”)]).
操作符 描述
== left等于right(注意1不等于'1')
!= 不等于
< 小于
<= 小于等于
> 大于
>= 大于等于
=~ 匹配正则表达式[?(@.name =~ /foo.*?/i)]
in 左边存在于右边 [?(@.size in ['S', 'M'])]
nin 左边不存在于右边
size (数组或字符串)长度
empty (数组或字符串)为空
3.4 python版本的jsonpath
https://github.com/kennknowles/python-jsonpath-rw
此库主要是为了方便json数据查询
from jsonpath_rw import jsonpath, parse
sJOSN = {
"test": "123",
"remote_user": "-",
"request_time": {
"receive_time": "14",
"from_time": "23",
"to_time": 45
},
"day1": {
"day2": {
"day3-1": "123",
"day3-2": "234"
}
},
}
jsonpath_expr = parse('day1.day2.day3-2')
match = jsonpath_expr.find(sJOSN)
print("day:",match,type(match))
4、对json数据格式自动检测自动纠正
当时业务上有这方面需求,找了好多关于json开源的库,奈何没找到想要,不过幸好找到相似的开源库,在此demjson库基础上做了修改,已经放到GitHub上,有兴趣的可自取。
- 支持非标格式的json数据检测纠正
- 支持十六进制转中文
- 支持转义符
- 支持用户自定义输入depth,自动展开嵌套的json数据
https://github.com/HQCfly/correctjsonformat