CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

json schema用途(不看后悔)java json schema,JSON Schema 规范(中文版),免费源码交易平台,

1.json-schema

理解 JSON Schema本内容翻译自《Understanding JSON Schema》JSON Schema 是用于验证 JSON 数据结构的强大工具,Schema可以理解为模式或者规则然而,通过阅读它的规范来学习如何使用就像通过查看汽车的设计图来学习驾驶汽车。

2.JSON Schema

如果您只想买些杂货,那你是不需要知道电动机是如何组合在一起的因此,本书旨在成为 JSON Schema 使用的友好讲师它适用于那些想要编写并理解它,但可能目前对构建自己的汽车——呃,编写自己的 JSON 模式验证器不感兴趣的人。

3.json schema生成工具

笔记:本书主要是基于 JSON Schema Draft 7早期版本的 JSON Schema 与这里描述的格式不完全兼容,但在大多数情况下,这些差异都会在文本中注明从哪里开始?本书使用了一些新颖的约定来展示模式示例并将 JSON 模式与您选择的编程语言相关联。

4.json schema python

如果您不确定什么是模式,请查看什么是模式?.基础章节应该足以让您开始了解核心JSON 模式参考当您开始开发具有许多嵌套和重复部分的大型模式时,请查看构建复杂模式json-schema.org有很多资源,包括官方规范和使用各种编程语言的 JSON Schema 的工具。

5.json schema校验

有许多在线 JSON 模式工具允许您针对示例文档运行自己的 JSON 模式如果您想在不安装任何软件的情况下进行尝试,这些会非常方便一、本书中使用的约定特定语言注释当来自另一种动态语言时,JavaScript 和 JSON 中基本类型的名称可能会令人困惑。

我白天是一名 Python 程序员,所以当事物的名称与它们在 Python 中的名称不同时,我会在此处注明,以及任何其他特定于 Python 的使用 JSON 和 JSON Schema 的建议我绝不试图对这本书产生 Python 偏见,但这是我所知道的,所以我从那里开始。

从长远来看,我希望这本书对各行各业的程序员都有用,所以如果您有兴趣将 Python 参考翻译成 Algol-68 或您可能知道的任何其他语言,欢迎提出请求!??特定语言部分显示为每种语言的选项卡一旦您选择了一种语言,当您逐页阅读时,该选择将被记住。

例如,这里有一个特定于语言的部分,其中包含有关在几种不同语言中使用 JSON 的建议:在 Python 中,可以使用标准库中的 json 模块读取 JSON在 Ruby 中,可以使用 json gem 读取 JSON。

对于 C,你可能要考虑使用Jansson来读写 JSON特定 Draft 注释JSON Schema 标准已经过多次修订或 Draft当前版本是 Draft 7,但 Draft 4 仍然被广泛使用编写该文本是为了鼓励使用Draft 7 并优先考虑最新的约定和功能,但在与早期版本不同的地方,这些差异在特殊标注中突出显示。

如果您只想针对 Draft 7,您可以放心地忽略这些部分Draft 7 中的新内容Draft特定信息:例子本书中有许多示例,它们都遵循相同的格式每个示例的开头是一个简短的 JSON 模式,说明了一个特定的原则,然后是针对该模式有效或无效的简短 JSON 片段。

有效示例标记ok无效的例子标记not ok通常会有注释来解释为什么有效或无效笔记:每当构建本书时,这些示例都会自动进行测试,以保证它们不仅有用,而且正确!例如,这是一个说明如何使用number类型的片段:

{ “type”: “number” }42 // ok-1 // ok5.0 //简单的浮点数 ok2.99792458e8 //指数计数法 ok”42″ // 作为字符串的数字 not ok二、什么是 Schema ?

如果您曾经使用过 XML Schema、RelaxNG 或 ASN.1,您可能已经知道什么是模式,并且可以愉快地跳到下一部分如果这一切对您来说听起来像天书,那么您来对地方了要定义 JSON Schema 是什么,我们可能应该首先定义 JSON 是什么。

JSON 代表“JavaScript Object Notation”,一种简单的数据交换格式它最初是作为万维网的符号由于 JavaScript 存在于大多数 Web 浏览器中,并且 JSON 基于 JavaScript,因此很容易支持。

然而,它已被证明足够有用且足够简单,以至于它现在被用于许多其他不涉及网上冲浪的环境中从本质上讲,JSON 建立在以下数据结构上:对象(object){ “key1”: “value1”, “key2”: “value2” }

数组(array)[ “first”, “second”, “third” ]数字(integer/number)423.1415926字符串(string)”This is a string”布尔值(boolean)

truefalsenullnull在大多数编程语言中都有类似类型,尽管它们可能有不同的名称。下表从 JSON 类型的名称映射到它们在 Python 中的类似类型:

[^4]: 由于 JSON 字符串始终支持 unicode,因此它们类似于Python 2.x 中unicode和Python 3.x中的str [^5]: JSON 没有单独的整数和浮点类型下表将 JSON 类型的名称映射到它们在 Ruby 中的类似类型:

[^6]: JSON 没有单独的整数和浮点类型通过这些简单的数据类型,各种结构化数据都可以被表示然而,这种巨大的灵活性伴随着巨大的责任,因为同一个概念可以以多种方式表示例如,您可以想象以不同的方式在 JSON 中表示一个人的信息:。

{ “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 的用武之地以下 JSON Schema 片段描述了上面第二个示例的结构现在不要太担心细节它们将在后续章节中进行解释。

{ “type”: “object”, “properties”: { “first_name”: { “type”: “string” }, “last_name”: { “type”: “string” }, “birthday”: { “type”: “string”, “format”: “date” }, “address”: { “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “city”: { “type”: “string” }, “state”: { “type”: “string” }, “country”: { “type” : “string” } } } }}

