“Understanding JSON Schema”官方文档翻译和解读
---Release 7.0
一. 基础
{ }
接受任何有效的JSON
true
接受任何有效的JSON,等同于{ }
false
不匹配任何的JSON
type
关键字的基本类型
type的值可以是单个,也可以是一个list
$schema
声明这是一个schema, 还可以声明它针对的是哪个特定的版本
例如:
"$schema": "http://json-schema.org/schema#"
或
"$schema": "http://json-schema.org/draft-07/schema#"
$id
声明整个架构的唯一标识符
声明一个用于$ref
解析URI的基URI
例如:
声明顶级架构的$id
为
{ "$id": "http://foo.bar/schemas/address.json" }
当引用{ "$ref": "person.json" }
时
将试图从http://foo.bar/schemas/person.json这个地址来获取person.json
即使address.json是从其他地方加载的...
$id
还提供了一种在不使用JSON指针的情况下引用子模式的方法.这表示可以通过唯一的名称来引用它们,而不是它们在JSON数中的位置.
例如:
address对象的"$id": "#address"
则当引用时,可直接使用{ "$ref": "#address" }
注意:python的jsonschema库暂时不支持此功能.
二. 特定类型关键字
type
的取值:
string, integer, number, object, array, boolean, null
2.1 string
{ "type": "string" }
minLength
和 maxLength
约束字符串长度
例如:
{
"type": "string",
"minLength": 2,
"maxLength": 3
}
pattern
将字符串限制为特定的正则表达式
format
对常用的某些字符串进行基本语义验证.允许将值限制为超出JSON Schema中的其他工具.
日期和时间
"date-time": Date and time together, for example, 2018-11-13T20:20:39+00:00.
"time": New in draft 7 Time, for example, 20:20:39+00:00
"date": New in draft 7 Date, for example, 2018-11-13.
Email地址
"email": Internet email address, see RFC 5322, section 3.4.1.
"idn-email": New in draft 7 The internationalized form of an Internet email address, see RFC 6531.
Hostnames
"hostname": Internet host name, see RFC 1034, section 3.1.
"idn-hostname": New in draft 7 An internationalized Internet host name, see RFC5890, section 2.3.2.3.
IP地址
"ipv4": IPv4 address, according to dotted-quad ABNF syntax as defined in RFC 2673, section 3.2.
"ipv6": IPv6 address, as defined in RFC 2373, section 2.2.
资源标识符
"uri": A universal resource identifier (URI), according to RFC3986.
"uri-reference": New in draft 6 A URI Reference (either a URI or a relative-reference), according to RFC3986, section 4.1.
"iri": New in draft 7 The internationalized equivalent of a “uri”, according to RFC3987.
"iri-reference": New in draft 7 The internationalized equivalent of a “uri-reference”, according to RFC3987
如果模式中的值能够相对于特定源路径(例如来自网页的链接),则通常更好的做法是使用 "uri-reference"(或"iri-reference")而不是"uri"(或 "iri")。"uri"只应在路径必须是绝对路径时使用。
URI模板
"uri-template":草案6中的新内容根据RFC6570的 URI模板(任何级别) 。如果您还不知道URI模板是什么,则可能不需要此值。
JSON指针
"json-pointer":根据RFC6901 ,草案6中的新功能 JSON指针。在结构化复杂模式中,有更多关于JSON指针在JSON模式中的使用的讨论。请注意,仅当整个字符串仅包含JSON指针内容时才应使用此选项.
例如 /foo/bar
而 #/foo/bar/ 应该使用 "uri-reference"
"relative-json-pointer":草案7中的新内容相对JSON指针。
正则表达式
"regex":草案7中的新内容正则表达式,根据ECMA 262 方言应该有效
2.2 integer
{"type": "integer"}
代表整数
警告:
“整数”类型的精确处理可能取决于JSON模式验证器的实现。JavaScript(以及JSON)没有针对整数和浮点值的不同类型。因此,JSON Schema不能单独使用类型来区分整数和非整数。JSON Schema规范建议但不要求验证器使用数学值来确定数字是否为整数,而不是单独的类型。因此,在这一点上验证者之间存在一些分歧。例如,基于JavaScript的验证器可以接受1.0为整数,而基于Python的jsonschema则不接受。
所以可以使用multipleOf关键字来解决这种差异
例如:
{ "type": "number", "multipleOf": 1.0 }
可以匹配42,也可以匹配42.0
但不能匹配3.1415926
2.3 number
{"type": "number"}
匹配任何数字类型,包括整数,浮点数甚至指数表示法.
multipleOf
可匹配给定数字的倍数,它的取值可以使任何正数.
例如:
{
"type" : "number",
"multipleOf" : 10
}
则代表匹配10的倍数.
0,10,20等等都是正向用例.
minimum
和 maximum
minimum <= X <= maximum
exclusiveMinimum
和exclusiveMaximum
exclusiveMinimum < X < exclusiveMaximum
注意,在草案4中,exclusiveMinimum和 exclusiveMaximum的取值是 true 或 false.
2.4 object
{ "type": "object" }
properties
定义对象上的属性(键值对)
required
必须出现的字段
additionalProperties
控制额外内容的处理,即名称未在properties中列出的属性.默认允许任何其他属性.
该关键字可以是一个布尔值或对象.
如果是布尔值并设置为false,则不允许其他属性出现.
如果是对象,则该对象是将用于验证未列出的任何其他属性的模式
例如:
允许其他属性出现,但前提是他们的值都是字符串:
"additionalProperties": { "type": "string" }
因此当某一个不存在的properties的值不是字符串类型时,将报错.
propertyNames
只验证属性的名称,而不校验它的值.
例如:
{
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
}
}
只有匹配该正则的属性名称才被认为有效.并且一定是字符串.(因为对象键无论如何必须始终是字符串)
patternProperties
验证属性的名称符合正则并且指定它的属性
例如:
{
"type": "object",
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
},
"additionalProperties": false
}
以上架构验证了以前缀S_开头的任何其他属性必须是字符串,以前缀为I_开头的任何其他属性必须是整数.
patternProperties
和additionalProperties
可以结合使用.
例如:
{
"type": "object",
"properties": {
"builtin": { "type": "number" }
},
"patternProperties": {
"^S_": { "type": "string" },
"^I_": { "type": "integer" }
},
"additionalProperties": { "type": "string" }
}
以上表示当属性既不是内置的,也不匹配patternProperties时, 它的值必须是string.
minProperties
和 maxProperties
限制对象上的属性数量.必须是非负整数.
例如:
{
"type": "object",
"minProperties": 2,
"maxProperties": 3
}
该schema匹配只有两个或三个属性名称的对象.
dependencies
属性依赖
dependencies关键字表示一个属性,对另一个属性的依赖关系.
它的值是一个对象,对象中的每个条目都从属性名称银蛇到一个字符串数组,列出了该属性名称存在时所需的属性.
例如:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" },
"billing_address": { "type": "string" }
},
"required": ["name"],
"dependencies": {
"credit_card": ["billing_address"]
}
}
该schema描述了,每当存在credit_card时,还必须存在billing_address
但这个依赖不是双向的. 当存在billing_address时,没有credit_card也是可以的.
当我们需要定义一个双向的依赖关系时,可以这样处理:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" },
"billing_address": { "type": "string" }
},
"required": ["name"],
"dependencies": {
"credit_card": ["billing_address"],
"billing_address": ["credit_card"]
}
}
模式依赖
作用类似于属性依赖项,但他们不是仅指定其他必须属性,而是可以扩展模式以具有其他约束.
例如:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" }
},
"required": ["name"],
"dependencies": {
"credit_card": {
"properties": {
"billing_address": { "type": "string" }
},
"required": ["billing_address"]
}
}
}
2.5 array
{ "type": "array" }
列表验证
items
任意长度的序列,其中每个项目匹配相同的模式。
对于这种数组,items就是单个的schema,这个schema用于验证数组中的所有项.
当items是单个schema时, additionalItems这个关键字没有意义.
items的值是一个对象{ }
contains
虽然items必须对数组中的每个项有效, 但是contains只需要针对数组中的一个或多个项进行验证
例如:
{
"type": "array",
"contains": {
"type": "number"
}
}
只要被验证项中存在一个number,该项就被验证成功了.
元组验证
items
每个字段都有不同的架构.此时items的值是一个list[ ]
此时按索引序号进行验证.
additionalItems
当该关键字的值为布尔值时,
该关键字控制当超出所定义的数组中的其他项时,是否有效.
默认情况下如果没有这个字段或值为true,是允许其他额外项的.
当该关键字的值是一个对象时
该关键字将对额外项进行描述
例如:
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "string"
},
{
"type": "string",
"enum": ["Street", "Avenue", "Boulevard"]
},
{
"type": "string",
"enum": ["NW", "NE", "SW", "SE"]
}
],
"additionalItems": { "type": "string" }
}
这个列表中的额外项必须是string类型.
minItems
和 maxItems
指定数组的长度
uniqueItems
确保数组中的每个项都是唯一的.
2.6 boolean
{ "type": "boolean" }
该字段只接收布尔值
2.7 null
{ "type": "null" }
该字段只能必须是null
false, 0, "" 都不能通过校验
三. 通用关键字
3.1 注释类
title
description
default
examples
这四个关键字都不用于验证,只用来描述.并且也不是必须的.
3.2 评论
$comment
草案7新增关键字.用于向jsonschema添加注释.它的值必须始终是一个字符串.
3.3 枚举
enum
该关键字用于限制值,它必须是一个至少包含一个元素的数组,并且其中每一个元素都是唯一的.
enum即便没有被标明类型,也仍然可以接受不同类型的值.
但是如果type被定义,即便该值在enum中,也必须遵循type原则.
3.4 常数
const
该字段用于将值限值为单个值.
四. 媒体:字符串编码,非JSON数据
contentMediaType
该关键字指定媒体类型
支持的类型参见:
http://www.iana.org/assignments/media-types/media-types.xhtml
但具体仍然要取决于应用程序和操作系统.
对web很重要的MIME类型参见:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types
例如:
{
"type": "string",
"contentMediaType": "text/html"
}
该模式指定了一个包含HTML文档的字符串
正确的匹配示例:
"<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head></html>"
contentEncoding
该关键字用于指定存储内容
可接受的值为7bit,8bit,binary,quoted-printable 和base64。
如果内容是二进制的数据,可设置为base64,这将包括许多图像类型,例如 image/png 或音频类型,例如 audio/mpeg
例如:
{
"type": "string",
"contentEncoding": "base64",
"contentMediaType": "image/png"
}
该模式表示字符串包含使用base64编码的PNG图像
正确的匹配示例:
"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA..."
五. 组合模式
-
allOf
:必须对所有子模式有效 -
anyOf
:必须对任何子模式有效 -
oneOf
:必须对其中一个子模式有效
allOf
给定值必须对所有给定的子schema有效
例如:
{
"allOf": [
{ "type": "string" },
{ "maxLength": 5 }
]
}
则:
"short"
为正确匹配
"too long"
为错误匹配
逻辑上不可能成立的schema:
{
"allOf": [
{ "type": "string" },
{ "type": "number" }
]
}
anyOf
给定值必须对任何一个或多个给定的子schema有效.
只要一个值对这些schema中的任何一个进行验证成功,则认为它对整个组合schema有效
例如:
{
"anyOf": [
{ "type": "string", "maxLength": 5 },
{ "type": "number", "minimum": 0 }
]
}
则:
"short"
为正确匹配
"too long"
为错误匹配
12
为正确匹配
-5
为错误匹配
oneOf
给定值必须仅对其中一个给定子schema有效
例如:
{
"oneOf": [
{ "type": "number", "multipleOf": 5 },
{ "type": "number", "multipleOf": 3 }
]
}
则:
10
为正确匹配
9
为正确匹配
2
为错误匹配,因为它不是5或3的倍数。
15
为错误匹配,因为它匹配多个
可以分解子schema的公共部分
例如:以下schema等同于上述schema
{
"type": "number",
"oneOf": [
{ "multipleOf": 5 },
{ "multipleOf": 3 }
]
}
not
例如:
{ "not": { "type": "string" } }
则:
42
为正确匹配
{ "key": "value" }
为正确匹配,因为它是一个对象
"I am a string"
为错误匹配
六. 有条件地应用子模式
if
, then
和 else
关键字
如果if生效,则then必须生效,然后else会被忽略
如果if无效,则else必须生效,then会被忽略.
例如:
假设您想编写一个模式来处理美国和加拿大的地址。这些国家/地区有不同的邮政编码格式,我们希望根据国家/地区选择要验证的格式。如果地址在美国,则该postal_code字段为“zipcode”:五个数字后跟可选的四位数后缀。如果地址位于加拿大,则该postal_code字段是六位数的字母数字字符串,其中字母和数字交替显示。
{
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"country": {
"enum": ["United States of America", "Canada"]
}
},
"if": {
"properties": { "country": { "const": "United States of America" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
},
"else": {
"properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
}
}
则:
{
"street_address": "1600 Pennsylvania Avenue NW",
"country": "United States of America",
"postal_code": "20500"
}
为正确校验
{
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "K1M 1M4"
}
为正确校验
{
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "10000"
}
为错误校验
当需要处理两个以上的内容时, 可以用if和then ,然后用allOf关键字把它们包裹起来.
例如:
{
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"country": {
"enum": ["United States of America", "Canada", "Netherlands"]
}
},
"allOf": [
{
"if": {
"properties": { "country": { "const": "United States of America" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
}
},
{
"if": {
"properties": { "country": { "const": "Canada" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
}
},
{
"if": {
"properties": { "country": { "const": "Netherlands" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{4} [A-Z]{2}" } }
}
}
]
}
则:
{
"street_address": "1600 Pennsylvania Avenue NW",
"country": "United States of America",
"postal_code": "20500"
}
为正确校验
{
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "K1M 1M4"
}
为正确校验
{
"street_address": "Adriaan Goekooplaan",
"country": "Netherlands",
"postal_code": "2517 JX"
}
为正确校验
{
"street_address": "24 Sussex Drive",
"country": "Canada",
"postal_code": "10000"
}
为错误校验
十. 构建jsonschema的复杂模式
10.1 重用
我们可以使用$ref关键字从其他地方引用此架构片段 。
{ "$ref": "#/definitions/address" }
完整举例:
{
"$schema": "http://json-schema.org/draft-07/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" }
}
}
$ref
也可以是相对或绝对URI,因此如果您希望将定义包含在单独的文件中,也可以这样做。
例如:
{ "$ref": "definitions.json#/address" }
将从另一个文件中加载地址模式。
10.2 递归
$ref
元素可用于创建引用自身的递归模式。例如,您可能拥有一个person包含数组的模式children,每个模式也是person实例。
例如:
{
"$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" }
}
}
则:
英国王室树的片段:
{
"person": {
"name": "Elizabeth",
"children": [
{
"name": "Charles",
"children": [
{
"name": "William",
"children": [
{ "name": "George" },
{ "name": "Charlotte" }
]
},
{
"name": "Harry"
}
]
}
]
}
}
可通过校验
上面,我们创建了一个引用自身另一部分的模式,有效地在验证器中创建了一个“循环”,这既是允许的又是有用的。但请注意,相互$ref引用的模式循环可能会导致解析器中的无限循环,并且明确禁止。
例如:
{
"definitions": {
"alice": {
"anyOf": [
{ "$ref": "#/definitions/bob" }
]
},
"bob": {
"anyOf": [
{ "$ref": "#/definitions/alice" }
]
}
}
}
10.3 扩展
当$ref
与组合关键字allOf
, anyOf
, oneOf
一起使用
举例:
{
"$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": {
"allOf": [
{ "$ref": "#/definitions/address" },
{ "properties":
{ "type": { "enum": [ "residential", "business" ] } },
"required": ["type"]
}
]
}
}
}
以上模式首先定义了一个address的模式. 下方具体字段有账单地址, 他的模式与address相同. 有送货地址, 该地址除了与address模式要相同以外,还必须额外存在一个type字段.