“Understanding JSON Schema”官方文档翻译和解读

“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" }

minLengthmaxLength
约束字符串长度
例如:

{
  "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等等都是正向用例.

minimummaximum

minimum <= X <= maximum

exclusiveMinimumexclusiveMaximum

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_开头的任何其他属性必须是整数.

patternPropertiesadditionalProperties可以结合使用.
例如:

{
  "type": "object",
  "properties": {
    "builtin": { "type": "number" }
  },
  "patternProperties": {
    "^S_": { "type": "string" },
    "^I_": { "type": "integer" }
  },
  "additionalProperties": { "type": "string" }
}

以上表示当属性既不是内置的,也不匹配patternProperties时, 它的值必须是string.

minPropertiesmaxProperties
限制对象上的属性数量.必须是非负整数.
例如:

{
  "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类型.

minItemsmaxItems
指定数组的长度

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, thenelse 关键字
如果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字段.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342