參考資料:
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