通过针对此模式“验证”的一个失败案例如下:{ “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 Schema 本身是用 JSON 编写的它是数据本身,而不是计算机程序它只是一种用于“描述其他数据结构”的声明性格式这既是它的优点也是它的缺点(它与其他类似的模式语言共享)简明地描述数据的表面结构并根据它自动验证数据很容易。

但是,由于 JSON Schema 不能包含任意代码,因此在表达数据元素之间的关系上有所限制因此,用于足够复杂的数据格式的任何“验证工具”都可能有两个验证阶段:一个在模式(或结构)级别,一个在语义级别后一种检查可能需要使用更通用的编程语言来实现。

三、基础概览在学习任何新语言时,从最简单的事情开始通常会很有帮助在 JSON 模式中,空对象是一个完全有效的模式,它将接受任何有效的 JSON{}这可以接受任何内容,只要它是有效的 JSON42 // OK”Im a string” // OK\{ “an”: \[ “arbitrarily”, “nested” \], “data”: “structure” \} // OK。

Draft 6 中的新内容您还可以使用true代替空对象来表示匹配任何内容的模式,或者false表示不匹配任何内容的模式true // 该模式表示可以接受任何内容,只要它是有效的 JSON42 // OK”Im a string” // OK{ “an”: [ “arbitrarily”, “nested” ], “data”: “structure” } // OK。

false // 该模式表示不匹配任何内容”Resistance is futile… This will always fail\!\!\!” //not OK类型关键字当然,如果我们只想接受任何 JSON 文档,我们就不会使用 JSON Schema。

在 JSON Schema 中最常见的事情是限制为特定类型,type关键字就用于此当本书提到 JSON Schema“关键字”时,它指的是对象中键/值对的“键”部分编写 JSON Schema 的大部分工作都涉及将特殊的“关键字”映射到对象中的值。

例如,在下面,只接受字符串:{ “type”: “string” }”Im a string” // OK42 // not OKtype关键字在类型特异性的关键字进行了更详细的描述声明一个 JSON 模式。

判断 JSON Schema 使用的是哪个draft并不总是那么容易您可以使用$schema关键字来声明架构写入的 JSON 模式规范是哪个版本更多信息,请参阅$schema包含它通常是一种很好的做法,尽管它不是必需的。

笔记为简洁起见,本书的大多数示例中不包含$schema关键字,但在实际使用中应始终使用该关键字{ “$schema”: “http://json-schema.org/draft-07/schema#” }。

在 Draft 4 中,$schema值是http://json-schema.org/schema#指最新版本的 JSON Schema此用法已被弃用,并且需要使用特定版本的 URI声明唯一标识符将$id

属性包含为每个模式的唯一标识符也是最佳实践现在,只需将其设置为您控制的域中的 URL,例如:{ “$id”: “http://yourdomain.com/schemas/myschema.json” }。

当您开始构建复杂模式时,$id 的细节变得更加明显在draft 4 中,$id 只是 id(没有$符号)四、JSON Schema 规范数据类型type关键字是 JSON Schema 的基础它指定 Schema 的数据类型。

JSON Schema 的核心定义了以下基本类型:stringnumberintegerobjectarray布尔值null在大多数编程语言中都有类似类型,尽管它们可能有不同的名称下表从 JSON 类型的名称映射到它们在 Python 中的类似类型:。

[^4]: 由于 JSON 字符串始终支持 unicode,因此它们类似于Python 2.x 中unicode和Python 3.x中的str [^5]: JSON 没有单独的整数和浮点类型下表将 JSON 类型的名称映射到它们在 Ruby 中的类似类型:

[^6]: JSON 没有单独的整数和浮点类型type关键字可以是一个字符串或数组:如果是字符串,则是上述基本类型之一的名称如果是数组,则必须是字符串数组,其中每个字符串是其中一种基本类型的名称,每个元素都是唯一的。

在这种情况下,如果 JSON 片段与_任何_给定类型匹配,则它是有效的这是使用type关键字的简单示例:{ “type”: “number” }42 // OK42.0 // OK”42″ //not ok。

这不是一个数字,它是一个包含数字的字符串在以下示例中,我们接受字符串和数字,但不接受结构化数据类型:{ “type”: [“number”, “string”] }42 // OK”Life, the universe, and everything” // OK[“Life”, “the universe”, “and everything”] // not OK

对于这些类型中的每一种,都有仅适用于这些类型的关键字例如,数字类型有一种指定数字范围的方法,这不适用于其他类型在本参考中,这些验证关键字及其对应的每个类型都在后面章节中进行了描述字符串(string)该

string类型用于文本字符串它可能包含 Unicode 字符在 Python 中,“string”类似于Python 2.x 上的unicode和 Python 3.x 上的str类型在 Ruby 中,“string”类似于。

String 类型{ “type”: “string” }”This is a string” // OK”Déjà vu” // OK,Unicode 字符”” // OK”42″ // OK42 // not OK

长度可以使用minLength和maxLength关键字来限制字符串的长度对于这两个关键字,该值必须是非负数{“type”: “string”, “minLength”: 2, “maxLength”: 3}”A””AB””ABC””ABCD”。

正则表达式pattern关键字用于将字符串限制为特定的正则表达式正则表达式语法是在 JavaScript(特别是ECMA 262)中定义的有关更多信息,请参阅正则表达式笔记 在定义正则表达式时,重要的是要注意,如果表达式匹配字符串中的任何位置,则该字符串被认为是有效的。

例如,正则表达式”p”将匹配任何包含一个p的字符串,例如”apple”不仅仅是一个简单的字符串”p”因此,将正则表达式括在^…$中(例如,”^p$”),通常不会令人困惑,除非有充分的理由不这样做以下示例匹配一个带有可选区号的简单北美电话号码:

{ “type”: “string”, “pattern”: “^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$”}”555-1212″ // OK”(888)555-1212″ // OK”(888)555-1212 ext. 532″ // not OK”(800)FLOWERS” // not OK

格式该format关键字允许对常用的某些类型的字符串值进行基本语义验证这允许限制值超出 JSON 模式中的其他工具,包括 正则表达式可以做的不需要 JSON Schema 实现来实现规范的这一部分,而且其中很多都不需要。

JSON Schema 规范中偏向于与网络相关的格式,这很可能是由于其在 Web 技术方面的传统但是,也可以使用自定义格式,只要交换 JSON 文档的各方也交换有关自定义格式类型的信息即可JSON Schema 验证器将忽略它不理解的任何格式类型。

内置格式以下是 JSON Schema 规范中指定的格式列表日期和时间日期和时间在RFC 3339 第 5.6 节中表示这是日期格式的子集,也通常称为ISO8601 格式”date-time”:日期和时间在一起,例如, 。

2018-11-13T20:20:39+00:00″time”:draft7的时间,例如,20:20:39+00:00″date”:draft7的日期,例如,2018-11-13电子邮件地址”email”。

:Internet 电子邮件地址,请参阅RFC 5322,第 3.4.1 节”idn-email”:draft7的新内容Internet 电子邮件地址的国际化形式,请参阅RFC 6531主机名”hostname”。

: Internet 主机名,请参阅RFC 1034,第 3.1 节”idn-hostname”:draft7的 中的新内容,国际化 Internet 主机名,请参阅RFC5890,第 2.3.2.3 节。

IP 地址”ipv4″:IPv4 地址,根据RFC 2673 第 3.2 节中定义的点分四线 ABNF 语法”ipv6″:IPv6 地址,如RFC 2373 第 2.2 节中所定义资源标识符”uri”:根据

RFC3986 的通用资源标识符 (URI) “uri-reference”:draft7 6 中的新增内容,一个 URI 引用(URI 或相对引用),根据RFC3986 第 4.1 节”iri”:draft 7 中的新内容,根据

RFC3987,“uri”的国际化等价物”iri-reference”:draft7中的新内容,根据RFC3987,“uri-reference”的国际化等价物如果模式中的值能够与特定的源路径(例如来自网页的链接)相关联,那么使用。

“uri-reference”(or”iri-reference”) 而不是”uri”(or”iri”)通常是更好的做法 “uri”只应在路径必须是绝对路径时使用draft 4 只包括”uri”,不包括。

“uri-reference”因此,是否”uri”应该接受相对路径存在一些歧义URI 模板”uri-template”:draft 6 中的新增内容,一个 URI 模板(任何级别)根据RFC6570如果您还不知道 URI 模板是什么,您可能不需要这个值。

JSON 指针”json-pointer”:draft6 中的新内容,一个 JSON 指针,根据RFC6901在Structuring a complex schema 中有更多关于在 JSON Schema 中使用 JSON Pointer 的讨论。

请注意,仅当整个字符串仅包含 JSON 指针内容时才应使用此方法,例如/foo/bar. JSON 指针 URI 片段,例如#/foo/bar/应该使用”uri-reference”.”relative-json-pointer”

:draft7 中的新内容,一个相对 JSON 指针正则表达式”regex”:draft7中的新内容,正则表达式,根据ECMA 262应有效请注意,在实践中,JSON 模式验证器只需要接受本文档其他地方描述的正则表达式的安全子集。

正则表达式示例以下示例匹配一个带有可选区号的简单北美电话号码:{ “type”: “string”, “pattern”: “^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$”}”555-1212″ // OK”(888)555-1212″ // OK”(888)555-1212 ext. 532″ // not OK”(800)FLOWERS” // not OK

数字类型(integer/number)integerinteger类型用于整数JSON 没有针对整数和浮点值的不同类型因此,有无小数点并不足以区分整数和非整数例如,1和1.0是在 JSON 中表示相同值的两种方式。

无论使用哪种表示形式,JSON 模式都将该值视为整数在 Python 中,“integer”类似于int类型,在 Ruby 中,“integer”类似于Integer类型{ “type”: “integer” }42 // OK\-1 // OK1.0 // OK,小数部分为零的数字被视为整数3.1415926 // not OK,浮点数被拒绝”42″ // not OK,作为字符串的数字被拒绝

number该number类型用于任何数字类型,整数或浮点数在 Python 中,“数字”类似于float类型在 Ruby 中,“数字”类似于Float类型{ “type”: “number” }42 // OK\-1 // OK5.0 // OK,简单的浮点数2.99792458e8 // OK,指数符号也有效”42″ // not OK,作为字符串的数字被拒绝。

倍数可以使用multipleOf关键字将数字限制为给定数字的倍数 它可以设置为任何正数{ “type”: “number”, “multipleOf” : 10}0 // OK10 // OK20 // OK23 // not OK,不是 10 的倍数。

范围数字的范围是使用minimum和maximum关键字的组合指定的 (或exclusiveMinimum和exclusiveMaximum用于表示排他范围)如果x是要验证的值,则以下必须成立:x ≥ 。

minimumx > exclusiveMinimumx ≤ maximumx < exclusiveMaximum虽然您可以同时指定minimum和exclusiveMinimum或同时 指定maximum

和exclusiveMaximum,但这样做没有意义{ “type”: “number”, “minimum”: 0, “exclusiveMaximum”: 100}-1 // not OK,小于00 // OK10 // OK99 // OK100 // not OK101 // not OK。

Draft 4在 JSON Schema draft4 中,exclusiveMinimum和exclusiveMaximum工作方式不同它们是布尔值,指示是否minimum和maximum不包括该值例如:。

如果exclusiveMinimum是false,x ≥ minimum如果exclusiveMinimum是true, x > minimum新版本已更改为具有更好的关键字独立性这是一个使用旧Draft 4 约定的示例:。

{ “type”: “number”, “minimum”: 0, “maximum”: 100, “exclusiveMaximum”: true }-1 // not OK,小于00 // OK10 // OK99 // OK100 // not OK101 // not OK

对象(object)对象是 JSON 中的映射类型他们将“键”映射到“值”在 JSON 中,“键”必须始终是字符串这些对中的每一个通常被称为“值”在 Python 中,“对象”类似于dict类型然而,一个重要的区别是,虽然 Python 字典可以使用任何可散列的键作为键,但在 JSON 中,所有键都必须是字符串。

尽量不要被此处“对象”一词的两种用法所混淆:Python 使用该词object来表示所有事物的通用基类,而在 JSON 中,它仅用于表示从字符串键到值的映射在 Ruby 中,“对象”类似于Hash类型然而,一个重要的区别是 JSON 中的所有键都必须是字符串,因此任何非字符串键都被转换为它们的字符串表示。

尽量不要被这里“对象”一词的两种用法所混淆:Ruby 使用这个词Object来表示所有事物的通用基类,而在 JSON 中,它仅用于表示从字符串键到值的映射{ “type”: “object” }{// OK “key”: “value”, “another_key”: “another_value”}{// OK “Sun”: 1.9891e30, “Jupiter”: 1.8986e27, “Saturn”: 5.6846e26, “Neptune”: 10.243e25, “Uranus”: 8.6810e25, “Earth”: 5.9736e24, “Venus”: 4.8685e24, “Mars”: 6.4185e23, “Mercury”: 3.3022e23, “Moon”: 7.349e22, “Pluto”: 1.25e22}{// not OK,使用非字符串作为键是无效的 JSON 0.01: “cm”, 1: “m”, 1000: “km”}”Not an object” // not OK,使用非字符串作为键是无效的 JSON[“An”, “array”, “not”, “an”, “object”] // not OK。

属性对象的属性(键值对)是使用properties关键字定义的 properties的值是一个对象,其中每个键是属性的名称,每个值是用于验证该属性的模式此properties关键字将忽略与关键字中的任何属性名称不匹配的任何属性。

注意:禁止不符合任何属性名称的属性properties,请参阅附加属性例如,我们要为由数字、街道名称和街道类型组成的地址定义一个简单的模式:{ “type”: “object”, “properties”: { “number”: { “type”: “number” }, “street_name”: { “type”: “string” }, “street_type”: { “enum”: [“Street”, “Avenue”, “Boulevard”] } }}// OK{ “number”: 1600, “street_name”: “Pennsylvania”, “street_type”: “Avenue” }// not OK,提供的号码类型错误,则无效{ “number”: “1600”, “street_name”: “Pennsylvania”, “street_type”: “Avenue” }// OK,默认情况下,省略属性是有效的。

请参阅必需属性{ “number”: 1600, “street_name”: “Pennsylvania” }// OK,通过扩展,即使是空对象也是有效的{}// OK,默认情况下,提供附加属性是有效的:{ “number”: 1600, “street_name”: “Pennsylvania”, “street_type”: “Avenue”, “direction”: “NW” }。

模式属性有时您想说,给定一种特定类型的属性名称,该值应该与特定模式相匹配这就是patternProperties起作用的地方 :它将正则表达式映射到模式如果属性名称与给定的正则表达式匹配,则属性值必须针对相应的架构进行验证。

注意:正则表达式没有锚定这意味着在为 定义正则表达式时patternProperties,请务必注意该表达式可能与属性名称内的任何位置匹配例如,正则表达式”p”将匹配任何包含一个p的属性名称,例如”apple”。

,而不仅仅是名称为”p”因此,将正则表达式括在^…$中通常不那么令人困惑,例如,”^p$”在此示例中,名称以前缀开头的任何属性都S_必须是字符串,并且任何具有前缀的属性都I_必须是整数任何与任一正则表达式都不匹配的属性将被忽略。

{ “type”: “object”, “patternProperties”: { “^S_”: { “type”: “string” }, “^I_”: { “type”: “integer” } }}// OK{ “S_25”: “This is a string” }// OK{ “I_0”: 42 }// not OK,如果名称以 开头S_,则必须是字符串{ “S_0”: 42 } // not OK,如果名称以 开头I_,则必须是整数{ “I_42”: “This is a string” }// OK这是一个不匹配任何正则表达式的键{ “keyword”: “value” }

额外属性该additionalProperties关键字用于控制的额外的东西,那就是性能,其名称不中列出的处理properties关键字或任何相匹配的正则表达式的patternProperties关键字。

默认情况下,允许任何其他属性additionalProperties关键字的值是一个模式,将用于验证实例中与properties或不匹配的任何属性patternProperties将additionalProperties。

架构设置 为false意味着不允许其他属性重用 Properties 中的示例,但这次设置additionalProperties为false.{ “type”: “object”, “properties”: { “number”: { “type”: “number” }, “street_name”: { “type”: “string” }, “street_type”: { “enum”: [“Street”, “Avenue”, “Boulevard”] } }, “additionalProperties”: false}// OK{ “number”: 1600, “street_name”: “Pennsylvania”, “street_type”: “Avenue” } // not OK,额外属性“direction”使对象无效{ “number”: 1600, “street_name”: “Pennsylvania”, “street_type”: “Avenue”, “direction”: “NW” }。

您可以使用非布尔模式对实例的其他属性设置更复杂的约束例如,可以允许额外的属性,但前提是它们都是一个字符串:{ “type”: “object”, “properties”: { “number”: { “type”: “number” }, “street_name”: { “type”: “string” }, “street_type”: { “enum”: [“Street”, “Avenue”, “Boulevard”] } }, “additionalProperties”: { “type”: “string” }}// OK{ “number”: 1600, “street_name”: “Pennsylvania”, “street_type”: “Avenue” }// OK,这是有效的,因为附加属性的值是一个字符串{ “number”: 1600, “street_name”: “Pennsylvania”, “street_type”: “Avenue”, “direction”: “NW” } // not OK,这是无效的,因为附加属性的值不是字符串:{ “number”: 1600, “street_name”: “Pennsylvania”, “street_type”: “Avenue”, “office_number”: 201 }。

您可以additionalProperties与properties和patternProperties组合起来使用在以下示例中,基于Pattern Properties 中的示例,我们添加了一个”builtin”。

属性,该属性必须是数字,并声明所有其他属性(既不符合properties定义,同时不匹配patternProperties)必须是字符串:{ “type”: “object”, “properties”: { “builtin”: { “type”: “number” } }, “patternProperties”: { “^S_”: { “type”: “string” }, “^I_”: { “type”: “integer” } }, “additionalProperties”: { “type”: “string” }}// OK{ “builtin”: 42 }// OK,这是一个不匹配任何正则表达式的键:{ “keyword”: “value” } // not OK,额外属性必须是一个字符串:{ “keyword”: 42 }

必须属性默认情况下,properties不需要关键字定义的属性但是,可以使用required关键字提供所需属性的列表该required关键字采用零个或多个字符串的数组这些字符串中的每一个都必须是唯一的[draft 4](

http://json-schema.org/understanding-json-schema/reference/object.html#7fb9d91c7f70_Draft4)在dreft 4 中,

required必须至少包含一个字符串{ “type”: “object”, “properties”: { “name”: { “type”: “string” }, “email”: { “type”: “string” }, “address”: { “type”: “string” }, “telephone”: { “type”: “string” } }, “required”: [“name”, “email”]}// OK{ “name”: “William Shakespeare”, “email”: “bill@stratford-upon-avon.co.uk”}// OK,提供额外的属性是可以的,即使是架构中没有定义的属性:{ “name”: “William Shakespeare”, “email”: “bill@stratford-upon-avon.co.uk”, “address”: “Henley Street, Stratford-upon-Avon, Warwickshire, England”, “authorship”: “in question”} // not OK,缺少必需的“email”属性会使 JSON 文档无效{ “name”: “William Shakespeare”, “address”: “Henley Street, Stratford-upon-Avon, Warwickshire, England”,} // not OK,在 JSON 中,具有值的属性null不等同于不存在的属性。

这失败,因为null不是“字符串”类型,而是“空”类型{ “name”: “William Shakespeare”, “address”: “Henley Street, Stratford-upon-Avon, Warwickshire, England”, “email”: null}。

属性名称draft6 中的新内容可以根据模式验证属性名称,而不管它们的值如果您不想强制执行特定属性,但您想确保这些属性的名称遵循特定约定,这会很有用例如,您可能想要强制所有名称都是有效的 ASCII 标记,以便它们可以用作特定编程语言中的属性。

{ “type”: “object”, “propertyNames”: { “pattern”: “^[A-Za-z_][A-Za-z0-9_]*$” }}// OK{ “_a_proper_token_001”: “value”} // not OK{ “001 invalid”: “value”}

由于对象键无论如何必须始终是字符串,因此暗示给定的模式propertyNames始终至少为:{ “type”: “string” }属性数量可以使用minProperties和maxProperties

关键字来限制对象上的属性数量 这些中的每一个都必须是非负整数{ “type”: “object”, “minProperties”: 2, “maxProperties”: 3}{} // not OK{ “a”: 0 } // not OK{ “a”: 0, “b”: 1 } // OK{ “a”: 0, “b”: 1, “c”: 2 } // OK{ “a”: 0, “b”: 1, “c”: 2, “d”: 3 } // not OK。

数组(array)数组用于有序元素在 JSON 中,数组中的每个元素可能是不同的类型在 Python 中,“数组”类似于 list或tuple类型,具体取决于用法但是,jsonPython 标准库中的模块将始终使用 Python 列表来表示 JSON 数组。

在 Ruby 中,“数组”类似于Array类型{ “type”: “array” }[1, 2, 3, 4, 5] // OK[3, “different”, { “types” : “of values” }] // OK{“Not”: “an array”} // not OK。

元素JSON 中数组的使用一般有两种方式:**列表验证:**任意长度的序列,其中每个项目都匹配相同的模式**元组验证:**一个固定长度的序列,其中每个项目可能有不同的模式在这种用法中,每个项目的索引(或位置)对于如何解释值是有意义的。

(在某些编程语言中,这种用法通常被赋予一个完整的单独类型,例如 Python 的tuple)列表验证列表验证对于任意长度的数组很有用,其中每个项目都匹配相同的模式对于这种类型的数组,将items关键字设置为单个模式,将用于验证数组中所有元素。

笔记:当items是单模式时,additionalItems关键字没有意义,不应使用在下面的例子中,我们定义数组中的每一项都是一个数字:{ “type”: “array”, “items”: { “type”: “number” }}[1, 2, 3, 4, 5] // OK[1, 2, “3”, 4, 5] // not OK,单个“非数字”会导致整个数组无效[] // OK,空数组始终有效。

元组验证当数组是一个元素的集合时,元组验证很有用,其中每个项目都有不同的架构并且每个项目的序数索引是有意义的例如,您可以表示街道地址,例如:1600 Pennsylvania Avenue NW作为以下形式的 4 元组:。

[号码、街道名称、街道类型、方向]这些字段中的每一个都将具有不同的模式:number: 地址编号,必须是数字street_name: 街名,必须是字符串street_type: 街道类型,应该是来自一组固定值的字符串。

direction:地址所在城市象限,应该是来自不同值组成集合的字符串为此,我们将items关键字设置为一个数组,其中每个项目都是一个模式,对应于文档数组的每个索引也就是说,一个数组,其中第一个元素验证输入数组的第一个元素,第二个元素验证输入数组的第二个元素,依此类推。

以下是示例:{ “type”: “array”, “items”: [ { “type”: “number” }, { “type”: “string” }, { “enum”: [“Street”, “Avenue”, “Boulevard”] }, { “enum”: [“NW”, “NE”, “SW”, “SE”] } ]}[1600, “Pennsylvania”, “Avenue”, “NW”] // OK[24, “Sussex”, “Drive”] // not OK,“Drive”不是可接受的街道类型之一[“Palais de lÉlysée”] // not OK,此地址缺少街道号码[10, “Downing”, “Street”] // OK,可以不提供所有项目[1600, “Pennsylvania”, “Avenue”, “NW”, “Washington”] // OK,默认情况下可以在尾部添加其他项目

附加元素使用additionalItems关键字控制如果有超过元组内items属性定义的附加元素,元组是否有效additionalItems关键字的值是一个模式,所有其他项目必须通过该模式才能验证关键字。

如果items同一模式中不存在“元组验证”关键字,则忽略此关键字在Draft 4 中,additionalItems不需要存在“元组验证”items关键字对任何项目都没有限制,因此所有项目都被视为附加项目。

在这里,我们将重用上面的示例模式,但设置additionalItems为false,这具有禁止数组中的额外项目的效果{ “type”: “array”, “items”: [ { “type”: “number” }, { “type”: “string” }, { “enum”: [“Street”, “Avenue”, “Boulevard”] }, { “enum”: [“NW”, “NE”, “SW”, “SE”] } ], “additionalItems”: false}[1600, “Pennsylvania”, “Avenue”, “NW”] // OK[1600, “Pennsylvania”, “Avenue”] // OK,可以不提供所有元素[1600, “Pennsylvania”, “Avenue”, “NW”, “Washington”] // not OK,不能提供额外的元素。

您可以通过使用非布尔模式来限制附加项可以具有的值来表达更复杂的约束在这种情况下,我们可以说允许附加元素,只要它们都是字符串:{ “type”: “array”, “items”: [ { “type”: “number” }, { “type”: “string” }, { “enum”: [“Street”, “Avenue”, “Boulevard”] }, { “enum”: [“NW”, “NE”, “SW”, “SE”] } ], “additionalItems”: { “type”: “string” }}[1600, “Pennsylvania”, “Avenue”, “NW”, “Washington”] // OK,额外的字符串元素是可以的[1600, “Pennsylvania”, “Avenue”, “NW”, 20500] // not OK,额外的元素不是字符串。

注意:因为“列表验证”(items是一个对象)适用于列表中的所有项目,所以这三个项目没有附加项目,因此additionalItems没有任何可应用其模式的内容,也不会产生任何影响包含Draft 6 中的新内容:虽然。

items模式必须对数组中的每一项都有效,但contains模式只需要针对数组中的一项或多项进行验证{ “type”: “array”, “contains”: { “type”: “number” }}[“life”, “universe”, “everything”, 42] // OK,包含一个number元素[“life”, “universe”, “everything”, “forty-two”] // not OK,不包含number元素[1, 2, 3, 4, 5] // OK。

长度可以使用minItems和maxItems关键字指定数组的长度每个关键字的值必须是非负数无论是进行List 验证还是Tuple 验证,这些关键字都 有效{ “type”: “array”, “minItems”: 2, “maxItems”: 3}[] // not OK,[1] // not OK,[1, 2] // OK[1, 2, 3] // OK[1, 2, 3, 4] // not OK。

唯一性只需将uniqueItems关键字设置为true,可以限制数组中的每个元素都是唯一的{ “type”: “array”, “uniqueItems”: true}[1, 2, 3, 4, 5] // OK[1, 2, 3, 3, 4] // not OK[] // OK空数组总是通过。

布尔值(boolean)布尔类型只匹配两个特殊值:true和false请注意,模式不接受_其他约定_为true或false的值,例如 1 和 0在 Python 中,“boolean”类似于bool类型。

请注意,在 JSON 中, trueandfalse是小写的,而在 Python 中,它们是大写的 ( Trueand False)在 Ruby 中,“boolean”类似于TrueClass和FalseClass。

请注意,在 Ruby 中没有Boolean类{ “type”: “boolean” }true // OKfalse // OK”true” // not OK0 // not OKNULL(null)。

当一个模式指定type为null时,它只有一个可接受的值:null注意:在 JSON 中,null不等于缺少某些东西有关示例,请参阅必需属性在 Python 中,null类似于None.在 Ruby中, 。

null 类似于 nil.{ “type”: “null” }null // OKfalse // not OK0 // not OK”” // not OK通用关键字注释JSON Schema 包含一些关键字,它们并不严格用于验证,而是用于描述模式的一部分。

这些“注释”关键字都不是必需的,但鼓励使用为了良好实践,并且可以使您的模式“自我记录”title和description关键字必须是字符串title最好是简短的,而description提供模式描述的数据因此会有更长的说明。

default关键字指定一个默认值该值不用于在验证过程中填充缺失值文档生成器或表单生成器等非验证工具可能会使用此值提示用户如何使用该值但是,default通常用于表示如果缺少某个值,则该值在语义上与该值与默认值一起存在时的语义相同。

default的值应该根据它所在的模式进行验证,但这不是必需的Draft 6 中的新内容examples关键字是提供一系列针对模式进行验证的示例的地方这不用于验证,但可能有助于向读者解释模式的效果和目的。

每个条目都应该根据它所在的模式进行验证,但这并不是严格要求的没有必要复制examples数组中的default值,因为default将被视为另一个示例Draft 7 中的新内容布尔类型的关键字readOnly。

和writeOnly通常用于 API 上下文中readOnly表示该值可读不可改,可用于说明一个更改值的PUT请求将得到一个400 Bad Request的响应writeOnly表示该值可已修改但是不可以读,可用于说明可通过PUT请求来设置值,但通过GET请求来检索该记录时不能获取该值 。

Draft2019-09的新内容deprecated关键字是一个布尔值,表明该关键字应用的实例值不宜使用,并可能在将来被移除{ “title”: “Match anything”, “description”: “This is a schema that matches anything.”, “default”: “Default value”, “examples”: [ “Anything”, 4035 ], “deprecated”: true, “readOnly”: true, “writeOnly”: false}。

评论Draft 7 中的新内容$comment关键字严格用于向模式添加注释它的值必须始终是一个字符串与注解title、description和examples不同, JSON 模式实现不允许附加任何含义或行为,甚至可以随时剥离它们。

因此,它们对于给 JSON 模式的未来编辑者留下笔记很有用,但不宜用于与模式的用户进行交流枚举值enum关键字用于将值限制为一组固定的值它必须是一个包含至少一个元素的数组,其中每个元素都是唯一的以下是验证路灯颜色的示例:。

{ “enum”: [“red”, “amber”, “green”]}”red” // OK”blue” // not OK您甚至可以使用enum添加没有类型的值,让我们扩展示例,用null指示“off”,并添加 42,只是为了好玩。

{ “enum”: [“red”, “amber”, “green”, null, 42]}”red” // OKnull // OK42 // OK0 // not OK常量值Draft 6 中的新内容

const关键字被用于限制值为一个常量值例如,如果出于出口原因仅支持运送到美国:{ “properties”: { “country”: { “const”: “United States of America” } }}{ “country”: “United States of America” } // OK{ “country”: “Canada” } // not OK。

Media:字符串编码非 JSON 数据内容媒体类型contentMediaType关键字指定的MIME类型的字符串的内容,如在RFC 2046有一个由 IANA 正式注册的MIME 类型列表,但支持的类型集将取决于应用程序和操作系统。

Mozilla Developer Network 还维护了一个较短的对网络很重要的 MIME 类型列表内容编码contentEncoding关键字指定编码用于存储内容,如在规定的RFC 2054,部分6.1

和RFC 4648可接受的值为7bit,8bit,binary,quoted-printable,base16,base32,和base64如果未指定,则编码与包含的 JSON 文档相同在不深入了解每种编码的底层细节的情况下,实际上只有两个选项对现代使用有用:。

如果内容使用与封闭 JSON 文档相同的编码(出于实际目的,几乎总是 UTF-8),请保持 contentEncoding未指定,并将内容按原样包含在字符串中这包括基于文本的内容类型,例如text/html。

或 application/xml如果内容是二进制数据,则设置contentEncoding为base64并使用Base64对内容进行编码这将包括许多图像类型,例如image/png或音频类型,例如audio/mpeg

.内容架构2019-09 Draft中的新内容文档即将推出例子以下模式指示字符串包含一个 HTML 文档,使用与周围文档相同的编码进行编码:{ “type”: “string”, “contentMediaType”: “text/html”}// OK””

以下模式指示字符串包含使用 Base64 编码的PNG图像:{ “type”: “string”, “contentEncoding”: “base64”, “contentMediaType”: “image/png”}// OK”iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA…”

Schema 组合allOf要验证allOf,给定的数据必须针对给定的所有子模式有效{ “allOf”: [ { “type”: “string” }, { “maxLength”: 5 } ]}”short” // OK”too long” // not OK。

注意:在面向对象继承的意义上, anyOf要验证anyOf,数据必须满足任意一个或多个给定子模式{ “anyOf”: [ { “type”: “string”, “maxLength”: 5 }, { “type”: “number”, “minimum”: 0 } ]}”short” // OK”too long” // not OK12 // OK-5 // not OK。

oneOf要验证oneOf,数据必须满足且只满足一个给定的子模式{ “oneOf”: [ { “type”: “number”, “multipleOf”: 5 }, { “type”: “number”, “multipleOf”: 3 } ]}10 // OK9 // OK2 // not OK,不是 5 或 3 的倍数。

15 // not OK,同时符合两个子模式被拒绝not要验证not,数据不能满足给定的子模式例如,以下模式针对不是字符串的任何内容进行验证:{ “not”: { “type”: “string”} }42 // OK{ “key”: “value” } // OK”I am a string” // not OK。

模式组合的属性子模式独立注意:allOf、anyOf 或oneOf数组中列出的模式彼此一无所知例如,假设您在一个$defs部分中有一个地址的架构,并且想要“扩展”它以包含地址类型:{ “$defs”: { “address”: { “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “city”: { “type”: “string” }, “state”: { “type”: “string” } }, “required”: [“street_address”, “city”, “state”] } }, “allOf”: [ { “$ref”: “#/$defs/address” }, { “properties”: { “type”: { “enum”: [ “residential”, “business” ] } } } ]}{// OK “street_address”: “1600 Pennsylvania Avenue NW”, “city”: “Washington”, “state”: “DC”, “type”: “business”}。

这是可行的,但是如果我们想限制模式以便不允许附加属性怎么办?可以尝试添加”additionalProperties”: false{ “$defs”: { “address”: { “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “city”: { “type”: “string” }, “state”: { “type”: “string” } }, “required”: [“street_address”, “city”, “state”] } }, “allOf”: [ { “$ref”: “#/$defs/address” }, { “properties”: { “type”: { “enum”: [ “residential”, “business” ] } } } ], “additionalProperties”: false} // not OK{ “street_address”: “1600 Pennsylvania Avenue NW”, “city”: “Washington”, “state”: “DC”, “type”: “business”}

不幸的是,现在模式将拒绝_一切_这是因为additionalProperties对不合逻辑的模式请注意,使用这些关键字创建逻辑上不可能的模式非常容易以下示例创建了一个不会针对任何内容进行验证的架构(因为某些内容可能不会同时是字符串和数字):。

{ “allOf”: [ { “type”: “string” }, { “type”: “number” } ]}”No way” // not OK-1 // not OK分解模式

请注意,可以“分解”子模式的公共部分以下两个模式是等效的{ “oneOf”: [ { “type”: “number”, “multipleOf”: 5 }, { “type”: “number”, “multipleOf”: 3 } ]}。

{ “type”: “number”, “oneOf”: [ { “multipleOf”: 5 }, { “multipleOf”: 3 } ] }有条件地应用子模式必要依赖

dependentRequired关键字有条件地要求,如果一个对象存在某个特定的属性,则另一个属性也必须存在例如,假设我们有一个表示客户的模式,如果您有他们的信用卡号,您还需要确保您有账单地址如果您没有他们的信用卡号,则不需要帐单邮寄地址。

我们使用dependentRequired关键字表示一个属性对另一个属性的这种依赖性dependentRequired关键字的值是一个对象对象中的每个条目都从属性的名称_p_映射到一个字符串数组,其中列出了_p_存在时所需的属性。

在下面的例子中,无论何时,只要存在credit_card,另一个属性billing_address`属性必须存在:{ “type”: “object”, “properties”: { “name”: { “type”: “string” }, “credit_card”: { “type”: “number” }, “billing_address”: { “type”: “string” } }, “required”: [“name”], “dependentRequired”: { “credit_card”: [“billing_address”] }}// OK{ “name”: “John Doe”, “credit_card”: 5555555555555555, “billing_address”: “555 Debtors Lane”} // not OK,这个实例有一个credit_card,但缺少一个billing_address。

{ “name”: “John Doe”, “credit_card”: 5555555555555555}// OK这没关系,因为我们既没有credit_carda也没有billing_address。

{ “name”: “John Doe”}// OK请注意,依赖项不是双向的有一个没有信用卡号的帐单地址是可以的{ “name”: “John Doe”, “billing_address”: “555 Debtors Lane”}。

要解决上面的最后一个问题(依赖项不是双向的),您当然可以明确定义双向依赖项:{ “type”: “object”, “properties”: { “name”: { “type”: “string” }, “credit_card”: { “type”: “number” }, “billing_address”: { “type”: “string” } }, “required”: [“name”], “dependentRequired”: { “credit_card”: [“billing_address”], “billing_address”: [“credit_card”] }} // not OK,这个实例有一个credit_card,但缺少一个billing_address。

{ “name”: “John Doe”, “credit_card”: 5555555555555555} // not OK,这有一个billing_address,但缺少一个credit_card。

{ “name”: “John Doe”, “billing_address”: “555 Debtors Lane”}模式依赖dependenciesSchemas关键字要求当给定的属性存在时,有条件地应用子模式。

此架构的应用方式与allOf应用架构的方式相同没有合并或扩展任何内容两种模式独立应用例如,这里有另一种写法:{ “type”: “object”, “properties”: { “name”: { “type”: “string” }, “credit_card”: { “type”: “number” } }, “required”: [“name”], “dependentSchemas”: { “credit_card”: { “properties”: { “billing_address”: { “type”: “string” } }, “required”: [“billing_address”] } }}// OK{ “name”: “John Doe”, “credit_card”: 5555555555555555, “billing_address”: “555 Debtors Lane”} // not OK,这个实例有一个credit_card,但缺少一个 billing_address:{ “name”: “John Doe”, “credit_card”: 5555555555555555}// OK。

这有一个billing_address,但缺少一个 credit_card这通过了,因为这里billing_address 看起来像一个附加属性:{ “name”: “John Doe”, “billing_address”: “555 Debtors Lane”}。

Draft 4-7 Draft2019-09之前的版本,dependentRequired和 dependentSchemas被称为一个关键字dependencies如果依赖值是一个数组,它的行为就像一个 。

dependentRequired,如果依赖值是一个模式,它的行为就像dependentSchema.条件语句新的Draft7中if,then和else关键字允许基于另一种模式的结果来应用子模式,这很像传统编程语言中的

if/then/else构造如果if有效,then也必须有效(并被else忽略)如果if无效,else也必须有效(并被then忽略)如果then或else未定义,则if表现为它们的值为true如果then

和/或else出现在没有if,then和 的模式中,else则被忽略我们可以把它放在真值表的形式中,显示 whenif,then, andelseare valid的组合 以及整个模式的结果有效性:

例如,假设您想编写一个模式来处理美国和加拿大的地址这些国家/地区有不同的邮政编码格式,我们希望根据国家/地区选择要验证的格式如果地址在美国,则该postal_code字段是“邮政编码”:五个数字后跟可选的四位后缀。

如果地址在加拿大,则该postal_code字段是一个六位字母数字字符串,其中字母和数字交替出现{ “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “country”: { “default”: “United States of America”, “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]” } } }}// OK{ “street_address”: “1600 Pennsylvania Avenue NW”, “country”: “United States of America”, “postal_code”: “20500”}// OK{ “street_address”: “1600 Pennsylvania Avenue NW”, “postal_code”: “20500”}// OK{ “street_address”: “24 Sussex Drive”, “country”: “Canada”, “postal_code”: “K1M 1M4”} // not OK{ “street_address”: “24 Sussex Drive”, “country”: “Canada”, “postal_code”: “10000”}// not OK{ “street_address”: “1600 Pennsylvania Avenue NW”, “postal_code”: “K1M 1M4”}。

笔记 :在此示例中,“国家/地区”不是必需的属性因为“if”模式也不需要“country”属性,它会pass然后应用“then”模式因此,如果未定义“country”属性,则默认行为是将“postal_code”验证为美国邮政编码。

“default”关键字没有效果,但将其包含在模式中,对读者比较友好,可以更容易地识别默认行为不幸的是,上面的这种方法不能扩展到两个以上的国家但是,您可以将if和then包裹在allOf`以创建可扩展的内容。

在此示例中,我们将使用美国和加拿大邮政编码,但还会添加荷兰邮政编码,即 4 位数字后跟两个字母读者可以尝试练习将其扩展到世界上其余的邮政编码{ “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “country”: { “default”: “United States of America”, “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” } }, “required”: [“country”] }, “then”: { “properties”: { “postal_code”: { “pattern”: “[A-Z][0-9][A-Z] [0-9][A-Z][0-9]” } } } }, { “if”: { “properties”: { “country”: { “const”: “Netherlands” } }, “required”: [“country”] }, “then”: { “properties”: { “postal_code”: { “pattern”: “[0-9]{4} [A-Z]{2}” } } } } ]}// OK{ “street_address”: “1600 Pennsylvania Avenue NW”, “country”: “United States of America”, “postal_code”: “20500”}// OK{ “street_address”: “1600 Pennsylvania Avenue NW”, “postal_code”: “20500”}// OK{ “street_address”: “24 Sussex Drive”, “country”: “Canada”, “postal_code”: “K1M 1M4”}// OK{ “street_address”: “Adriaan Goekooplaan”, “country”: “Netherlands”, “postal_code”: “2517 JX”} // not OK{ “street_address”: “24 Sussex Drive”, “country”: “Canada”, “postal_code”: “10000”} // not OK{ “street_address”: “1600 Pennsylvania Avenue NW”, “postal_code”: “K1M 1M4”}

笔记 “if”模式中的“required”关键字是必需的,否则如果未定义“country”,则它们都将适用如果未定义“country”,则将“required”从“United States of America”“IF”模式中删除,使其有效地成为默认值。

笔记 即使“country”是必填字段,仍然建议在每个“if”模式中使用“required”关键字验证结果将相同,因为“required”将失败,但不包括它会增加错误结果的噪音,因为它将针对所有三个“then”模式验证“postal_code”,导致不相关的错误。

蕴含在 Draft 7 之前,您可以使用模式组合关键字和称为“蕴含”的布尔代数概念来表达“if-then”条件 A -> B(A 隐含 B)意味着如果 A 为真,那么 B 也必须为真它表示为 JSON Schema可以这样写。

!A || B{ “type”: “object”, “properties”: { “restaurantType”: { “enum”: [“fast-food”, “sit-down”] }, “total”: { “type”: “number” }, “tip”: { “type”: “number” } }, “anyOf”: [ { “not”: { “properties”: { “restaurantType”: { “const”: “sit-down” } }, “required”: [“restaurantType”] } }, { “required”: [“tip”] } ]} // OK{ “restaurantType”: “sit-down”, “total”: 16.99, “tip”: 3.4} // not OK{ “restaurantType”: “sit-down”, “total”: 16.99} // OK{ “restaurantType”: “fast-food”, “total”: 6.99}// OK{ “total”: 5.25 }

蕴涵的变化可以用来表达你用if/then/else关键字表达的内容if/then可表示为A -> B,if/else可表示为!A -> B,if/then/else可表示为A -> B AND !A -> C。

笔记由于此模式不是很直观,因此建议将您在$defs中的 条件语句与描述性名称一起, 结合”allOf”: [{ “$ref”: “#/$defs/sit-down-restaurant-implies-tip-is-required” }]

一起$ref入您的模式中声明方言$schema 该$schema关键字用于声明模式是针对哪种 JSON 方言编写的$schema关键字的值也是模式的标识符,可用于根据方言$schema标识验证模式是否有效。

描述另一个模式的模式称为“元模式”$schema适用于整个文档并且必须在根级别它不适用于外部引用的 ($ref,$recursiveRef) 文档这些模式需要声明自己的$schema.如果$schema。

未使用,则实现可能允许您在外部指定一个值,或者它可能会假设应该使用哪个规范版本来评估模式建议所有 JSON 模式都有一个$schema关键字来与读者和工具进行交流,以了解预期的规范版本因此,大多数情况下,您会希望在架构的根目录下使用它:。

“$schema”: “https://json-schema.org/draft/2019-09/schema”Draft 4 的标识符是http://json-schema.org/draft-04/schema#

Draft 4 定义了一个没有特定方言 ( http://json-schema.org/schema#)的$schema,这意味着使用最新的方言这已被弃用,不应再使用您可能会遇到对 Draft 5 的引用。

没有 JSON Schema 的 Draft 5 版本Draft 5 指的是Draft 4 版本的无变化修订版它不会添加、删除或更改任何功能它只更新参考资料、进行澄清和修复错误Draft 5 描述了DraftDraft4 版本。

如果您来这里寻找有关Draft 5 的信息,您会在Draft 4 下找到它我们不再使用“Draft”术语来指代补丁版本以避免这种混淆Draft 6 的标识符是http://json-schema.org/draft-06/schema#

Draft 7 的标识符是http://json-schema.org/draft-07/schema#词汇表2019-09 Draft中的新内容:文档即将推出Draft4-7 在引入 Vocabularies 之前,您仍然可以使用自定义关键字扩展 JSON Schema,但该过程不太正式。

您需要的第一件事是包含自定义关键字的元架构最好的方法是为要扩展的版本制作元模式的副本,并对副本进行更改您需要选择一个自定义 URI 来标识您的自定义版本此 URI 不能是用于标识官方 JSON 架构规范Draft的 URI 之一,并且可能应该包含您拥有的域名。

您可以将此 URI 与$schema关键字一起使用来声明您的模式使用您的自定义版本笔记并非所有实现都支持自定义元模式和自定义关键字实现指南JSON Schema 的优势之一是它可以用 JSON 编写并在各种环境中使用。

例如,它可用于前端和后端 HTML 表单验证使用自定义词汇表的问题在于,您想要使用模式的每个环境都需要了解如何评估词汇表的关键字元模式可用于确保模式编写正确,但每个实现都需要自定义代码来了解如何评估词汇表的关键字。

元数据关键字是最具互操作性的,因为它们不影响验证例如,您可以添加units关键字对于合规的验证器,将始终按预期生效{ “type”: “number”, “units”: “kg”}42 // OK”42″ // not OK。

自定义关键字的下一个最佳候选者是不应用其他模式且不修改现有关键字行为的关键字isEven关键字是一个例子,在某些语境下验证比没有验证要好,例如在浏览器中验证 HTML 表单时,此模式的性能将达到预期完全验证仍然是需要的,并且应该使用可以理解自定义关键字的验证器。

{ “type”: “integer”, “isEven”: true}2 // OK3 // OK,这通过因为验证器不理解 `isEven`”3″ // not OK,模式没有因为不理解 `isEven`而完全受损

互操作性最差的自定义关键字类型是应用其他模式或修改现有关键字行为的自定义关键字一个例子就是requiredProperties,这个关键字声明属性并使它们成为必需属性以下示例显示了在使用不理解自定义关键字的验证器进行校验时,模式如何变得几乎无用。

这并不一定意味着这requiredProperties对关键字来说是个坏主意,只是说如果模式在不理解自定义关键字的上下文中使用时不是一个好的选择{ “type”: “object”, “requiredProperties”: { “foo”: { “type”: “string”} }}{ “foo”: “bar” } // OK{} // OK,因为`requiredProperties`不被理解{ “foo”: 42 } //ok,因为`requiredProperties`不被理解。

构建复杂模式模式识别与任何其他代码一样,将模式分解为在必要时相互引用的逻辑单元,则模式更易于维护为了引用模式,我们需要一种识别模式的方法模式文档由非相对 URI 所标识模式文档不需要有标识符,但如果您想从另一个模式引用一个模式,则需要一个标识符。

在本文档中,我们将没有标识符的模式称为“匿名模式”在以下部分中,我们将看到如何确定模式的“标识符”笔记URI 术语有时可能不直观在本文件中,使用了以下定义:URI[1]或非相对URI:含有模式的完整URI(。

https)它可能包含一个 URI 片段 (#foo)有时本文档会使用“非相对 URI”来明确表示不允许使用相对 URI相对引用[2]:不包含模式 (https) 的部分 URI 它可能包含一个片段 (。

#foo)URI-引用[3]:相对引用或非相对 URI它可能包含一个 URI 片段 (#foo)绝对 URI[4]包含模式 (https) 但不包含 URI 片段 (#foo) 的完整 URI 笔记 尽管模式由 URI 标识,但这些标识符不一定是网络可寻址的。

它们只是标识符通常,实现不会发出 HTTP 请求 ( https://) 或从文件系统 ( file://) 读取以获取模式相反,它们提供了一种将模式加载到内部模式数据库中的方法当模式被其 URI 标识符引用时,将从内部架构数据库中检索该模式。

JSON 指针除了标识模式文档,您还可以标识子模式最常见的方法是在指向子模式的 URI 片段中使用JSON 指针JSON 指针描述了一个以斜线分隔的路径来遍历文档中对象中的键因此,/properties/street_address。

意味着:找到键的值 properties在该对象中,找到键的值 street_addressURIhttps://example.com/schemas/address#/properties/street_address

标识以下模式中子模式 { “type”: “string” }{ “$id”: “https://example.com/schemas/address”,”type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “city”: { “type”: “string” }, “state”: { “type”: “string” } }, “required”: [“street_address”, “city”, “state”]}。

$锚点标识子模式的一种不太常见的方法是使用$anchor关键字并在 URI 片段中使用该名称在模式中创建命名锚点锚点必须以字母开头,后跟任意数量的字母、数字、-、_、:、 或.在 Draft 4 中,您以与 Draft 6-7 中相同的方式声明锚点,。

$id 只是只是 id(没有美元符号)在Draft 6-7 中,使用$id仅包含 URI 片段的定义了命名锚点URI 片段的值是锚点的名称JSON Schema 没有定义当$id同时包含片段和非片段 URI 部分时应该如何解析。

因此,在设置命名锚点时,不应在 URI 引用中使用非片段 URI 部分笔记 如果一个命名的锚点在定义时不遵循这些命名规则,则它的行为未定义您的锚点可能在某些实现中起作用,但在其他实现中不起作用URIhttps://example.com/schemas/address#street_address

标识以下模式的子模式{“$anchor”: “#street_address”, “type”: “string”}{ “$id”: “https://example.com/schemas/address”, “type”: “object”, “properties”: { “street_address”: { “$anchor”: “#street_address”, “type”: “string” }, “city”: { “type”: “string” }, “state”: { “type”: “string” } }, “required”: [“street_address”, “city”, “state”]}

基本 URI使用非相对 URI 可能很麻烦,因此 JSON 模式中使用的任何 URI 都可以是 URI 引用,根据模式的基本 URI 进行解析,从而产生非相对 URI本节介绍如何确定架构的基本 URI笔记

基本 URI 确定和相对引用解析由RFC-3986定义如果您熟悉这在 HTML 中的工作原理,那么本节应该会感到非常熟悉检索 URI用于获取模式的 URI 称为“检索 URI”通常可以将匿名模式传递给实例,在这种情况下,该模式将没有检索 URI。

让我们假设使用 URI 引用https://example.com/schemas/address模式并检索以下模式{ “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “city”: { “type”: “string” }, “state”: { “type”: “string” } }, “required”: [“street_address”, “city”, “state”]}。

此架构的基本 URI 与检索 URI 相同https://example.com/schemas/address$id您可以在模式根目录中使用$id关键字来设置基本 URI $id的值是一个没有根据检索 URI

解析片段的 URI 引用生成的 URI 是模式的基本 URI在Draft 4 中,$id只是id(没有$)在Draft 4-7 中,允许在$id(或 Draft4中的id)中有片段但是,设置包含 URI 片段的基本 URI 时的行为未定义,不应使用,因为实现可能会以不同方式对待它们。

笔记这类似于HTML 中的标签笔记当$id关键字出现在子模式中时,它的含义略有不同有关更多信息,请参阅捆绑部分让我们假设 URIhttps://example.com/schema/address。

和https://example.com/schema/billing-address两者都标识以下模式{ “$id”: “/schemas/address”, “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “city”: { “type”: “string” }, “state”: { “type”: “string” } }, “required”: [“street_address”, “city”, “state”]}。

无论使用两个 URI 中的哪一个来检索此模式,基本 URI 都将是https://example.com/schemas/address,这是$id针对检索 URI的URI 引用解析 的结果但是,在设置基本 URI 时使用相对引用可能会出现问题。

例如,我们不能将此模式用作匿名模式,因为没有检索 URI并且您无法解析相对引用出于这个原因和其他原因,建议您在使用$id声明基本URI时尽量使用绝对URI.无论检索 URI是什么 或者它是否用作匿名模式,以下模式的基本 URI 将始终是。

https://example.com/schemas/address{ “$id”: “https://example.com/schemas/address”, “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “city”: { “type”: “string” }, “state”: { “type”: “string” } }, “required”: [“street_address”, “city”, “state”]}。

$ref一个模式可以使用$ref关键字引用另一个模式$ref的值是根据模式的Base URI解析的 URI 引用当获取$ref的值时,一个实现是使用解析的标识符来检索引用的模式并将该模式应用于实例中在Draft 4-7

中,$ref表现略有不同当一个对象包含一个$ref属性时,该对象被认为是一个引用,而不是一个模式因此,您放入该对象的任何其他属性都不会被视为 JSON 模式关键字,并且会被验证器忽略$ref只能在需要模式的地方使用。

在这个例子中,假设我们要定义一个客户记录,其中每个客户可能都有一个送货地址和一个账单地址地址总是相同的——它们有街道地址、城市和州——所以我们不想在我们想要存储地址的任何地方复制模式的那部分这不仅会使模式更加冗长,而且会使将来更新它变得更加困难。

如果我们想象中的公司将来开始从事国际业务,并且我们想为所有地址添加一个国家/地区字段,那么最好在一个地方而不是在使用地址的所有地方进行此操作{ “$id”: “https://example.com/schemas/customer”, “type”: “object”, “properties”: { “first_name”: { “type”: “string” }, “last_name”: { “type”: “string” }, “shipping_address”: { “$ref”: “/schemas/address” }, “billing_address”: { “$ref”: “/schemas/address” } }, “required”: [“first_name”, “last_name”, “shipping_address”, “billing_address”]}

$ref中的URI 引用根据模式的基本 URI(https://example.com/schemas/customer)进行解析,结果为https://example.com/schemas/address

. 该实现检索该模式并使用它来获取“shipping_address”和“billing_address”属性的值笔记$ref在匿名模式中使用时,相对引用可能无法解析假设此示例用作匿名模式{ “type”: “object”, “properties”: { “first_name”: { “type”: “string” }, “last_name”: { “type”: “string” }, “shipping_address”: { “$ref”: “https://example.com/schemas/address” }, “billing_address”: { “$ref”: “/schemas/address” } }, “required”: [“first_name”, “last_name”, “shipping_address”, “billing_address”]}。

在/properties/shipping_address的在没有非相对基础解析时解析是可以的,但中的ref无法解析到一个非相对URI,因此无法用于检索address模式$defs有时,我们有一小段仅用于当前模式的子模式,将它们定义为单独的模式是没有意义的。

虽然我们可以使用 JSON 指针或命名锚点来识别任何子模式,但$defs关键字为我们提供了一个标准化的位置来保存想在当前模式文档中复用的子模式让我们扩展之前的客户模式示例,以使用名称属性的通用架构为此定义一个新模式没有意义,它只会在这个模式中使用,所以使用。

$defs非常合适{ “$id”: “https://example.com/schemas/customer”, “type”: “object”, “properties”: { “first_name”: { “$ref”: “#/$defs/name” }, “last_name”: { “$ref”: “#/$defs/name” }, “shipping_address”: { “$ref”: “/schemas/address” }, “billing_address”: { “$ref”: “/schemas/address” } }, “required”: [“first_name”, “last_name”, “shipping_address”, “billing_address”], “$defs”: { “name”: { “type”: “string” } }}。

$ref不仅有助于避免重复它对于编写更易于阅读和维护的模式也很有用模式的复杂部分可以$defs用描述性名称定义并在需要的地方引用这允许模式的读者在深入研究更复杂的部分之前,更快速、更轻松地在高层次上理解模式。

笔记 可以引用外部子模式,但通常您希望将 a 限制$ref为引用外部模式或$defs.递归该$ref关键字可以被用来创建一个自我递归模式例如,您可能有一个person模式包含一个children的数组,每个。

children也是person的实例{ “type”: “object”, “properties”: { “name”: { “type”: “string” }, “children”: { “type”: “array”, “items”: { “$ref”: “#” } } }}。

英国王室的家庭树片段{ “name”: “Elizabeth”, “children”: [ { “name”: “Charles”, “children”: [ { “name”: “William”, “children”: [ { “name”: “George” }, { “name”: “Charlotte” } ] }, { “name”: “Harry” } ] } ]}

上面,我们创建了一个引用自身的模式,有效地在验证器中创建了一个“循环”,这既允许又有用但是请注意,$ref对另一个的引用$ref可能会导致解析器中的无限循环,并且是明确禁止的{ “$defs”: { “alice”: { “$ref”: “#/$defs/bob” }, “bob”: { “$ref”: “#/$defs/alice” } }}。

扩展递归模式2019-09 Draft中的新内容文档即将推出捆绑使用多个模式文档便于开发,但将所有模式捆绑到单个模式文档中通常更方便分发这可以通过在子模式中使用关键字来完成当id`在子模式中使用时,它表示嵌入式模式。

嵌入式模式的标识符是根据它出现在其中的模式的基本URI解析的得到的$id的值包含嵌入模式的模式文档称为复合模式文档,复合架构文档中每个带有$id的模式称为模式资源Draft 4 中,$id只是id(没有$)。

Draft 4-7 中,子模式中的$id 不表示嵌入式模式相反,它只是单模式文档中的基本 URI 更改这类似于HTML 中的的标签笔记 在开发模式时使用嵌入式模式是不常见的通常最好不要显式使用此功能,并在需要时使用模式捆绑工具来构建捆绑模式。

此示例显示捆绑到复合模式文档中的客户模式示例和地址模式示例{ “$id”: “https://example.com/schemas/customer”, “$schema”: “https://json-schema.org/draft/2019-09/schema”, “type”: “object”, “properties”: { “first_name”: { “type”: “string” }, “last_name”: { “type”: “string” }, “shipping_address”: { “$ref”: “/schemas/address” }, “billing_address”: { “$ref”: “/schemas/address” } }, “required”: [“first_name”, “last_name”, “shipping_address”, “billing_address”], “$defs”: { “address”: { “$id”: “/schemas/address”, “$schema”: “http://json-schema.org/draft-07/schema#”, “type”: “object”, “properties”: { “street_address”: { “type”: “string” }, “city”: { “type”: “string” }, “state”: { “$ref”: “#/definitions/state” } }, “required”: [“street_address”, “city”, “state”], “definitions”: { “state”: { “enum”: [“CA”, “NY”, “… etc …”] } } } }}。

无论是否捆绑了模式资源,复合模式文档中的所有引用都必须相同请注意,$ref客户架构中的 关键字没有更改唯一的区别是地址模式现在定义在/$defs/address而不是单独的模式文档您不能使用#/$defs/address。

引用地址架构,因为如果您拆分模式,该引用将不再指向地址模式Draft 4-7 中,这两个 URI 都是有效的,因为子模式 $id仅表示基本 URI 更改,而不是嵌入模式但是,虽然允许,仍然强烈建议 JSON 指针不要越过具有基本 URI 更改的模式。

您还应该看到 “$ref”: “#/definitions/state” 解析为地址模式中的 definitions 关键字,而不是顶级模式中的关键字,就像未使用嵌入式模式时那样每个模式资源都是独立求值的,并且可能使用不同的 JSON 模式方言。

上面的示例中, 地址模式资源使用了 Draft 7 ,而客户模式资源使用 Draft 2019-09如果嵌入式模式中没有声明$schema,则默认使用父模式的方言Draft 4-7 中,子$id模式只是基本 URI 更改,不被视为独立的模式资源。

因为$schema仅允许在模式资源的根目录中使用,所以使用子模式 $id 捆绑的所有模式必须使用相同的方言。举报/反馈

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
相关推荐
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容