上篇文章主要介绍了JSON Schema的标准、规范、实现(),接下来本文重点介绍JSON Schema的基本概念、使用。
三、快速开始
- 官网链接:http://json-schema.org/learn/ 、http://json-schema.org/understanding-json-schema/
- json schema在线校验工具:https://jsonschemalint.com/
- json schema在线生成功能:https://json-schema-inferrer.herokuapp.com/ 、https://hellosean1025.github.io/json-schema-visual-editor/
- json格式化、压缩、转义在线工具:https://www.bejson.com/
1、what is schema?
如果您曾经使用过XML Schema,RelaxNG或ASN.1,则可能已经知道什么是schema。要了解JSON Schema,首先要是知道什么事JSON。JSON代表“ JavaScript对象表示法”,一种简单的数据交换格式。它最初是作为万维网的一种表示法,由于大多数网络浏览器中都存在JavaScript,并且JSON基于JavaScript,因此很容易在其中进行支持。js的基本数据类型:
- object:{ "key1": "value1", "key2": "value2" }
- array:["a","b"]
- number:1、1.2
- string:“string”
- boolean:true、false
- null:null
利用这些简单的数据类型,可以表示各种结构化数据。但是,由于其灵活性,导致同一概念可以以多种方式表示。例如:
{
"name": "George Washington",
"birthday": "February 22, 1732",
"address": "Mount Vernon, Virginia, United States"
}
{
"first_name": "George",
"last_name": "Washington",
"birthday": "1732-02-22",
"address": {
"street_address": "3200 Mount Vernon Memorial Highway",
"city": "Mount Vernon",
"state": "Virginia",
"country": "United States"
}
}
以上两种写法表达了同一个信息。记录的设计将在很大程度上取决于其在应用程序中的预期用途,因此这里没有正确或错误的答案。但是,当应用程序说“给我一个人的JSON记录”时,准确知道该记录的组织方式非常重要。例如,我们需要知道需要哪些字段以及如何表示值。这就是JSON Schema的来源。
2、基础篇
2.1)特殊的schema:
在JSON Schema中,一个空对象({})是一个有效的schema,它可以兼容所有的json;同样也可以使用true代替空对象来表示匹配任何内容的schema,或者使用false表示不匹配任何内容的schema。例如:
//schema 可以匹配一下所有json
{}
//json
42
"string"
{"a":1}
//同样,true也可以匹配上面所有的json
2.2)声明json schema:
由于JSON Schema本身就是JSON,因此很难分辨出什么是JSON Schema或只是任意JSON块。 $ schema关键字用于声明某些内容为JSON模式。最好将其包括在内,尽管不是必需的。例如:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
}
2.3)keyword:
关键字 | 描述 |
$schema | 表示该JSON Schema使用的版本规范,非必填,目前最新一版“Draft-07”是2019.09发布的。每个版本的语法可能有出入,方便以后人员维护建议使用 |
title | JSON Schema文件的标题,非必填 |
description | JSON Schema文件的描述信息,非必填 |
type | 待校验元素的类型(例如,最外层的type表示待校验的是一个JSON对象,内层type分别表示待校验的元素类型为,可以是object、array、null、number,string,array,object) |
properties | JSON对象中,各个key-value对中value的限制条件 |
required | 校验的JSON对象中,必须存在的key,不存在则校验失败 |
注:type可以使用数组表示,表示多种类型。例如:
{ "type": "number" }
42 //√
42.0 //√
"42" //×
{ "type": ["number", "string"] }
42 //√
42.0 //√
"42" //√
接下里来,具体看下每种类型的具体使用。
3、JSON Schema 语法:
3.1)string类型:
用来约束json数据中value的类型,此外还可以通过一些属性来具体约束value的长度、正则...
1)minLength、maxLength:
{
"type": "string",
"minLength": 2,
"maxLength": 3
}
"A" //×
"ABCD" //×
"ABC" //√
2)正则表达式:
正则表达式语法是JavaScript(特别是ECMA 262)中定义的语法。具体可以查看:http://json-schema.org/understanding-json-schema/reference/regular_expressions.html#regular-expressions
{
"type": "string",
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
}
"555-1212" //√
"(888)555-1212 ext. 532" //×
3)Format:
不常用,值只能是以下的取值date-time(时间格式)、email(邮件格式)、hostname(网站地址格式)、ipv4、ipv6、uri、uri-reference、uri-template、json-pointer。假如要校验的字符串是邮箱格式的可以使用"forma":"email",而不用pattern自己去指定正则表达式。
3.2)integer、number类型:
integer表示整型,number表示浮点型数据。
注:对“整数”类型的精确处理可能取决于JSON Schema验证程序的实现,JavaScript(以及JSON)没有整数和浮点值的不同类型。因此,JSON Schema不能单独使用类型来区分整数和非整数。JSON Schema规范建议(但不要求)验证者使用数学值确定数字是否为整数,而不是单独的类型。因此,在这一点上,验证者之间存在一些分歧。例如,基于JavaScript的验证器可以接受1.0作为整数,而基于Python的jsonschema不接受。
1)multipleOf:
可以使用关键字multipleOf将数字限制为给定数字的倍数。
{
"type" : "number",
"multipleOf" : 10
}
20 //√
23 //×
2)range:
- x ≥ minimum
- x > exclusiveMinimum
- x ≤ maximum
- x < exclusiveMaximum
{
"type": "number",
"minimum": 0,
"exclusiveMaximum": 100
}
-1 //×
100 //×
99 //√
3.3)boolean:
{ "type": "boolean" }
true //√
false //√
0 //×
"true" //×
3.4)null:
{ "type": "null" }
null //√
false //×
0 //×
"" //×
3.5)object:
1)properties:
使用properties关键字定义对象上的属性(键值对)。属性的值是一个对象,其中每个键是json数据中的属性名称,每个值是用于验证该属性的JSON Schema。
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "number"
},
"name": {
"type": "string"
}
}
}
{} //√
{"id":1} //√
{"name":"test"} //√
{"id":1,"name":"test"} //√
{"id":1,"name":"test","other":1} //√
可以使用enum指定某个字段的值。例如:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "number"
},
"name": {
"type": "string",
"enum": ["a", "b"]
}
}
}
{} //√
{"name":"a"} //√
{"name":""} //×
{"name":"c"} //×
2)additionalProperties :
additionalProperties关键字用于控制json数据中的字段是否允许超过JSON Schema中定义的字段。默认情况下允许,additionalProperties值可以是布尔型,也可以是对象(用来指定允许哪些类型)
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "number"
},
"name": {
"type": "string"
}
},
"additionalProperties": false
}
{} //√
{"id":1} //√
{"name":"test"} //√
{"id":1,"name":"test"} //√
{"id":1,"name":"test","other":1} //×
也可以通过additionalProperties控制允许哪些类型的字段,例如:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "number"
},
"name": {
"type": "string"
}
},
"additionalProperties": false
}
{} //√
{"id":1} //√
{"name":"test"} //√
{"id":1,"name":"test"} //√
{"id":1,"name":"test","other":"1"} //√
{"id":1,"name":"test","other":1} //×
3)required:
默认,json数据中的字段可以比JSON Schema中定义的字段多或者少。可以使用additionalProperties 来控制json数据中的字段不能多于JSON Schema中定义的字段;同样,可以使用required控制某些JSON Schema中的字段,必须要在json数据中出现。
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "number"
},
"name": {
"type": "string"
}
},
"required": [
"name"
]
}
{} //×
{"id":1} //×
{"name":"test"} //√
{"id":1,"name":"test"} //√
{"id":1,"name":"test","other":1} //√
4)Pattern Properties:
additionalProperties 和required可以限制json中的字段是否符合JSON Schema中的定义。可以进一步通过pattern来限制那些符合某些正则的字段。
{
"type": "object",
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
},
"additionalProperties": false
}
{} //√
{ "S_25": "This is a string" } //√
{ "I_0": 42 } //√
{"a":1} //×
{"b":"b"} //×
5)Property names:
draft6新特性,Property names可以根据schema验证属性的名称,而不管其值、类型如何。如果您不想强制使用特定的属性,但是要确保这些属性的名称遵循特定的约定,这将很有用。
{
"type": "object",
"propertyNames": {
"pattern": "^a"
}
}
{} //√
{"a":1} //√
{"a":"1"} //√
{"a":{}} //√
{"a":[]} //√
{"b":1} //×
6)Property dependencies:
我们使用dependencies关键字表示一个属性对另一个属性的依赖。 dependency关键字的值是一个对象。对象中的每个条目都从属性名p映射到列出存在p时所需的属性的字符串数组。
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" },
"billing_address": { "type": "string" }
},
"dependencies": {
"credit_card": ["billing_address"]
}
}
{"name":"John Doe","credit_card":555,"billing_address":"555 Debtor's Lane"}//√
{"billing_address":"555 Debtor's Lane"}//√
{"credit_card":555} //×
7)Schema dependencies:
Schema dependencies的工作方式类似于Property dependencies,但是它们不仅可以指定其他必需的属性,还可以扩展模式使其具有其他约束。
8)size:
{
"type": "object",
"minProperties": 2,
"maxProperties": 3
}
{ "a": 0, "b": 1 } //√
{ "a": 0, "b": 1, "c": 2 } //√
{ "a": 0 }//×
{} //×
3.6)array:
{ "type": "array" }
[1, 2, 3, 4, 5] //√
[3, "different", { "types" : "of values" }] //√
1)items:
可以使用items限制数组中元素的类型。
{
"type": "array",
"items": {
"type": "number"
}
}
[] //√
[1, 2, 3, 4, 5] //√
[1, 2, "3", 4, 5] //×
此外,可以通过items来指定数组中每个元素的类型。(有顺序要求的)
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "string"
}
]
}
[1] //√
[1,"Pennsylvania"] //√
[1, "Pennsylvania",1] //√
["Pennsylvania"] //×
["Pennsylvania",1] //×
同时,也可以使用additionalItems来限制是否允许其他类型存在。
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "string"
}
],
"additionalItems": false
}
[1] //√
[1,"Pennsylvania"] //√
["Pennsylvania"] //×
["Pennsylvania",1] //×
[1, "Pennsylvania",1] //×
2)contains:
draft6新增特性。items是校验数组中每个元素类型,contains用来校验一个或多个元素。
{
"type": "array",
"contains": {
"type": "number"
}
}
["life", "universe", "everything", 42] //√
["life", "universe", "everything"] //×
3)Tuple validation:
可以使用enum,对数组中每个元素的取值进行校验。例如:
{
"type": "array",
"items": [
{
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
},
{
"type": "string",
"enum": ["NW", "NE", "SW", "SE"]
}
]
}
["Avenue", "NW"] //√
["Avenue", "2NW"] //×
4)length:
{
"type": "array",
"minItems": 2,
"maxItems": 3
}
[] //√
[1,2,] //√
[1,2,3] //√
[1,2,3,4] //×
5)uniqueness:
{
"type": "array",
"uniqueItems": true
}
[] //√
[1, 2, 3, 4, 5] //√
[1, 2, 3, 4, 5, 5] //×
4、高级篇:
4.1)combining schemas:
可以使用allOf、anyOf、oneOf、not 将多个JSON Schema组合起来使用,形成具有一定逻辑关系的schema。
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
4.2)reuse:
重用是编程中最核心的思想之一。JSON Schema也可以重用。
1)definitions、$ref:
我们可以将一个JSON Schema放到definitions中,供其他地方重用。可以通过$ref来引用definitions中的schema。(通过JSON Pointer)
2)看一个例子:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": { "$ref": "#/definitions/address" }
},
"required": ["shipping_address", "billing_address"]
}
//json
{
"shipping_address": {
"street_address": "1600 Pennsylvania Avenue NW",
"city": "Washington",
"state": "DC"
},
"billing_address": {
"street_address": "1st Street SE",
"city": "Washington",
"state": "DC"
}
}
4.3)Recursion(递归):
$ ref元素可用于创建引用自己的递归模式。例如,您可能具有一个包含多个子级的人员模式,每个子级也是人员实例。
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"person": {
"type": "object",
"properties": {
"name": { "type": "string" },
"children": {
"type": "array",
"items": { "$ref": "#/definitions/person" },
"default": []
}
}
}
},
"type": "object",
"properties": {
"person": { "$ref": "#/definitions/person" }
}
}
//json
{
"person": {
"name": "Elizabeth",
"children": [
{
"name": "Charles",
"children": [
{
"name": "William",
"children": [
{ "name": "George" },
{ "name": "Charlotte" }
]
},
{
"name": "Harry"
}
]
}
]
}
}
4.4)$id:
可以使用$id属性指向一个有效的URL。
{ "$id": "http://foo.bar/schemas/address.json" }