sweetmalt / schema

0 stars 0 forks source link

Understanding JSON Schema 2020-12 中文版 #1

Open sweetmalt opened 10 months ago

sweetmalt commented 10 months ago

Understanding JSON Schema 2020-12 中文版

sweetmalt commented 10 months ago

Understanding JSON Schema | JSON Schema 入门(中英对照版)

JSON Schema is a powerful tool for validating the structure of JSON data. However, learning to use it by reading its specification is like learning to drive a car by looking at its blueprints. You don't need to know how an electric motor fits together if all you want to do is pick up the groceries. This book, therefore, aims to be the friendly driving instructor for JSON Schema. It's for those that want to write it and understand it, but maybe aren't interested in building their own car--er, writing their own JSON Schema validator--just yet.

octopus

JSON Schema 是用于验证 JSON 数据格式的强大工具。然而,如果我们只能通过阅读 JSON Schema 的官方规范文档来学习如何使用它,就好像通过阅读汽车设计图纸去学如何开车一样(小题大做),换句话说,您大可不必仅仅为了清除地上的几片杂物而去搞懂一台吸尘器的内部电机工作原理。因此,本书旨在成为一本有关 JSON Schema 的简易应用指南。其读者对象为,那些仅仅想要懂得如何编写 JSON Schema 文档、而非想要设计自己的汽车——额(不好意思,搞错了)——而非想要设计自己的 JSON Schema 验证器的人——是的,仅此而已(规范文档主要是写给验证器开发者们看的)。

Note

This book describes JSON Schema draft 2020-12. Earlier versions of JSON Schema are not completely compatible with the format described here, but for the most part, those differences are noted in the text.

备注

本书基于 JSON Schema 草案 2020-12 版,该版草案与其他更早版本之间存在的那些不一致的叙述——即所谓版本不兼容的地方,本书会尽量给予标注提示。

Where to begin?

  • This book uses some novel conventions for showing schema examples and relating JSON Schema to your programming language of choice.
  • If you're not sure what a schema is, check out What is a schema?
  • The basics chapter should be enough to get you started with understanding the core JSON Schema Reference.
  • When you start developing large schemas with many nested and repeated sections, check out Structuring a complex schema.
  • json-schema.org has a number of resources, including the official specification and tools for working with JSON Schema from various programming languages.
  • There are a number of online JSON Schema tools that allow you to run your own JSON schemas against example documents. These can be very handy if you want to try things out without installing any software.

从哪里开始

Conventions used in this book | 读者须知

Language-specific notes | 与编程语言有关的注释

The names of the basic types in JavaScript and JSON can be confusing when coming from another dynamic language. I'm a Python programmer by day, so I've notated here when the names for things are different from what they are in Python, and any other Python-specific advice for using JSON and JSON Schema. I'm by no means trying to create a Python bias to this book, but it is what I know, so I've started there. In the long run, I hope this book will be useful to programmers of all stripes, so if you're interested in translating the Python references into Algol-68 or any other language you may know, pull requests are welcome!

The language-specific sections are shown with tabs for each language. Once you choose a language, that choice will be remembered as you read on from page to page.

For example, here's a language-specific section with advice on using JSON in a few different languages:

Advice

  • In Python, JSON can be read using the json module in the standard library.
  • In Ruby, JSON can be read using the json gem.
  • For C, you may want to consider using Jansson to read and write JSON.

当属于 JavaScript(和 JSON )的基本类型名称出现在另一种动态语言里时,多少会造成一些困惑。例如,我白天(上班时)是一名 Python 程序员,因此,每当发现与 Python 里叫法不同的东西,我都会加以标注,并备注更多特定于 Python 的 JSON 和 JSON Schema 的应用建议。我绝非故意要把本书写得如此之「 Python 」,只不过我熟悉它,就用它来抛砖引玉吧。未来,我希望本书能对各行各业的程序员都有用,因此,如果您对将本书里的 Python 参考替换成 Algol-68 或您可能知道的任何其他语言的参考信息——感兴趣,请把本书pull回您的编辑器里去吧,千万别客气!

与编程语言有关的提示内容将被放在一个多页选项卡里。你对该选项卡的最近一次选择,在你跳转到本书的其他页面时能被自动记住(具备跨页记忆功能)。(本书原本以网页形式存在于其官网上,的确具有此处所说的那种选项卡功能。翻译编辑成markdown文本时,进行了各种形式的简化,总之不存在什么选项卡了,但内容尽量确保完全一致,不影响阅读理解。译者注)

例如,下面就是这样一个与编程语言有关的(即关于在几种不同语言中的)JSON 使用建议:

建议

Draft-specific notes | 与不同版本的草案有关的注释

The JSON Schema standard has been through a number of revisions or "drafts". The current version is Draft 2020-12, but some older drafts are still widely used as well.
The text is written to encourage the use of Draft 2020-12 and gives priority to the latest conventions and features, but where it differs from earlier drafts, those differences are highlighted in special call-outs. If you only wish to target Draft 2020-12, you can safely ignore those sections.

JSON Schema 标准在经过多次修订后,现已存在多个版本的草案( Draft )。当前草案版本是 Draft 2020-12 ,但诸多旧版本仍在被广泛使用中。

本文鼓励使用最新版,Draft 2020-12,也会优先介绍其新约定、新特性。但对于新旧版本之间的改变,会着重给予特殊标注和提示。如果您只对 Draft 2020-12 感兴趣,大可放心地忽略这些提示。

Examples | 关于示例

There are many examples throughout this book, and they all follow the same format. At the beginning of each example is a short JSON Schema, illustrating a particular principle, followed by short JSON snippets that are either valid or invalid against that schema. Valid examples are in green, with a checkmark. Invalid examples are in red, with a cross. Often there are comments in between to explain why something is or isn't valid.

本书示例众多,但都遵循同一格式,即:每个示例都开始于一个简短的 JSON Schema ,预设出一个特定规则;紧跟其后的则是多条同样简短的 JSON 代码片段,其中既有能被上述 JSON Schema 验证通过的有效代码、也有无法通过验证的无效代码。有效代码用绿色对勾标注,无效代码后面则是一个红叉。另外,代码片段与「绿勾、红叉」之间通常还会有一段文字,那是对其之所以有效或者无效的进一步解释。

Note

These examples are tested automatically whenever the book is built, so hopefully they are not just helpful, but also correct!

For example, here's a snippet illustrating how to use the number type:

注意

本书每重构一次,这些示例代码都会被自动测试一遍,这使得它们不仅有用(拥有字面上的教学价值),还很正确(可运行)!

例如,下面是一个关于如何使用数字类型的示例片段:

JSON Schema:

{ "type": "number" }
JSON comment 注释 V/X
42 V
-1 V
5.0 Simple floating point number 简单的浮点数 V
2.99792458e8 Exponential notation also works 指数计数法 V
"42" Numbers as strings are rejected 作为字符串的"数字" X

What is a schema? | 啥是 schema ?

If you've ever used XML Schema, RelaxNG or ASN.1 you probably already know what a schema is and you can happily skip along to the next section. If all that sounds like gobbledygook to you, you've come to the right place. To define what JSON Schema is, we should probably first define what JSON is.

如果您曾经使用过 XML Schema 、RelaxNG 或 ASN.1 ,您多半已经知道啥是 schema 了(并敬请愉快地跳过本章余下内容)。但如果关于 schema 的一切对您来就像是在听天书,那您算是来对地方了!在搞懂 JSON Schema 之前,我们得先搞懂啥是 JSON 。

JSON stands for “JavaScript Object Notation”, a simple data interchange format. It began as a notation for the world wide web. Since JavaScript exists in most web browsers, and JSON is based on JavaScript, it's very easy to support there. However, it has proven useful enough and simple enough that it is now used in many other contexts that don't involve web surfing.

At its heart, JSON is built on the following data structures:

JSON 是「 JavaScript Object Notation —— JavaScript 对象表示法」的缩略词,是一种简单的数据交换格式。一种为万维网而生的数据交换格式。这是由于几乎所有 Web 浏览器都支持 JavaScript ,而 JSON 内生于 JavaScript 。然而,一旦它那无与伦比的简单性和易用性得到广泛证明,其应用领域很快就超出了 web 冲浪的范畴。

JSON 的核心是以下几个数据结构:

object:

{ "key1": "value1", "key2": "value2" }

array:

[ "first", "second", "third" ]

number:

 42
 3.1415926

string:

"This is a string"

boolean:

true
false

null:

null

These types have analogs in most programming languages, though they may go by different names.

除了某些叫法不同,这些类型存在于几乎所有编程语言里。

The following table maps from the names of JSON types to their analogous types in Python and Ruby:

上述 JSON 数据类型与其在 Python 和 Ruby 中的对应名称,见下表。

JSON Python Ruby
string string [4] String
number int/float [5] Integer/Float [6]
object dict Hash
array list Array
boolean bool TrueClass/FalseClass
null None NilClass

Footnotes

[4] Since JSON strings always support unicode, they are analogous to unicode on Python 2.x and str on Python 3.x.

[5] JSON does not have separate types for integer and floating-point.

[6] JSON does not have separate types for integer and floating-point.

脚注

【4】:JSON 的字符串一开始就支持 unicode 编码格式,对应 Python 2.x 中 unicode 和 Python 3.x 中的 str 。

【5】:JSON 没有明确区分整数和浮点数类型。

【6】:JSON 没有明确区分整数和浮点数类型。

With these simple data types, all kinds of structured data can be represented. With that great flexibility comes great responsibility, however, as the same concept could be represented in myriad ways. For example, you could imagine representing information about a person in JSON in different ways:

仅需这几个简单的数据类型,就可以表示出所有类型的结构化数据。然而,如此巨大的灵活性带来的,是繁重且无可推卸的用户责任——因为每定义一个概念,您都不得不从一大堆可行的表示法中去做个唯一选择。例如,针对同一个个人信息,您可以写出如下两个极为不同的 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"
  }
}

Both representations are equally valid, though one is clearly more formal than the other. The design of a record will largely depend on its intended use within the application, so there's no right or wrong answer here. However, when an application says “give me a JSON record for a person”, it's important to know exactly how that record should be organized. For example, we need to know what fields are expected, and how the values are represented. That's where JSON Schema comes in. The following JSON Schema fragment describes how the second example above is structured. Don't worry too much about the details for now. They are explained in subsequent chapters.

尽管第二种显然比第一种更正式,但上述两种表述同样有效。数据记录的设计,主要取决于其应用场景,这里不存在谁对谁错。然而,当应用程序要求「给我一个个人资料的 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" }
      }
    }
  }
}

By “validating” the first example against this schema, you can see that it fails:

下面是为此 shema 写的第一个 JSON 示例,拿去实际「验证」一下吧,您会发现其结果为失败:

{
  "name": "George Washington",
  "birthday": "February 22, 1732",
  "address": "Mount Vernon, Virginia, United States"
}

However, the second example passes:

而下面的示例二则是能通过验证的:

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

You may have noticed that the JSON Schema itself is written in JSON. It is data itself, not a computer program. It's just a declarative format for “describing the structure of other data”. This is both its strength and its weakness (which it shares with other similar schema languages). It is easy to concisely describe the surface structure of data, and automate validating data against it. However, since a JSON Schema can't contain arbitrary code, there are certain constraints on the relationships between data elements that can't be expressed. Any “validation tool” for a sufficiently complex data format, therefore, will likely have two phases of validation: one at the schema (or structural) level, and one at the semantic level. The latter check will likely need to be implemented using a more general-purpose programming language.

您可能已经注意到了, JSON Schema 本身也是写成 JSON 的。它本身只是数据,而非程序。仅仅只是一种用于「描述其他数据结构」的声明性格式而已。这既是它的优点也是它的缺点(这是所有 schema 语言的通病)。对于描述那些简明扼要型的数据的表面结构,以及根据其描述对具体数据进行自动验证,都很方便。然而,由于 JSON Schema 不能包含任何程序代码,导致其无法表示某些数据元素之间的约束关系。因此,对于格式相对复杂的数据的一次验证过程,所有「验证工具」都只好分出两个验证阶段:一个在 schema(或称结构)层,另一个在语义层。后一种(即语义层的)验证,通常就是需要借助一种通用编程语言才能实现的。

The basics | 基础

In What is a schema?, we described what a schema is, and hopefully justified the need for schema languages. Here, we proceed to write a simple JSON Schema.

上一节,我们讲了 啥是 schema ,还试图阐明我们为啥需要这种叫 schema 的语言。接下来,让我们从写一个简单的 JSON Schema 以继续这个阐述过程。

Hello World | 世界您好

When learning any new language, it's often helpful to start with the simplest thing possible. In JSON Schema, an empty object is a completely valid schema that will accept any valid JSON.

JSON Schema comments
{ } This accepts anything, as long as it's valid JSON
JSON comments valid or invalid
42 V
"I'm a string" V
{ "an": [ "arbitrarily", "nested" ], "data": "structure" } V

经验告诉我们,学习任何新语言应尽量从最简单的事情开始。在 JSON Schema 的世界里,(最简单的)空对象「{ }」,即是一个完全有效的 schema ,只不过,但凡是有效的 JSON ,它都表示接受。

JSON Schema 注释
{ } 接受任何内容,只要是有效的 JSON
JSON 注释 验证结果
42 数值 V
"I'm a string" 字符串 V
{ "an": [ "arbitrarily", "nested" ], "data": "structure" } 对象 V

New in draft 6

You can also use true in place of the empty object to represent a schema that matches anything, or false for a schema that matches nothing.

JSON Schema comments
true This accepts anything, as long as it's valid JSON
false
JSON comments valid or invalid
"Resistance is futile... This will always fail!!!" by「 false 」schema X

这是从 draft 6 开始引入的新特性

您还可以使用「 true 」代替空对象「{ }」以表示匹配任何内容的 schema ,用「 false 」表示不匹配任何内容的 schema 。

JSON Schema 注释
true 接受任何内容,只要是有效的 JSON
false 不接受任何内容
JSON 注释 验证结果
"抵抗是徒劳的... 这将始终失败!!!" 当以「 false 」为 schema 时 X

The type keyword | 类型关键词

Of course, we wouldn't be using JSON Schema if we wanted to just accept any JSON document. The most common thing to do in a JSON Schema is to restrict to a specific type. The type keyword is used for that.

当然,如果我们只想要一个接受任何 JSON 文档的「验证」,那还要 JSON Schema 干啥呢。JSON Schema 的第一大功用,非「特定类型限定」莫属,承担这一使命的是关键词 type 。

Note

When this book refers to JSON Schema “keywords”, it means the “key” part of the key/value pair in an object. Most of the work of writing a JSON Schema involves mapping a special “keyword” to a value within an object.

注意

当本书提到 JSON Schema「关键词」时,特指对象「键/值对」中的「键」。而编写 JSON Schema 时,我们干的最多的事情,往往就是为每个对象里的每个值,匹配一个恰当的「关键词」。

For example, in the following, only strings are accepted: JSON Schema comments
{ "type": "string" } only strings are accepted
JSON comments valid or invalid
"I'm a string" V
42 X

The type keyword is described in more detail in Type-specific keywords.

如下所示,一个只接受字符串类型的 JSON Schema : JSON Schema 注释
{ "type": "string" } 只接受字符串类型
JSON 注释 验证结果
"I'm a string" 字符串类型,验证通过 V
42 数值类型,验证不通过 X

关于type关键词的更详细的描述,请参见「特定类型关键词」一节。

Declaring a JSON Schema | 声明一个 JSON Schema

It's not always easy to tell which draft a JSON Schema is using. You can use the $schema keyword to declare which version of the JSON Schema specification the schema is written to. See $schema for more information. It's generally good practice to include it, though it is not required.

由于存在多版本问题,使得人们很难凭空判断某个 JSON Schema 依据的是哪个草案版本( draft )。您可以通过使用关键词「 $schema 」来显示地声明您写的 schema 依据的是哪个版本的 JSON Schema 规范。更多信息请参阅「 $schema 」一节。尽管不是强制要求,但在您的 JSON Schema 里始终包含这样一个版本申明,是个好习惯。

Note

For brevity, the $schema keyword isn't included in most of the examples in this book, but it should always be used in the real world.

JSON Schema comments
{ "$schema": "https://json-schema.org/draft/2020-12/schema" }

注意

为简洁起见,本书示例大多省略了 $schema 关键词,但在实际工作中,请一定记得用起来。

JSON Schema 注释
{ "$schema": "https://json-schema.org/draft/2020-12/schema" }

Draft 4

In Draft 4, a $schema value of http://json-schema.org/schema# referred to the latest version of JSON Schema. This usage has since been deprecated and the use of specific version URIs is required.

草案 4

在草案 4 中,曾规定当 $schema 值为「 http://json-schema.org/schema# 」时,即表示指向最新版本的 JSON Schema 。此用法现已被废弃,以后 $schema 的值必须是如上所示的那样一个包含特定版本信息的资源定位符「 URI 」。

Declaring a unique identifier | 声明唯一标识符

It is also best practice to include an $id property as a unique identifier for each schema. For now, just set it to a URL at a domain you control, for example:

JSON Schema comments
{ "$id": "http://yourdomain.com/schemas/myschema.json" }

The details of $id become more apparent when you start Structuring a complex schema.

New in draft 6

Draft 4

In Draft 4, $id is just id (without the dollar-sign).

另一个最佳实践是,让您的 schema 里包含一个代表唯一标识符的 $id 属性。现在,只需将其赋值为您拥有的某个域名的一个网址「 URL 」即可,例如:

JSON Schema 注释
{ "$id": "http://yourdomain.com/schemas/myschema.json" }

仅当您开始创建一个较为复杂的 schema 时,\$id 才可能有机会体现其价值。

这是从 draft 6 开始引入的新特性

草案 4:

在草案 4 中,\$id 只有 id(不包含美元符号 \$ )。

JSON Schema Reference | JSON Schema 参考

Type-specific keywords | 特定于类型的关键词

The 「 type 」 keyword is fundamental to JSON Schema. It specifies the data type for a schema. At its core, JSON Schema defines the following basic types:

关键词「 type 」,JSON Schema 之魂。因为所有 schema 里的所有数据类型,都是由它定义的。作为内核,JSON Schema 里其实也就定义了以下几个基本类型:

These types have analogs in most programming languages, though they may go by different names.

The following table maps from the names of JSON types to their analogous types in Python and Ruby:

JSON Python Ruby
string string [4] String
number int/float [5] Integer/Float [6]
object dict Hash
array list Array
boolean bool TrueClass/FalseClass
null None NilClass

Footnotes

[4] Since JSON strings always support unicode, they are analogous to unicode on Python 2.x and str on Python 3.x.

[5] JSON does not have separate types for integer and floating-point.

[6] JSON does not have separate types for integer and floating-point.

除了某些叫法不同,这些类型存在于几乎所有编程语言里。

上述6大 JSON 数据类型与其在 Python 和 Ruby 中的对应名称,见上表。

脚注

【4】:JSON 的字符串一开始就支持 unicode 编码格式,对应 Python 2.x 中 unicode 和 Python 3.x 中的 str 。

【5】【6】:JSON 没有明确区分整数和浮点数类型。

The type keyword may either be a string or an array:

  • If it's a string, it is the name of one of the basic types above.
  • If it is an array, it must be an array of strings, where each string is the name of one of the basic types, and each element is unique. In this case, the JSON snippet is valid if it matches any of the given types.

Here is a simple example of using the type keyword:

JSON Schema comments
{ "type": "number" }
JSON comments valid or invalid
42 V
42.0 V
"42" This is not a number, it is a string containing a number. X

In the following example, we accept strings and numbers, but not structured data types:

JSON Schema comments
{ "type": ["number", "string"] }
JSON comments valid or invalid
42 V
"Life, the universe, and everything" V
["Life", "the universe", "and everything"] X

For each of these types, there are keywords that only apply to those types. For example, numeric types have a way of specifying a numeric range, that would not be applicable to other types. In this reference, these validation keywords are described along with each of their corresponding types in the following chapters.

出现在关键词「 type 」后面的,可以是由单个字符串表示的某类型名称,也可以是由一个字符串数组表示的多个类型:

一个使用 type 关键词的简单示例:

JSON Schema 注释
{ "type": "number" }
JSON 注释 验证结果
42 V
42.0 V
"42" 这不是一个数字,而是一个包含数字的字符串。 X

在接下来的示例中,同时接受字符串和数字,但决绝接受其他更结构化的数据类型:

JSON Schema 注释
{ "type": ["number", "string"] }
JSON 注释 验证结果
42 V
"Life, the universe, and everything" V
["Life", "the universe", "and everything"] X

上述数据类型,差不多每一种都会有一些专属的 schema 关键词。例如,用于为数字类型指定范围的,其他类型就没有。这些依赖于具体类型的关键词,留待后续章节逐一详述。

string | 字符串

The string type is used for strings of text. It may contain Unicode characters.

  • In Python, "string" is analogous to the unicode type on Python 2.x, and the str type on Python 3.x.
  • In Ruby, "string" is analogous to the String type.
JSON Schema comments
{ "type": "string"}
JSON comments valid or invalid
"This is a string" V
"Déjà vu" Unicode characters V
"" V
"42" V
42 X

这个名为「 string 」的「 type 」是用于定义文本字符串的。支持 Unicode 字符集。

JSON Schema 注释
{ "type": "string"}
JSON 注释 验证结果
"This is a string" V
"Déjà vu" Unicode 字符集 V
"" V
"42" V
42 X

Length | 长度

The length of a string can be constrained using the minLength and maxLength keywords. For both keywords, the value must be a non-negative number.

JSON Schema:

{
  "type": "string",
  "minLength": 2,
  "maxLength": 3
} 
JSON comments valid or invalid
"A" X
"AB" V
"ABC" V
"ABCD" X

关键词 minLength 和 maxLength 用于限定字符串的长度。两者都必须是非负数。

JSON Schema:

{
  "type": "string",
  "minLength": 2,
  "maxLength": 3
} 
JSON 注释 验证结果
"A" X
"AB" V
"ABC" V
"ABCD" X

Regular Expressions | 正则表达式

The pattern keyword is used to restrict a string to a particular regular expression. The regular expression syntax is the one defined in JavaScript (ECMA 262 specifically) with Unicode support. See Regular Expressions for more information.

Note

When defining the regular expressions, it's important to note that the string is considered valid if the expression matches anywhere within the string. For example, the regular expression "p" will match any string with a p in it, such as "apple" not just a string that is simply "p". Therefore, it is usually less confusing, as a matter of course, to surround the regular expression in ^...$, for example, "^p$", unless there is a good reason not to do so.

The following example matches a simple North American telephone number with an optional area code:

JSON Schema

{
  "type": "string",
  "pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
} 
JSON comments valid or invalid
"555-1212" V
"(888)555-1212" V
"(888)555-1212 ext. 532" X
"(800)FLOWERS" X

关键词「 pattern 」用于将一个字符串限制为某个特定的正则表达式。支持 Unicode 的正则表达式语法在 JavaScript(主要是 ECMA 262 )中有定义。详情请参阅「 Regular Expressions 」一节。

注意

通常,一个正则表达式只要能匹配出某字符串中的一个位置,该字符串就能被验证为有效。例如,一个内容为 "p" 的正则表达式,能匹配所有包含字母 p 的字符串,如 apple ,而不是仅仅只能匹配那个全部内容只有字母 p 的字符串「 "p" 」。因此,或者说理所当然,实用中更常见的,无疑是那些将主体内容用 "^...$" 括起来的正则表达式,如 "^p$" (可实现针对字符串「 "p" 」的精准匹配)。

以下示例,用于匹配一种格式简单的电话号码,北美的,区号可选:

JSON Schema

{
  "type": "string",
  "pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
} 
JSON 注释 验证结果
"555-1212" V
"(888)555-1212" V
"(888)555-1212 ext. 532" X
"(800)FLOWERS" X

Format | 格式

The format keyword allows for basic semantic identification of certain kinds of string values that are commonly used. For example, because JSON doesn't have a “DateTime” type, dates need to be encoded as strings. format allows the schema author to indicate that the string value should be interpreted as a date. By default, format is just an annotation and does not effect validation.

关键词「 format 」允许您对常用的某些类型的字符串值进行基本语义标识。例如,JSON 里没有 DateTime 类型,日期型数据就需要编码为字符串。即,允许 schema 创建者通过 format 将某种特定格式的字符串解释为日期类型的数据。默认情况下,format 只起注释作用,不影响验证。

Optionally, validator implementations can provide a configuration option to enable format to function as an assertion rather than just an annotation. That means that validation will fail if, for example, a value with a date format isn't in a form that can be parsed as a date. This can allow values to be constrained beyond what the other tools in JSON Schema, including Regular Expressions can do.

或者,市面上的验证器们,也可以通过提供一个配置选项,让「 format 」拥有验证能力,而不仅仅是个注释。这意思是,例如,如果一个「 format 」为日期的字符串无法被解析为真正日期数据,则整个验证结果为失败。这为 JSON Schema 提供了一种超出正则表达式的、更强大的数据约束能力。

Note

Implementations may provide validation for only a subset of the built-in formats or do partial validation for a given format. For example, some implementations may consider a string an email if it contains a @, while others might do additional checks for other aspects of a well formed email address.

In Draft 4-7, there is no guarantee that you get annotation-only behavior by default.

There is a bias toward networking-related formats in the JSON Schema specification, most likely due to its heritage in web technologies. However, custom formats may also be used, as long as the parties exchanging the JSON documents also exchange information about the custom format types. A JSON Schema validator will ignore any format type that it does not understand.

注意

某些验证器可能仅为全部内建「 format 」的一个子集提供验证,或者只对一个给定的「 format 」进行部分验证。例如,仅当某个字符串包含字符「 @ 」,某些验证器即可将其视为一个电子邮件,而别的验证器则可能在如何验证出一个「格式完美」的电子邮件地址这个问题上,大费周章。

Draft 4-7 中,无上述默认「仅注释」行为。

JSON Schema 规范中有不少与网络相关的内建「 format 」,这可能源于其先天的 WEB 技术基因。当然,自定义「 format 」也是被允许的,只要参与数据交换的各方在交换其 JSON 文档的同时附带上相关自定义「 format 」的助解信息。JSON Schema 验证器将无视那些它理解不了的「 format 」 。

Built-in formats | 内建「 format 」

The following is the list of formats specified in the JSON Schema specification.

下面列式 JSON Schema 规范中的内建「 format 」:

Dates and times | 日期与时间

Dates and times are represented in RFC 3339, section 5.6. This is a subset of the date format also commonly known as ISO8601 format.

  • "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.
  • "duration": New in draft 2019-09 A duration as defined by the ISO 8601 ABNF for “duration”. For example, P3D expresses a duration of 3 days.

这是日期格式的一个子集,请参阅 RFC 3339 的第 5.6 节,通常也称为 ISO8601 forma

Email addresses | 电子邮件地址

  • "email": Internet email address, see RFC 5321, section 4.1.2.
  • "idn-email": New in draft 7 The internationalized form of an Internet email address, see RFC 6531.

Hostnames | 主机名

  • "hostname": Internet host name, see RFC 1123, section 2.1.
  • "idn-hostname": New in draft 7 An internationalized Internet host name, see RFC5890, section 2.3.2.3.

IP Addresses | 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.

Resource identifiers | 资源标识符

  • "uuid": New in draft 2019-09 A Universally Unique Identifier as defined by RFC 4122. Example: 3e4666bf-d5e5-4aa7-b8ce-cefe41c7568a
  • "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

If the values in the schema have the ability to be relative to a particular source path (such as a link from a webpage), it is generally better practice to use "uri-reference" (or "iri-reference") rather than "uri" (or "iri"). "uri" should only be used when the path must be absolute.

Draft 4 only includes "uri", not "uri-reference". Therefore, there is some ambiguity around whether "uri" should accept relative paths.

如果能够为您的 schema 中的值选择相对路径(例如来自某个网页的链接地址),应尽量使用 "uri-reference"(或 "iri-reference" )而不是 "uri"(或 "iri" )。仅当要求必须使用绝对路径的地方,才用 "uri" 。

草案 4 中仅有 "uri" ,还没有 "uri-reference" 。因此,在草案 4 中关于 "uri" 是否应该接受相对路径是存在歧义的。

URI template | URI 模板

  • "uri-template": New in draft 6 A URI Template (of any level) according to RFC6570. If you don't already know what a URI Template is, you probably don't need this value.

JSON Pointer | JSON 指针

  • "json-pointer": New in draft 6 A JSON Pointer, according to RFC6901. There is more discussion on the use of JSON Pointer within JSON Schema in Structuring a complex schema. Note that this should be used only when the entire string contains only JSON Pointer content, e.g. /foo/bar. JSON Pointer URI fragments, e.g. #/foo/bar/ should use "uri-reference".
  • "relative-json-pointer": New in draft 7 A relative JSON pointer.

Regular Expressions | 正则表达式

  • "regex": New in draft 7 A regular expression, which should be valid according to the ECMA 262 dialect.

Be careful, in practice, JSON schema validators are only required to accept the safe subset of Regular Expressions described elsewhere in this document.

注意,实践中,JSON Schema 验证器只要求实现上述文档所述的正则表达式的安全子集。

Regular Expressions | 正则表达式

The pattern and Pattern Properties keywords use regular expressions to express constraints. The regular expression syntax used is from JavaScript (ECMA 262, specifically). However, that complete syntax is not widely supported, therefore it is recommended that you stick to the subset of that syntax described below.

关键词「 pattern 」以及其他模式属性类关键词,均采用正则表达式来实现约束。其正则表达式语法直接借用自 JavaScript(主要是 ECMA 262 ),但又借用得并不完整,因此建议您只使用如下所述的这个子集:

  • A single unicode character (other than the special characters below) matches itself.
  • .: Matches any character except line break characters. (Be aware that what constitutes a line break character is somewhat dependent on your platform and language environment, but in practice this rarely matters).
  • ^: Matches only at the beginning of the string.
  • $: Matches only at the end of the string.
  • (...): Group a series of regular expressions into a single regular expression.
  • |: Matches either the regular expression preceding or following the | symbol.
  • [abc]: Matches any of the characters inside the square brackets.
  • [a-z]: Matches the range of characters.
  • [^abc]: Matches any character not listed.
  • [^a-z]: Matches any character outside of the range.
  • +: Matches one or more repetitions of the preceding regular expression.
  • *: Matches zero or more repetitions of the preceding regular expression.
  • ?: Matches zero or one repetitions of the preceding regular expression.
  • +?, ?, ??: The , +, and ? qualifiers are all greedy; they match as much text as possible. Sometimes this behavior isn't desired and you want to match as few characters as possible.
  • (?!x), (?=x): Negative and positive lookahead.
  • {x}: Match exactly x occurrences of the preceding regular expression.
  • {x,y}: Match at least x and at most y occurrences of the preceding regular expression.
  • {x,}: Match x occurrences or more of the preceding regular expression.
  • {x}?, {x,y}?, {x,}?: Lazy versions of the above expressions.

Example | 示例

The following example matches a simple North American telephone number with an optional area code:

JSON Schema

{
  "type": "string",
  "pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
} 
JSON comments valid or invalid
"555-1212" V
"(888)555-1212" V
"(888)555-1212 ext. 532" X
"(800)FLOWERS" X

以下示例,用于匹配一种格式简单的电话号码,北美的,区号可选:

JSON Schema

{
  "type": "string",
  "pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
} 
JSON 注释 验证结果
"555-1212" V
"(888)555-1212" V
"(888)555-1212 ext. 532" X
"(800)FLOWERS" X

Numeric types | 数值类型

There are two numeric types in JSON Schema: integer and number. They share the same validation keywords.

Note

JSON has no standard way to represent complex numbers, so there is no way to test for them in JSON Schema.

JSON Schema 中有两种数值类型:整数 integer 和数字 number 。它们共享相同的验证关键词。

注意

JSON 没有表示复数的标准方法,因此无法在 JSON Schema 中测试它们。

integer | 整数

The integer type is used for integral numbers. JSON does not have distinct types for integers and floating-point values. Therefore, the presence or absence of a decimal point is not enough to distinguish between integers and non-integers. For example, 1 and 1.0 are two ways to represent the same value in JSON. JSON Schema considers that value an integer no matter which representation was used.

  • In Python, "integer" is analogous to the int type.
  • In Ruby, "integer" is analogous to the Integer type.

JSON Schema

{
  "type": "integer"
} 
JSON comments valid or invalid
42 V
-1 V
1.0 Numbers with a zero fractional part are considered integers V
3.1415926 Floating point numbers are rejected X
"42" Numbers as strings are rejected X

类型 integer 用于验证整数。JSON 没有专门的浮点类型。是否存在小数点不是区分整数和非整数的关键。如,1 和 1.0 相同。在 JSON Schema 里,它们都是整数。

JSON Schema

{
  "type": "integer"
} 
JSON 注释 验证结果
42 V
-1 V
1.0 小数部分为零的数字被视为整数 V
3.1415926 拒绝浮点数 X
"42" 拒绝字符串 X

number | 数

The number type is used for any numeric type, either integers or floating point numbers.

  • In Python, "number" is analogous to the float type.
  • In Ruby, "number" is analogous to the Float type.

JSON Schema

{
  "type": "number"
} 
JSON comments valid or invalid
42 V
-1 V
5.0 Simple floating point number V
2.99792458e8 Exponential notation also works V
"42" Numbers as strings are rejected X

类型 number 用于验证所有数值类型,无论是整数,还是浮点数。

JSON Schema

{
  "type": "number"
} 
JSON 注释 验证结果
42 V
-1 V
5.0 简单浮点数 V
2.99792458e8 指数表示法也有效 V
"42" 拒绝字符串 X

Multiples | 倍数

Numbers can be restricted to a multiple of a given number, using the multipleOf keyword. It may be set to any positive number.

JSON Schema

{
  "type": "number",
  "multipleOf" : 10
} 
JSON comments valid or invalid
0 V
10 V
20 V
23 Not a multiple of 10 X

关键词 multipleOf 用于将数字类型 number 的值限定为某个给定数字的倍数。它可以设置为任何正数。

JSON Schema

{
  "type": "number",
  "multipleOf" : 10
} 
JSON 注释 验证结果
0 V
10 V
20 V
23 不是 10 的倍数 X

Range | 范围

Ranges of numbers are specified using a combination of the minimum and maximum keywords, (or exclusiveMinimum and exclusiveMaximum for expressing exclusive range).

If x is the value being validated, the following must hold true:

  • x ≥ minimum
  • x > exclusiveMinimum
  • x ≤ maximum
  • x < exclusiveMaximum

While you can specify both of minimum and exclusiveMinimum or both of maximum and exclusiveMaximum, it doesn't really make sense to do so.

JSON Schema

{
  "type": "number",
  "minimum": 0,
  "exclusiveMaximum": 100
} 
JSON comments valid or invalid
-1 Less than minimum X
0 minimum is inclusive, so 0 is valid V
10 V
99 V
100 exclusiveMaximum is exclusive, so 100 is not valid X
101 Greater than maximum X

数字范围,由下限关键词 minimum 和上限关键词 maximum 组合框定(或由近下限关键词 exclusiveMinimum 和近上限关键词 exclusiveMaximum 参与框定)。

即,假如 x 是一个等待被验证的值,下列内容必须全部成立:

虽然您大可以让 minimum 和 exclusiveMinimum 以及 maximum 和 exclusiveMaximum 同时出现,但这样做貌似没什么意义。

JSON Schema

{
  "type": "number",
  "minimum": 0,
  "exclusiveMaximum": 100
} 
JSON 注释 验证结果
-1 小于最小值 X
0 0 是被包含的最小值,因此 0 有效 V
10 V
99 V
100 100 是不被包含的最大值,因此 100 无效 X
101 大于最大值 X

Draft 4

In JSON Schema Draft 4, exclusiveMinimum and exclusiveMaximum work differently. There they are boolean values, that indicate whether minimum and maximum are exclusive of the value. For example:

  • if exclusiveMinimum is false, x ≥ minimum.
  • if exclusiveMinimum is true, x > minimum.

This was changed to have better keyword independence.

Here is an example using the older Draft 4 convention:

JSON Schema

{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "exclusiveMaximum": true
} 
JSON comments valid or invalid
-1 Less than minimum X
0 exclusiveMinimum was not specified, so 0 is included V
10 V
99 V
100 exclusiveMaximum is true, so 100 is not included X
101 Greater than maximum X

Draft 4 | 草案 4

在 JSON Schema 的草稿 4 中,exclusiveMinimum 和 exclusiveMaximum 被定义为两个分别依赖 minimum 和 maximum 而存在布尔值,可以通过组合以决定最终是否包含其边界值。如:

修订后,显然具有了更好的关键词独立性 keyword independence 。

下面是使用较旧的草案 4 约定的示例:

JSON Schema

{
  "type": "number",
  "minimum": 0,
  "maximum": 100,
  "exclusiveMaximum": true
} 
JSON 注释 验证结果
-1 小于最小值 X
0 未指定 exclusiveMinimum ,因此包含 0 V
10 V
99 V
100 指定了 exclusiveMaximum ,且值为 true, 因此不包含 100 X
101 大于最大值 X

object | 对象

Objects are the mapping type in JSON. They map “keys” to “values”. In JSON, the “keys” must always be strings. Each of these pairs is conventionally referred to as a “property”.

对象 Objects ,是指 JSON 中的映射类型——从「键 keys 」映射到「值 values 」。在 JSON 中,「键 keys 」要求只能是字符串。这些键值对通常也被称为「属性 property 」。

  • In Python, "objects" are analogous to the dict type. An important difference, however, is that while Python dictionaries may use anything hashable as a key, in JSON all the keys must be strings.

    Try not to be confused by the two uses of the word "object" here: Python uses the word object to mean the generic base class for everything, whereas in JSON it is used only to mean a mapping from string keys to values.

  • In Ruby, "objects" are analogous to the Hash type. An important difference, however, is that all keys in JSON must be strings, and therefore any non-string keys are converted over to their string representation.

    Try not to be confused by the two uses of the word "object" here: Ruby uses the word Object to mean the generic base class for everything, whereas in JSON it is used only to mean a mapping from string keys to values.

JSON Schema

{
  "type": "object"
} 

JSONV

{
   "key": "value",
   "another_key": "another_value"
}

JSONV

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

JSONX

Using non-strings as keys is invalid JSON:

使用非字符串作为键是无效的 JSON:

{
    0.01: "cm",
    1: "m",
    1000: "km"
}

JSONX

"Not an object"

JSONX

["An", "array", "not", "an", "object"]

Properties | 属性

The properties (key-value pairs) on an object are defined using the properties keyword. The value of properties is an object, where each key is the name of a property and each value is a schema used to validate that property. Any property that doesn't match any of the property names in the properties keyword is ignored by this keyword.

对象属性(键值对)是用关键词 properties 来定义的。键 properties 对应的值也是一个对象,该对象里的每个键,即为属性名,其值,则是一个真正用于验证该属性的 shcema 。如果某个 JSON 属性不在此列,验证会忽略它(而非验证不通过)。

Note

See Additional Properties and Unevaluated Properties for how to disallow properties that don't match any of the property names in properties.

For example, let's say we want to define a simple schema for an address made up of a number, street name and street type:

注意

关于验证中,要如何禁止那些没在 properties 里的属性表里的某个 JSON 属性,请参阅后面的「意外属性 」和「未评估的属性 」这两节。

例如,假设我们要为一个由数字、街道名称和街道类型等这三个属性组成的地址数据类型,定义一个简单的 schema :

JSON Schema:

{
    "type": "object",
    "properties": {
        "number": { "type": "number" },
        "street_name": { "type": "string" },
        "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
    }
}

JSONV

{
    "number": 1600, 
    "street_name": "Pennsylvania", 
    "street_type": "Avenue" 
}

JSONX

If we provide the number in the wrong type, it is invalid:

如果我们以错误的类型提供数字,则将验证为不通过:

{
    "number": "1600", 
    "street_name": "Pennsylvania", 
    "street_type": "Avenue" 
}

JSONV

By default, leaving out properties is valid. See Required Properties.

默认情况下,省略属性是有效的。请参阅「必需属性」这一节。

{
    "number": 1600, 
    "street_name": "Pennsylvania", 
}

JSONV

By extension, even an empty object is valid:

即使空对象也是有效的:

{}

JSONV

By default, providing additional properties is valid:

默认情况下,额外的属性,是可以被验证通过的:

{
    "number": 1600, 
    "street_name": "Pennsylvania", 
    "street_type": "Avenue", 
    "direction": "NW"
}

Pattern Properties | 模式属性

Sometimes you want to say that, given a particular kind of property name, the value should match a particular schema. That's where patternProperties comes in: it maps regular expressions to schemas. If a property name matches the given regular expression, the property value must validate against the corresponding schema.

也许您也曾有此心声,能否通过给予特定类型的属性名称,即可匹配特定模式的值。这就是关键词 patternProperties 要干的事:它将正则表达式直接应用到 schema 里。如果某个属性名称与给定的正则表达式匹配,则该属性对应的值必须用与该正则表达式对应的 shcema 进行验证。

Note

Regular expressions are not anchored. This means that when defining the regular expressions for patternProperties, it's important to note that the expression may match anywhere within the property name. For example, the regular expression "p" will match any property name with a p in it, such as "apple", not just a property whose name is simply "p". It's therefore usually less confusing to surround the regular expression in ^...$, for example, "^p$".

注意

正则表达式不锚定。这意味着,在为 patternProperties 定义正则表达式时,请务必注意,表达式可能与属性名称中的任何位置匹配。例如,正则表达式 "p" 将匹配任何包含 p 的属性名称,如 "apple" ,而不仅仅是名称仅为"p"的属性。因此,将正则表达式括在 ^...$ 之中,通常不容易造成混淆,如 "^p$" 。

In this example, any properties whose names start with the prefix "S" must be strings, and any with the prefix " I" must be integers. Any properties that do not match either regular expression are ignored.

在此示例中,名称以前缀 "S" 开头的属性都必须是字符串,前缀为 "I" 的属性都必须是整数。与任一正则表达式都不匹配的属性都将被忽略。

JSON Schema

{
  "type": "object",
  "patternProperties": {
    "^S_": { "type": "string" },
    "^I_": { "type": "integer" }
  }
}

JSONV

{
    "S_25": "This is a string" 
}

JSONV

{
    "I_0": 42 
}

JSONX

If the name starts with S_, it must be a string

如果名称以 S_ 开头,则必须为字符串

{
    "S_0": 42
}

JSONX

f the name starts with I_, it must be an integer

如果名称以 I_ 开头,则它必须是整数

{
    "I_42": "This is a string"
}

JSONV

This is a key that doesn't match any of the regular expressions:

这里有一个与任何正则表达式都不匹配的键:

{
    "keyword": "value" 
}

Additional Properties | 意外属性

The additionalProperties keyword is used to control the handling of extra stuff, that is, properties whose names are not listed in the properties keyword or match any of the regular expressions in the patternProperties keyword. By default any additional properties are allowed.

关键词 additionalProperties 用于决定是否控制意外属性,所谓意外属性,即,名称既未出现在 properties 包含的属性列表里,也不与 patternProperties 中的任何正则表达式相匹配的属性。默认情况下,允许任何意外属性。

The value of the additionalProperties keyword is a schema that will be used to validate any properties in the instance that are not matched by properties or patternProperties. Setting the additionalProperties schema to false means no additional properties will be allowed.

关键词 additionalProperties 的值是一个 shcema ,专门用于验证那些出现在实例中、但却与 properties 和 patternProperties 中的属性名称都不匹配的属性。当将 additionalProperties 的值设为 false ,意味着不允许出现任何意外属性。

Reusing the example from Properties, but this time setting additionalProperties to false.

下面重用「属性 Properties」那一节的示例,但这次设置了 additionalProperties 且其值为 false 。

JSON Schema:

{
  "type": "object",
  "properties": {
    "number": { "type": "number" },
    "street_name": { "type": "string" },
    "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
  },
  "additionalProperties": false
}

JSONV

{
    "number": 1600, 
    "street_name": "Pennsylvania", 
    "street_type": "Avenue"
}

JSONX

Since additionalProperties is false, this extra property “direction” makes the object invalid:

由于 additionalProperties 的值为 false,其中的意外属性 "direction" 将使对象无效:

{
    "number": 1600, 
    "street_name": "Pennsylvania", 
    "street_type": "Avenue",
    "direction": "NW"
}

You can use non-boolean schemas to put more complex constraints on the additional properties of an instance. For example, one can allow additional properties, but only if their values are each a string:

您也可以为 additionalProperties 赋予比布尔类型更复杂的实例约束。如下,一个允许 additionalProperties 的 schema,其 additionalProperties 的值被限定为字符串类型:

JSON Schema:

{
  "type": "object",
  "properties": {
    "number": { "type": "number" },
    "street_name": { "type": "string" },
    "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
  },
  "additionalProperties": { "type": "string" }
}

JSONV

{ 
  "number": 1600, 
  "street_name": "Pennsylvania", 
  "street_type": "Avenue" 
}

JSONV

This is valid, since the additional property's value is a string:

这是有效的,因为意外属性 direction 的值是一个字符串:

{ 
  "number": 1600, 
  "street_name": "Pennsylvania", 
  "street_type": "Avenue", 
  "direction": "NW" 
}

JSONX

This is invalid, since the additional property's value is not a string:

这是无效的,因为意外属性 office_number 的值不是字符串:

{ 
  "number": 1600, 
  "street_name": "Pennsylvania", 
  "street_type": "Avenue", 
  "office_number": 201 
}

You can use additionalProperties with a combination of properties and patternProperties. In the following example, based on the example from Pattern Properties, we add a "builtin" property, which must be a number, and declare that all additional properties (that are neither defined by properties nor matched by patternProperties) must be strings:

您也可以将 additionalProperties 与 properties 和 patternProperties 组合起来使用。如下所示,在「 Pattern Properties 」一节的示例基础上,添加一个名为 "builtin" 的属性,其值被规定为数字类型,所有意外属性(既不属于 properties ,也不匹配 patternProperties )必须是字符串:

JSON Schema:

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

JSONV

{ "builtin": 42 }

JSONV

This is a key that doesn't match any of the regular expressions:

一个与任何正则表达式都不匹配的键( "keyword" 为字符串类型,满足 additionalProperties 的规定,验证通过):

{ "keyword": "value" }

JSONX

It must be a string:

必须为字符串( "keyword" 为数值类型,不满足 additionalProperties 的规定,验证不通过):

{ "keyword": 42 }
Extending Closed Schemas | 扩展封闭 schema

It's important to note that additionalProperties only recognizes properties declared in the same subschema as itself. So, additionalProperties can restrict you from “extending” a schema using Schema Composition keywords such as allOf. In the following example, we can see how the additionalProperties can cause attempts to extend the address schema example to fail.

请务必注意,additionalProperties 仅识别与自身在同一个子 schema 块中声明的属性。因此,additionalProperties 会限制您使用 Schema Composition 类关键词,如 allOf,去扩展一个 schema 。如下所示,我们可以看到 additionalProperties 的存在对扩展一个地址 schema 的尝试是如何带来麻烦的。

JSON Schema:

{
  "allOf": [
    {
      "type": "object",
      "properties": {
        "street_address": { "type": "string" },
        "city": { "type": "string" },
        "state": { "type": "string" }
      },
      "required": ["street_address", "city", "state"],
      "additionalProperties": false
    }
  ],

  "properties": {
    "type": { "enum": [ "residential", "business" ] }
  },
  "required": ["type"]
}

JSONX

Fails additionalProperties. "type" is considered additional.

无法通过 additionalProperties 验证。因为按 schema 的要求,名为 "type" 的属性会被认为是「意外 additional 」的。

{
   "street_address": "1600 Pennsylvania Avenue NW",
   "city": "Washington",
   "state": "DC",
   "type": "business"
}

JSONX

Fails required. “type” is required.

无法通过 required 验证。因为按 schema 的要求,名为 "type" 的属性又是「必需 required 」的。

{
   "street_address": "1600 Pennsylvania Avenue NW",
   "city": "Washington",
   "state": "DC"
}

Because additionalProperties only recognizes properties declared in the same subschema, it considers anything other than “street_address”, “city”, and “state” to be additional. Combining the schemas with allOf doesn't change that. A workaround you can use is to move additionalProperties to the extending schema and redeclare the properties from the extended schema.

由于 additionalProperties 仅识别在同一子 schema 中声明的属性,因此它将除"street_address" 、"city" 、和 "state" 以外的任何内容视为「意外 additional 」 。用 allOf 也无法改变这一点。可以使用的解决方法是将 additionalProperties 移动到一个扩展 schema 里,在扩展 schema 里重新声明属性。

JSON Schema:

{
  "allOf": [
    {
      "type": "object",
      "properties": {
        "street_address": { "type": "string" },
        "city": { "type": "string" },
        "state": { "type": "string" }
      },
      "required": ["street_address", "city", "state"]
    }
  ],

  "properties": {
    "street_address": true,
    "city": true,
    "state": true,
    "type": { "enum": [ "residential", "business" ] }
  },
  "required": ["type"],
  "additionalProperties": false
}

JSONV

{
   "street_address": "1600 Pennsylvania Avenue NW",
   "city": "Washington",
   "state": "DC",
   "type": "business"
}

JSONX

{
   "street_address": "1600 Pennsylvania Avenue NW",
   "city": "Washington",
   "state": "DC",
   "type": "business",
   "something that doesn't belong": "hi!"
}

Now the additionalProperties keyword is able to recognize all the necessary properties and the schema works as expected. Keep reading to see how the unevaluatedProperties keyword solves this problem without needing to redeclare properties.

现在,additionalProperties 关键词能够识别所有必要的属性了,整个 schema 也按预期工作。继续阅读,您将了解关键词 unevaluatedProperties 是如何解决此问题的——无需重新声明属性。

Unevaluated Properties | 未评估的属性

New in draft 2019-09 | 草案 2019-09 新增的内容:

In the previous section we saw the challenges with using additionalProperties when “extending” a schema using Schema Composition. The unevaluatedProperties keyword is similar to additionalProperties except that it can recognize properties declared in subschemas. So, the example from the previous section can be rewritten without the need to redeclare properties.

在上一节中,我们看到了在使用 Schema Composition 扩展一个 schema 时, additionalProperties 带来的挑战。关键词 unevaluatedProperties 类似于 additionalProperties ,不同之处在于它可以识别在子 schema 中声明的属性。因此,下面重写的上一节的示例中,将无需重新声明属性了。

JSON Schema:

{
  "allOf": [
    {
      "type": "object",
      "properties": {
        "street_address": { "type": "string" },
        "city": { "type": "string" },
        "state": { "type": "string" }
      },
      "required": ["street_address", "city", "state"]
    }
  ],

  "properties": {
    "type": { "enum": ["residential", "business"] }
  },
  "required": ["type"],
  "unevaluatedProperties": false
}

JSONV

{
   "street_address": "1600 Pennsylvania Avenue NW",
   "city": "Washington",
   "state": "DC",
   "type": "business"
}

JSONX

{
   "street_address": "1600 Pennsylvania Avenue NW",
   "city": "Washington",
   "state": "DC",
   "type": "business",
   "something that doesn't belong": "hi!"
}

unevaluatedProperties works by collecting any properties that are successfully validated when processing the schemas and using those as the allowed list of properties. This allows you to do more complex things like conditionally adding properties. The following example allows the “department” property only if the “type” of address is “business”.

unevaluatedProperties 的工作原理是收集那些被 schema 验证通过属性,构建一个允许属性列表。这允许您执行更复杂的操作,例如有条件地添加属性。以下示例仅在地址的 "type" 为 "business" 时才允许使用名为 "department" 的属性。

JSON Schema:

{
  "type": "object",
  "properties": {
    "street_address": { "type": "string" },
    "city": { "type": "string" },
    "state": { "type": "string" },
    "type": { "enum": ["residential", "business"] }
  },
  "required": ["street_address", "city", "state", "type"],

  "if": {
    "type": "object",
    "properties": {
      "type": { "const": "business" }
    },
    "required": ["type"]
  },
  "then": {
    "properties": {
      "department": { "type": "string" }
    }
  },

  "unevaluatedProperties": false
}

JSONV

{
  "street_address": "1600 Pennsylvania Avenue NW",
  "city": "Washington",
  "state": "DC",
  "type": "business",
  "department": "HR"
}

JSONX

{
  "street_address": "1600 Pennsylvania Avenue NW",
  "city": "Washington",
  "state": "DC",
  "type": "residential",
  "department": "HR"
}

In this schema, the properties declared in the then schema only count as “evaluated” properties if the “type” of the address is “business”.

上述 schema 的意思是,仅当某个地址的 "type" 值为 "business" 时,关键词 "then" 所对应的 schema 代码块中声明的 "properties" (即,"department" )才算得上是“已评估”的属性。

Required Properties | 必须属性

By default, the properties defined by the properties keyword are not required. However, one can provide a list of required properties using the required keyword.

The required keyword takes an array of zero or more strings. Each of these strings must be unique.

默认情况下,由关键词 "properties" 定义的属性并不要求必需(出现在 JSON 里)。可通过关键词 "required" 申明一个属性列表来补充实现必需性验证。

关键词 "required" 的值为一个由零个或多个字符串构成的数组。数组中的每个字符串必须唯一。

Draft 4 | 草案 4

In Draft 4, required must contain at least one string.

在草案 4 中,关键词 "required" 的值要求必须至少包含一个字符串。

In the following example schema defining a user record, we require that each user has a name and e-mail address, but we don't mind if they don't provide their address or telephone number:

如下所示,为一个定义用户信息的 schema ,其中属性 name 和 e-mail 是「必需 required 」的,而属性 address 和 telephone 则无所谓:

JSON Schema:

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "email": { "type": "string" },
    "address": { "type": "string" },
    "telephone": { "type": "string" }
  },
  "required": ["name", "email"]
}

JSONV

{
  "name": "William Shakespeare",
  "email": "bill@stratford-upon-avon.co.uk"
}

JSONV

Providing extra properties is fine, even properties not defined in the schema:

允许出现额外的、schema 中未定义的属性:

{
  "name": "William Shakespeare",
  "email": "bill@stratford-upon-avon.co.uk",
  "address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
  "authorship": "in question"
}

JSONX

Missing the required “email” property makes the JSON document invalid:

缺少必需的 "email" 属性,使该 JSON 文档无效:

{
  "name": "William Shakespeare",
  "address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
}

JSONX

In JSON a property with value null is not equivalent to the property not being present. This fails because null is not of type “string”, it's of type “null”

在 JSON 中,「值为 null 的属性」的意思不是「该属性不存在」。值 null 属于一个专门叫 null 的类型,null 类型 与「字符串 string 」类型,是两个不同的类型。因此,此处验证为不通过。

{
  "name": "William Shakespeare",
  "address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
  "email": null
}

Property names | 属性名称

New in draft 6 | 草案6中的新增内容

The names of properties can be validated against a schema, irrespective of their values. This can be useful if you don't want to enforce specific properties, but you want to make sure that the names of those properties follow a specific convention. You might, for example, want to enforce that all names are valid ASCII tokens so they can be used as attributes in a particular programming language.

可以让 schema 仅验证属性名称,而忽略其值。这可用于当您需要某些属性的名称遵循特殊约定时。例如,您可能希望强制所有属性名称都是有效的 ASCII 标记,以便它们可以用于某特定编程语言。

JSON Schema:

{
  "type": "object",
  "propertyNames": {
    "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
  }
}

JSONV

{
  "_a_proper_token_001": "value"
}

JSONX

{
  "001 invalid": "value"
}

Since object keys must always be strings anyway, it is implied that the schema given to propertyNames is always at least:

{ "type": "string" }

由于对象的键名只能是字符串,因此关键词 propertyNames 的 schema 里已经暗含了:

{ "type": "string" }

Size | 属性数量

The number of properties on an object can be restricted using the minProperties and maxProperties keywords. Each of these must be a non-negative integer.

关键词 minProperties 和 maxProperties 用于限制对象上的属性数量。要求值为非负整数。

JSON Schema:

{
  "type": "object",
  "minProperties": 2,
  "maxProperties": 3
}
JSON 注释 验证结果
{} X
{ "a": 0 } X
{ "a": 0, "b": 1 } V
{ "a": 0, "b": 1, "c": 2 } V
{ "a": 0, "b": 1, "c": 2, "d": 3 } X

array | 数组

Arrays are used for ordered elements. In JSON, each element in an array may be of a different type.

  • In Python, "array" is analogous to a list or tuple type, depending on usage. However, the json module in the Python standard library will always use Python lists to represent JSON arrays.
  • In Ruby, "array" is analogous to a Array type.

数组用于有序元素。JSON 中,数组的每个元素的类型可以不同。

JSON Schema:

{ "type": "array" }
JSON 注释 验证结果
[1, 2, 3, 4, 5] V
[3, "different", { "types" : "of values" }] V
{"Not": "an array"} X

There are two ways in which arrays are generally used in JSON:

  • List validation: a sequence of arbitrary length where each item matches the same schema.
  • Tuple validation: a sequence of fixed length where each item may have a different schema. In this usage, the index (or location) of each item is meaningful as to how the value is interpreted. (This usage is often given a whole separate type in some programming languages, such as Python's tuple).

在 JSON 中通常有两种使用数组的方式:

Items | 元素

List validation is useful for arrays of arbitrary length where each item matches the same schema. For this kind of array, set the items keyword to a single schema that will be used to validate all of the items in the array.

In the following example, we define that each item in an array is a number:

列表验证用于验证任意长度的数组,所有元素匹配同一个 schema 。对于此类数组,请将关键词 items 的值设置为将用于验证数组中所有元素的单一 schema 。

如下所示,我们定义一个每个元素都是数字的数组:

JSON Schema:

{
  "type": "array",
  "items": {
    "type": "number"
  }
}
JSON 注释 验证结果
[1, 2, 3, 4, 5] V
[1, 2, "3", 4, 5] A single “non-number” causes the whole array to be invalid 单个“非数字”导致整个数组无效 X
[] The empty array is always valid 空数组始终有效 V

Tuple validation | 元组验证

Tuple validation is useful when the array is a collection of items where each has a different schema and the ordinal index of each item is meaningful.

For example, you may represent a street address such as:

1600 Pennsylvania Avenue NW

as a 4-tuple of the form:

[number, street_name, street_type, direction]

元组验证,用于当数组的每个元素需要匹配不同的 schema 时。

例如,您可以将一个街道地址:

1600 Pennsylvania Avenue NW

设定为一个 4 元组:

[number, street_name, street_type, direction]

Each of these fields will have a different schema:

  • number: The address number. Must be a number.
  • street_name: The name of the street. Must be a string.
  • street_type: The type of street. Should be a string from a fixed set of values.
  • direction: The city quadrant of the address. Should be a string from a different set of values.

每个字段将匹配不同的 schema :

To do this, we use the prefixItems keyword. prefixItems is an array, where each item is a schema that corresponds to each index of the document's array. That is, an array where the first element validates the first element of the input array, the second element validates the second element of the input array, etc.

为了实现这一点,需要使用关键词 prefixItems 。prefixItems 也是一个数组,其元素是与文档数组元素按索引一一对应的 schema 。也就是说,其第一个元素用于验证输入数组的第一个元素,第二个元素用于验证输入数组的第二个元素……,依此类推。

In Draft 4 - 2019-09, tuple validation was handled by an alternate form of the items keyword. When items was an array of schemas instead of a single schema, it behaved the way prefixItems behaves.

Here's the example schema:

在草案 4 - 2019-09 中,元组验证由关键词 items 的另一种内容形式来实现。当 items 是 一个 schema 数组而非单个 schema 时,它的行为方式与 prefixItems 的行为方式相同。

如下所示:

JSON Schema:

{
  "type": "array",
  "prefixItems": [
    { "type": "number" },
    { "type": "string" },
    { "enum": ["Street", "Avenue", "Boulevard"] },
    { "enum": ["NW", "NE", "SW", "SE"] }
  ]
}
JSON 注释 验证结果
[1600, "Pennsylvania", "Avenue", "NW"] V
[24, "Sussex", "Drive"] “Drive” is not one of the acceptable street types "Drive"不在可接受的街道类型之列 X
["Palais de l'Élysée"] This address is missing a street number 此地址缺少门牌号 X
[10, "Downing", "Street"] It's okay to not provide all of the items 允许内容不全 V
[1600, "Pennsylvania", "Avenue", "NW", "Washington"] And, by default, it's also okay to add additional items to end 而且,默认允许在末尾添加 schema 里没做规定的元素 V
Additional Items | 附加元素

The items keyword can be used to control whether it's valid to have additional items in a tuple beyond what is defined in prefixItems. The value of the items keyword is a schema that all additional items must pass in order for the keyword to validate.

  • Draft 4 - 2019-09:Before to Draft 2020-12, you would use the additionalItems keyword to constrain additional items on a tuple. It works the same as items, only the name has changed.
  • Draft 6 - 2019-09:In Draft 6 - 2019-09, the additionalItems keyword is ignored if there is not a "tuple validation" items keyword present in the same schema.

Here, we'll reuse the example schema above, but set items to false, which has the effect of disallowing extra items in the tuple.

关键词 items 可用于控制元组中超出 prefixItems 中定义的元素的验证。关键词 items 的值是一个 schema ,一个用于所有附加元素验证的 schema 。

在此,我们将重用上面的示例,但将 items 的值设置为 false ,这将产生不允许元组中有额外元素的效果。

JSON Schema:

{
  "type": "array",
  "prefixItems": [
    { "type": "number" },
    { "type": "string" },
    { "enum": ["Street", "Avenue", "Boulevard"] },
    { "enum": ["NW", "NE", "SW", "SE"] }
  ],
  "items": false
}
JSON 注释 验证结果
[1600, "Pennsylvania", "Avenue", "NW"] V
[1600, "Pennsylvania", "Avenue"] It's ok to not provide all of the items 允许只有部分元素 V [24, "Sussex", "Drive"] “Drive” is not one of the acceptable street types "Drive"不在可接受的街道类型之列 X
[1600, "Pennsylvania", "Avenue", "NW", "Washington"] But, since items is false, we can't provide extra items 由于 items 的值为 false ,不允许添加额外元素 X

You can express more complex constraints by using a non-boolean schema to constrain what value additional items can have. In that case, we could say that additional items are allowed, as long as they are all strings:

您可以通过为附加元素使用非布尔型的 schema 来表示更复杂的约束。如下所示,我们可以说允许其他元素,只要它们都是字符串:

JSON Schema:

{
  "type": "array",
  "prefixItems": [
    { "type": "number" },
    { "type": "string" },
    { "enum": ["Street", "Avenue", "Boulevard"] },
    { "enum": ["NW", "NE", "SW", "SE"] }
  ],
  "items": { "type": "string" }
}
JSON 注释 验证结果
[1600, "Pennsylvania", "Avenue", "NW", "Washington"] Extra string items are ok … 允许额外的字符串元素 V
[1600, "Pennsylvania", "Avenue", "NW", 20500] … but not anything else 但不是任何东西都会被允许 X

Unevaluated Items | 未评估的元素

New in draft 2019-09 | 草案 2019-09 中的新内容

Documentation Coming Soon

文档还在创作中

Contains | 包含

New in draft 6 | 草案 6 中的新内容

While the items schema must be valid for every item in the array, the contains schema only needs to validate against one or more items in the array.

items schema 必须对数组中的每个项目都有效,contains schema 只需要针对数组中的一个或多个项目进行验证。

JSON Schema

{
   "type": "array",
   "contains": {
     "type": "number"
   }
}
JSON 注释 验证结果
["life", "universe", "everything", 42] A single “number” is enough to make this pass 仅需要数组中有一个数字类元素即可 V
["life", "universe", "everything", "forty-two"] But if we have no number, it fails 如果一个数字类元素都没有,则验证不通过 X
[1, 2, 3, 4, 5] All numbers is, of course, also okay 当然也允许所有元素都是数字的 V
minContains / maxContains

New in draft 2019-09 | 草案 2019-09 中的新内容

minContains and maxContains can be used with contains to further specify how many times a schema matches a contains constraint. These keywords can be any non-negative number including zero.

minContains 和 maxContains 可以与 contains 一起使用,以进一步指定一个 schema 中的 contains 中的内容需要被匹配的次数。这俩关键词可以是任何非负数,包括零。

JSON Schema:

{
  "type": "array",
  "contains": {
    "type": "number"
  },
  "minContains": 2,
  "maxContains": 3
}
JSON 注释 验证结果
["apple", "orange", 2] Fails minContains 未通过 minContains 的验证 X
["apple", "orange", 2, 4] V
["apple", "orange", 2, 4, 8] V
["apple", "orange", 2, 4, 8, 16] Fails maxContains 未通过 maxContains 的验证 X

Length | 长度

The length of the array can be specified using the minItems and maxItems keywords. The value of each keyword must be a non-negative number. These keywords work whether doing list validation or Tuple validation.

可以使用关键词 minItems 和 maxItems 指定数组的长度。每个关键词的值必须是非负数。无论是执行列表验证还是元组验证,这些关键词都有效。

JSON Schema:

{
  "type": "array",
  "minItems": 2,
  "maxItems": 3
}
JSON 注释 验证结果
[] X
[1] X
[1, 2] V
[1, 2, 3] V
[1, 2, 3, 4] X

Uniqueness | 唯一性

A schema can ensure that each of the items in an array is unique. Simply set the uniqueItems keyword to true.

通过将关键词 uniqueItems 设置为 true,可确保数组元素的唯一性。

JSON Schema:

{
  "type": "array",
  "uniqueItems": true
}
JSON 注释 验证结果
[1, 2, 3, 4, 5] V
[1, 2, 3, 3, 4] X
[] The empty array always passes 允许空数组 V

boolean | 布尔类型

The boolean type matches only two special values: true and false. Note that values that evaluate to true or false, such as 1 and 0, are not accepted by the schema.

  • In Python, "boolean" is analogous to bool. Note that in JSON, true and false are lower case, whereas in Python they are capitalized (True and False).
  • In Ruby, "boolean" is analogous to TrueClass and FalseClass. Note that in Ruby there is no Boolean class.

布尔类型仅匹配两个特殊值:true 和 false。请注意,shcema 不接受计算结果为 true 或 false 的值(如 1 和 0)。

JSON Schema:

{ "type": "boolean" }
JSON 注释 验证结果
true V
false V
"true" X
0 Values that evaluate to true or false are still not accepted by the schema 不接受计算结果为 true 或 false 的值 X

null

When a schema specifies a type of null, it has only one acceptable value: null.

  • In Python, null is analogous to None.
  • In Ruby, null is analogous to nil.

当一个 schema 指定一个空类型时,它只有唯一一个可接受的值:null 。

JSON Schema:

{ "type": "null" }
JSON 注释 验证结果
null V
false X
0 X
"" X
X

Generic keywords | 通用关键词

This chapter lists some miscellaneous properties that are available for all JSON types.

本章列出了一些适用于所有 JSON 类型的杂项属性。

Annotations | 附注

JSON Schema includes a few keywords, that aren't strictly used for validation, but are used to describe parts of a schema. None of these “annotation” keywords are required, but they are encouraged for good practice, and can make your schema “self-documenting”.

The title and description keywords must be strings. A “title” will preferably be short, whereas a “description” will provide a more lengthy explanation about the purpose of the data described by the schema.

The default keyword specifies a default value. This value is not used to fill in missing values during the validation process. Non-validation tools such as documentation generators or form generators may use this value to give hints to users about how to use a value. However, default is typically used to express that if a value is missing, then the value is semantically the same as if the value was present with the default value. The value of default should validate against the schema in which it resides, but that isn't required.

JSON Schema 里有几个关键词,严格说来它们并不用于验证,仅用于描述 shcema 的各个部分。虽然这些“注释”性关键词都不是必需的,但鼓励使用,因为它们能使您的 shcema 变得有“自知之明”。

关键词 title 和 description,都以字符串为值。"title" 的值越简短越好,而 "description" 则用于为 schema 中定义的数据提供更详尽的解释。

关键词 "default" 用于指定默认值。此值不是用于在验证过程中填充缺失值的。非验证工具(如文档生成器或表单生成器)可以使用此值向用户提供有关如何赋值的提示。但是, "default" 通常用于表示,如果缺少了某个值,则该值在语义上应与 "default" 里的值相同。 "default" 的值是会被它所在的 schema 验证的,但它本身不是必需的。

New in draft 6 The examples keyword is a place to provide an array of examples that validate against the schema. This isn't used for validation, but may help with explaining the effect and purpose of the schema to a reader. Each entry should validate against the schema in which it resides, but that isn't strictly required. There is no need to duplicate the default value in the examples array, since default will be treated as another example.

New in draft 7 The boolean keywords readOnly and writeOnly are typically used in an API context. readOnly indicates that a value should not be modified. It could be used to indicate that a PUT request that changes a value would result in a 400 Bad Request response. writeOnly indicates that a value may be set, but will remain hidden. In could be used to indicate you can set a value with a PUT request, but it would not be included when retrieving that record with a GET request.

New in draft 2019-09 The deprecated keyword is a boolean that indicates that the instance value the keyword applies to should not be used and may be removed in the future.

草案 6 中的新增内容 关键词 examples 里可存放一组展示 schema 如何应用的示例数据。其本身不用于验证,但可能有助于向读者解释 schema 的效果和用途。虽说示例组中每个示例都理应通过其所在的 schema 的验证,但这却不是严格要求的。无需在示例数组中复制默认值,因为默认值将被视为另一个示例。

草案 7 中的新增内容 布尔类型的关键词 readOnly 和 writeOnly 通常用于描述 API 。readOnly 表示值不可修改。它可导致一个用于更改某个值的 PUT 请求,返回 400 错误响应。writeOnly 则表示值可改,但其修改后的值是不可读的。它允许您使用一个 PUT 请求设置某个值,但却不允许使用 GET 请求检索该值。

草案 2019-09 中的新增内容 布尔型关键词 deprecated 用于表示一个应被停止使用、将来可能会将被删除的内容。

JSON Schema:

{
  "title": "Match anything",
  "description": "This is a schema that matches anything.",
  "default": "Default value",
  "examples": [
    "Anything",
    4035
  ],
  "deprecated": true,
  "readOnly": true,
  "writeOnly": false
}

Comments | 注释

New in draft 7 $comment

The $comment keyword is strictly intended for adding comments to a schema. Its value must always be a string. Unlike the annotations title, description, and examples, JSON schema implementations aren't allowed to attach any meaning or behavior to it whatsoever, and may even strip them at any time. Therefore, they are useful for leaving notes to future editors of a JSON schema, but should not be used to communicate to users of the schema.

草案 7 中的新增内容$comment

关键词 $comment 用于向 schema 添加注释。其值必须始终为字符串。与 title ,description,examples 不同,JSON Schema 不会为其附加任何含义或行为,甚至可能随时被剥离。因此,它们对于向 JSON Schema 的未来编辑者留下注释很有用,但不应用于与 schema 的用户进行交流。

Enumerated values | 枚举值

The enum keyword is used to restrict a value to a fixed set of values. It must be an array with at least one element, where each element is unique.

The following is an example for validating street light colors:

关键词 enum 用于将值限制为一个固定的集合。它必须是至少包含一个元素的数组,其中每个元素都是唯一的。

以下是验证路灯颜色的示例:

JSON Schema:

{
  "enum": ["red", "amber", "green"]
}
JSON 注释 验证结果
"red" V
"blue" X

You can use enum even without a type, to accept values of different types. Let's extend the example to use null to indicate “off”, and also add 42, just for fun.

您也可以使用 enum 来接受不同类型的值。让我们扩展上述示例,使用 null 来表示“关闭”,并添加 42 ,只是为了好玩。

JSON Schema:

{
  "enum": ["red", "amber", "green", null, 42]
}
JSON 注释 验证结果
"red" V
null V
42 V
0 X

Constant values | 常量值

New in draft 6

The const keyword is used to restrict a value to a single value.

For example, if you only support shipping to the United States for export reasons:

草案 6 中的新增内容

关键词 const 用于将一个值限制为单个值。

例如,如果您仅支持出口到美国的货运:

JSON Schema:

{
  "properties": {
    "country": {
      "const": "United States of America"
    }
  }
}
JSON 注释 验证结果
{ "country": "United States of America" } V
{ "country": "Canada" } X

Media: string-encoding non-JSON data | 媒体:用字符串编码的非 JSON 数据

New in draft 7

JSON schema has a set of keywords to describe and optionally validate non-JSON data stored inside JSON strings. Since it would be difficult to write validators for many media types, JSON schema validators are not required to validate the contents of JSON strings based on these keywords. However, these keywords are still useful for an application that consumes validated JSON.

草案 7 中的新增内容

JSON Schema 有一组关键词,是用于描述和选择性地验证那些存储在 JSON 字符串中的 non-JSON 数据的。由于为众多媒体类型编写验证器是一件比较复杂的事情,市面上的 JSON Schema 验证器们并没有被要求去深入验证那些基于这些关键词的 JSON 字符串的内容。不过,这些关键词对于那些要求使用可验证的 JSON 数据的应用程序,还是很有意义的。

contentMediaType | 内容媒体类型

The contentMediaType keyword specifies the MIME type of the contents of a string, as described in RFC 2046. There is a list of MIME types officially registered by the IANA, but the set of types supported will be application and operating system dependent. Mozilla Developer Network also maintains a shorter list of MIME types that are important for the web

关键词 contentMediaType 就是用于表示类似 RFC 2046 中定义的、可藏身于字符串中的 MIME 类型的。IANA 维护着一个较为正式的 MIME 类型大全,具体的应用程序和操作系统都选择支持其中的一部分。Mozilla 开发者网络维护着一个侧重于web技术的规模相对小一些的 MIME 类型列表

contentEncoding | 内容编码

The contentEncoding keyword specifies the encoding used to store the contents, as specified in RFC 2054, part 6.1 and RFC 4648.

The acceptable values are 7bit, 8bit, binary, quoted-printable, base16, base32, and base64. If not specified, the encoding is the same as the containing JSON document.

Without getting into the low-level details of each of these encodings, there are really only two options useful for modern usage:

  • If the content is encoded in the same encoding as the enclosing JSON document (which for practical purposes, is almost always UTF-8), leave contentEncoding unspecified, and include the content in a string as-is. This includes text-based content types, such as text/html or application/xml.
  • If the content is binary data, set contentEncoding to base64 and encode the contents using Base64. This would include many image types, such as image/png or audio types, such as audio/mpeg.

关键词 contentEncoding 用于指定内容的存储编码格式,详情请参考 RFC 2054 的 6.1 节以及 RFC 4648

可接受的编码格式有 7bit、8bit、binary、quoted-printable、base16、base32、base64等。如果未做明确指定,则其编码格式与所在的 JSON 文档相同。

很少有人能掌握上述编码格式的全部底层细节,不过没关系,具体应用中常见的实际上只有如下两种情况:

contentSchema | 内容模式

New in draft 2019-09

Documentation Coming soon

草案 2019-09 中的新增内容

即将推出,敬请期待。

Examples | 示例

The following schema indicates the string contains an HTML document, encoded using the same encoding as the surrounding document:

如下,一个包含 HTML 文档的字符串 schema,使用了与其所在文档相同的编码格式:

JSON Schema:

{
  "type": "string",
  "contentMediaType": "text/html"
}
JSON 注释 验证结果
"<!DOCTYPE html><html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head></html>" V

The following schema indicates that a string contains a PNG image, encoded using Base64:

如下,一个包含使用 Base64 的 PNG 图像的字符串 schema:

JSON Schema:

{
  "type": "string",
  "contentEncoding": "base64",
  "contentMediaType": "image/png"
}

JSONV):

"iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA..."

Schema Composition | Schema 组合

JSON Schema includes a few keywords for combining schemas together. Note that this doesn't necessarily mean combining schemas from multiple files or JSON trees, though these facilities help to enable that and are described in Structuring a complex schema. Combining schemas may be as simple as allowing a value to be validated against multiple criteria at the same time.

These keywords correspond to well known boolean algebra concepts like AND, OR, XOR, and NOT. You can often use these keywords to express complex constraints that can't otherwise be expressed with standard JSON Schema keywords.

The keywords used to combine schemas are:

  • allOf: (AND) Must be valid against all of the subschemas
  • anyOf: (OR) Must be valid against any of the subschemas
  • oneOf: (XOR) Must be valid against exactly one of the subschemas

All of these keywords must be set to an array, where each item is a schema.

In addition, there is:

  • not: (NOT) Must not be valid against the given schema

JSON Schema 包含一些用于将 schema 组合在一起的关键词。请注意,这并不一定意味着合并来自多个文件或多个 JSON 树的 schema ,尽管它们有能力帮助实现这一点,详情请参考 Structuring a complex schema 一节。Combining schema 可能更像是简单地允许多个验证同时作用于同一个值。

这些关键词对应于众所周知的布尔代数概念,如 AND、OR、XOR 和 NOT 。您通常可以使用这些关键词来表示无法使用标准 JSON Schema 关键词表示的复杂约束。

用于 schema 组合的关键词:

所有这些关键词的值都必须是一个数组,一个以 schema 为元素的数组。

此外,还有:

allOf

To validate against allOf, the given data must be valid against all of the given subschemas.

若要通过 allOf 的验证,要求待验证的 JSON 数据必须经得起给定的 schema 数组中的每一个 schema 的独立验证。

JSON Schema:

{
  "allOf": [
    { "type": "string" },
    { "maxLength": 5 }
  ]
}
JSON 注释 验证结果
"short" V
"too long" X

Note

allOf can not be used to “extend” a schema to add more details to it in the sense of object-oriented inheritance. Instances must independently be valid against “all of” the schemas in the allOf. See the section on Extending Closed Schemas for more information.

注意

关键词 allOf 不是类似面向对象的继承机制那样,用于“扩展”一个 schema 的。被验证的实例必须独立地对 allOf 中的“所有”schemas 有效。详情请参阅 Extending Closed Schemas 一节。

anyOf

To validate against anyOf, the given data must be valid against any (one or more) of the given subschemas.

若要通过 anyOf 的验证,给定数据必须对至少一个给定的子 schema 有效。

JSON Schema:

{
  "anyOf": [
    { "type": "string", "maxLength": 5 },
    { "type": "number", "minimum": 0 }
  ]
}
JSON 注释 验证结果
"short" V
"too long" X
12 V
-5 X

oneOf

To validate against oneOf, the given data must be valid against exactly one of the given subschemas.

若要通过 oneOf 的验证,给定的数据必须仅对给定的子 schema 之一有效。

JSON Schema:

{
  "oneOf": [
    { "type": "number", "multipleOf": 5 },
    { "type": "number", "multipleOf": 3 }
  ]
}
JSON 注释 验证结果
10 V
9 V
2 Not a multiple of either 5 or 3 既不是5的倍数也不是3的倍数 X
15 Multiple of both 5 and 3 is rejected 同为5和3的倍数,拒绝 X

not

The not keyword declares that an instance validates if it doesn't validate against the given subschema.

For example, the following schema validates against anything that is not a string:

关键词 not 用于声明一个验证,其通过的条件为用于验证的实例对给定的子 schema 的验证为通不过。

例如,以下 schema 允许非字符串的任何内容:

JSON Schema:

{ "not": { "type": "string" } }
JSON 注释 验证结果
42 V
{ "key": "value" } V
"I am a string" X

Properties of Schema Composition | Schema 组合的属性

Illogical Schemas | 不合逻辑的 Schemas

Note that it's quite easy to create schemas that are logical impossibilities with these keywords. The following example creates a schema that won't validate against anything (since something may not be both a string and a number at the same time):

请注意,使用这些关键词可以轻易创建出逻辑矛盾的 schema 。如下所示,创建了一个无法验证任何内容的 schema(因为任何内容不可能即是字符串又是数字):

JSON Schema:

{
  "allOf": [
    { "type": "string" },
    { "type": "number" }
  ]
}
JSON 注释 验证结果
"No way" X
-1 X
Factoring Schemas | Schema 的因式分解

Note that it's possible to “factor” out the common parts of the subschemas. The following two schemas are equivalent.

请注意,可以“分解”子 schema 的公共部分。如下两个 schema 是等效的。

JSON Schema:

{
  "oneOf": [
    { "type": "number", "multipleOf": 5 },
    { "type": "number", "multipleOf": 3 }
  ]
}

{
   "type": "number",
   "oneOf": [
     { "multipleOf": 5 },
     { "multipleOf": 3 }
   ]
 }

Applying Subschemas Conditionally | 有条件地应用子 schema

dependentRequired | 必要依赖

The dependentRequired keyword conditionally requires that certain properties must be present if a given property is present in an object. For example, suppose we have a schema representing a customer. If you have their credit card number, you also want to ensure you have a billing address. If you don't have their credit card number, a billing address would not be required. We represent this dependency of one property on another using the dependentRequired keyword. The value of the dependentRequired keyword is an object. Each entry in the object maps from the name of a property, p, to an array of strings listing properties that are required if p is present.

In the following example, whenever a credit_card property is provided, a billing_address property must also be present:

关键词 dependentRequired 表示一种有条件的要求,即如果对象中出现了某给定属性,则必须同时存在某些特定属性。例如,假设我们有一个表示客户的 schema 。当您有他们的信用卡号时,您就还需要确保有其账单地址。如果您没有他们的信用卡号,则帐单地址也没必要有。我们使用 dependentRequired 表示一个属性对另一个属性的依赖关系。dependentRequired 关键词的值是一个对象。对象中的每个条目都是从某属性名称 p 映射到当 p 存在时必需同时出现的一个属性列表的字符串数组。

如下所示,每当出现 credit_card 属性的地方,要求必须同时存在 billing_address 属性:

JSON Schema:

{
  "type": "object",

  "properties": {
    "name": { "type": "string" },
    "credit_card": { "type": "number" },
    "billing_address": { "type": "string" }
  },

  "required": ["name"],

  "dependentRequired": {
    "credit_card": ["billing_address"]
  }
}

JSONV

{
  "name": "John Doe",
  "credit_card": 5555555555555555,
  "billing_address": "555 Debtor's Lane"
}

JSONX

This instance has a credit_card, but it's missing a billing_address.

此实例具有 credit_card ,但缺少 billing_address 。

{
  "name": "John Doe",
  "credit_card": 5555555555555555
}

JSONV

This is okay, since we have neither a credit_card, or a billing_address.

这样也行,因为我们既没有 credit_card ,也没有 billing_address 。

{
  "name": "John Doe"
}

JSONV

Note that dependencies are not bidirectional. It's okay to have a billing address without a credit card number.

请注意,依赖关系不是双向的。出现一个无信用卡号的帐单地址是允许的。

{
  "name": "John Doe",
  "billing_address": "555 Debtor's Lane"
}

To fix the last issue above (that dependencies are not bidirectional), you can, of course, define the bidirectional dependencies explicitly:

要解决上面的最后一个问题(依赖不是双向的),您当然可以显式定义双向依赖:

JSON Schema:

{
  "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"]
  }
}

JSONX

This instance has a credit_card, but it's missing a billing_address.

此实例具有一个 credit_card ,但缺少 billing_address 。

{
  "name": "John Doe",
  "credit_card": 5555555555555555
}

JSONX

This has a billing_address, but is missing a credit_card.

有一个 billing_address ,但缺少 credit_card 。

{
  "name": "John Doe",
  "billing_address": "555 Debtor's Lane"
}

Draft 4-7

Previously to Draft 2019-09, dependentRequired and dependentSchemas were one keyword called dependencies. If the dependency value was an array, it would behave like dependentRequired and if the dependency value was a schema, it would behave like dependentSchemas.

草案 4-7

在草案 2019-09 之前,dependentRequired 和 dependentSchemas 的功能由同一个关键词承担,即 dependencies 。如果依赖项值是一个数组,其行为类似于 dependentRequired;如果依赖项值是一个 schema ,其行为类似于 dependentSchemas 。

dependentSchemas | schema 依赖

The dependentSchemas keyword conditionally applies a subschema when a given property is present. This schema is applied in the same way allOf applies schemas. Nothing is merged or extended. Both schemas apply independently.

For example, here is another way to write the above:

关键词 dependenciesSchemas 要求当给定的属性存在时,有条件地应用子 schema 。此 schema 的应用方式与 allOf 对 schema 的应用方式相同。不会合并或扩展任何内容。两种 schema 独自发挥各自的作用。

如下,这是编写上述示例的另一种方法:

JSON Schema:

{
  "type": "object",

  "properties": {
    "name": { "type": "string" },
    "credit_card": { "type": "number" }
  },

  "required": ["name"],

  "dependentSchemas": {
    "credit_card": {
      "properties": {
        "billing_address": { "type": "string" }
      },
      "required": ["billing_address"]
    }
  }
}

JSONV

{
  "name": "John Doe",
  "credit_card": 5555555555555555,
  "billing_address": "555 Debtor's Lane"
}

JSONX

This instance has a credit_card, but it's missing a billing_address:

此实例有一个 credit_card ,但缺少 billing_address 。

{
  "name": "John Doe",
  "credit_card": 5555555555555555
}

JSONV

This has a billing_address, but is missing a credit_card. This passes, because here billing_address just looks like an additional property:

这里有一个 billing_address ,缺少一个 credit_card 。但这能通过验证,因为这里的 billing_address 看起来像一个附加属性:

{
  "name": "John Doe",
  "billing_address": "555 Debtor's Lane"
}

Draft 4-7

Previously to Draft 2019-09, dependentRequired and dependentSchemas were one keyword called dependencies. If the dependency value was an array, it would behave like dependentRequired and if the dependency value was a schema, it would behave like dependentSchemas.

草案 4-7

在草案 2019-09 之前,dependentRequired 和 dependentSchemas 的功能由同一个关键词承担,即 dependencies 。如果依赖项值是一个数组,其行为类似于 dependentRequired;如果依赖项值是一个 schema ,其行为类似于 dependentSchemas 。

If-Then-Else

New in draft 7 The if, then and else keywords allow the application of a subschema based on the outcome of another schema, much like the if/then/else constructs you've probably seen in traditional programming languages.

If if is valid, then must also be valid (and else is ignored.) If if is invalid, else must also be valid (and then is ignored).

If then or else is not defined, if behaves as if they have a value of true.

If then and/or else appear in a schema without if, then and else are ignored.

We can put this in the form of a truth table, showing the combinations of when if, then, and else are valid and the resulting validity of the entire schema:

草案 7 中的新增功能 关键词 if、then 和 else 允许基于另一个 schema 的结果应用某个子 schema ,就像您在传统编程语言中看到的 if/then/else 一样。

如果 if 有效,则 then 也必须有效( else 将被忽略)。如果 if 无效,则 else 必须有效( then 被忽略)。

如果 then 或 else 未定义,则 if 的行为就像它们已经被定义且值为 true 一样。

如果 then 与/或 else 出现在一个没有 if 的 schema 中,then 和 else 都会被忽略。

我们可以将其以真值表的形式,显示 if 、then 和 else 在其组合中各自何时会参与到有效性验证中以及整个 shcema 最终的有效性结果:

if then else whole schema
T T n/a T
T F n/a F
F n/a T T
F n/a F F
n/a n/a n/a T

For example, let's say you wanted to write a schema to handle addresses in the United States and Canada. These countries have different postal code formats, and we want to select which format to validate against based on the country. If the address is in the United States, the postal_code field is a “zipcode”: five numeric digits followed by an optional four digit suffix. If the address is in Canada, the postal_code field is a six digit alphanumeric string where letters and numbers alternate.

例如,假设您要编写一个 schema 来处理美国和加拿大的地址。这两个国家具有不同的邮政编码格式,因此我们希望根据国家选择要验证的格式。如果地址在美国,则 postal_code 字段是一个“zipcode”,即:五位数字后跟一个可选的四位数字后缀。如果地址在加拿大,则 postal_code 字段是一个六位字母数字字符串,其中字母和数字交替出现。

JSON Schema:

{
  "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]" } }
  }
}

JSONV

{
  "street_address": "1600 Pennsylvania Avenue NW",
  "country": "United States of America",
  "postal_code": "20500"
}

JSONV

{
  "street_address": "1600 Pennsylvania Avenue NW",
  "postal_code": "20500"
}

JSONV

{
  "street_address": "24 Sussex Drive",
  "country": "Canada",
  "postal_code": "K1M 1M4"
}

JSONX

{
  "street_address": "24 Sussex Drive",
  "country": "Canada",
  "postal_code": "10000"
}

JSONX

{
  "street_address": "1600 Pennsylvania Avenue NW",
  "postal_code": "K1M 1M4"
}

Note

In this example, “country” is not a required property. Because the “if” schema also doesn't require the “country” property, it will pass and the “then” schema will apply. Therefore, if the “country” property is not defined, the default behavior is to validate “postal_code” as a USA postal code. The “default” keyword doesn't have an effect, but is nice to include for readers of the schema to more easily recognize the default behavior.

注意

在此示例中,“country”不是必需属性。由于“if”指向的 schema 里也没明确表示“country”属性为必须属性,(当实际用于被验证的某 JSON 数据里缺失 country 时)它(即,if 指向的 schema )将被忽略,而“then”指向的 schema 将得到应用。另外,当“country”属性缺失时,默认会将“postal_code”验证为美国邮政编码。虽然这并非关键词“default”的作用,但为了阅读友好性,最好还是将其包含在(定义 country 属性的) schema 中,以便读者能更轻松地理解其默认行为。

Unfortunately, this approach above doesn't scale to more than two countries. You can, however, wrap pairs of if and then inside an allOf to create something that would scale. In this example, we'll use United States and Canadian postal codes, but also add Netherlands postal codes, which are 4 digits followed by two letters. It's left as an exercise to the reader to expand this to the remaining postal codes of the world.

不幸的是,上述方法不能扩展到两个以上的国家。不过,您可以将 if 和 then 一起包裹在 allOf 中,以创建可扩展的内容。如下所示,我们在继续使用美国和加拿大的邮政编码的基础上,添加荷兰的邮政编码,即 4 位数字后跟两个字母。作为一个练习,读者可以尝试将此示例扩展至能验证其他地方的邮政编码。

JSON Schema:

{
  "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}" } }
      }
    }
  ]
}

JSONV

{
  "street_address": "1600 Pennsylvania Avenue NW",
  "country": "United States of America",
  "postal_code": "20500"
}

JSONV

{
  "street_address": "1600 Pennsylvania Avenue NW",
  "postal_code": "20500"
}

JSONV

{
  "street_address": "24 Sussex Drive",
  "country": "Canada",
  "postal_code": "K1M 1M4"
}

JSONV

{
  "street_address": "Adriaan Goekooplaan",
  "country": "Netherlands",
  "postal_code": "2517 JX"
}

JSONX

{
  "street_address": "24 Sussex Drive",
  "country": "Canada",
  "postal_code": "10000"
}

JSONX

{
  "street_address": "1600 Pennsylvania Avenue NW",
  "postal_code": "K1M 1M4"
}

Note

The “required” keyword is necessary in the “if” schemas or they would all apply if the “country” is not defined. Leaving “required” off of the “United States of America” “if” schema makes it effectively the default if no “country” is defined.

Note

Even if “country” was a required field, it's still recommended to have the “required” keyword in each “if” schema. The validation result will be the same because “required” will fail, but not including it will add noise to error results because it will validate the “postal_code” against all three of the “then” schemas leading to irrelevant errors.

注意

“if”中的关键词“required”是必要的,否则(当待验证的数据里)未定义“country”时,所有 if 里的 schema 将同时参与验证。但“required”并不需要出现在“country”的值为“United States of America”的那个“if”中,因为此处提供了 country 属性未定时的默认验证。

注意

即使这个“country”属性已经是一个 required(必填的)字段了,仍然建议您在后面的每个“if”中使用“required”关键词。虽然验证结果一样,因为“country”自己的“required”会直接给出失败提示(指当某待验证的数据中缺失 country 属性时),但若 if 中缺少( required ),会向最终的错误信息里“注水”,具体来说,(当某待验证的数据中缺少 country 属性时)它任然会继续验证三个“then”里的“postal_code”,从而输出原本莫须有的错误提示。

Implication | 蕴含

Before Draft 7, you can express an “if-then” conditional using the Schema Composition keywords and a boolean algebra concept called “implication”. A -> B (pronounced, A implies B) means that if A is true, then B must also be true. It can be expressed as !A || B which can be expressed as a JSON Schema.

在草案 7 之前,您可以使用组合关键词和称为“implication”的布尔运算概念来表达类似“if-then”的能力。A -> B(发音,A 蕴含 B)意味着如果 A 为真,则 B 也必须为真。也就是说,JSON Schema 还可以是表示为类似 !A || B 的东西。

JSON Schema:

{
  "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"] }
  ]
}

JSONV

{
  "restaurantType": "sit-down",
  "total": 16.99,
  "tip": 3.4
}

JSONX

{
  "restaurantType": "sit-down",
  "total": 16.99
}

JSONV

{
  "restaurantType": "fast-food",
  "total": 6.99
}

JSONV

{ "total": 5.25 }

Variations of implication can be used to express the same things you can express with the if/then/else keywords. if/then can be expressed as A -> B, if/else can be expressed as !A -> B, and if/then/else can be expressed as A -> B AND !A -> C.

Note

Since this pattern is not very intuitive, it's recommended to put your conditionals in $defs with a descriptive name and $ref it into your schema with "allOf": [{ "$ref": "#/$defs/sit-down-restaurant-implies-tip-is-required" }].

蕴含的变体用于表达您用关键词 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 中。

Declaring a Dialect | 声明方言

A version of JSON Schema is called a dialect. A dialect represents the set of keywords and semantics that can be used to evaluate a schema. Each JSON Schema release is a new dialect of JSON Schema. JSON Schema provides a way for you to declare which dialect a schema conforms to and provides ways to describe your own custom dialects.

JSON Schema 把版本称为方言。一个方言即是用于评估 schema 的一组关键词及其语义。JSON Schema 为您提供了一种为 schema 申明具体依赖哪种方言的方法,并提供了描述您自己的自定义方言的方法。

$schema

The $schema keyword is used to declare which dialect of JSON Schema the schema was written for. The value of the $schema keyword is also the identifier for a schema that can be used to verify that the schema is valid according to the dialect $schema identifies. A schema that describes another schema is called a “meta-schema”.

关键词 $schema 即是用于为您的 schema 申明具体采用的是哪个版本的方言的。$schema 的值指向的也是一个 schema ,可用于对当前 schema 执行验证。这种用于定义另一个 schema 的 shcema 称为“ meta-schema(元-schema )”。

$schema applies to the entire document and must be at the root level. It does not apply to externally referenced ($ref, $dynamicRef) documents. Those schemas need to declare their own $schema.

$schema 位于根节点,作用于整个文档。它不同于外部引用(承担外部引用的关键词是 $ref 、$dynamicRef )。(一个明显的区别是,)那些(被外部引用的) schema 文档里也是有 $schema 关键词的。

If $schema is not used, an implementation might allow you to specify a value externally or it might make assumptions about which specification version should be used to evaluate the schema. It's recommended that all JSON Schemas have a $schema keyword to communicate to readers and tooling which specification version is intended. Therefore most of the time, you'll want this at the root of your schema:

若不用 $schema ,到具体的验证实现环节时,一个验证工具可能允许您额外临时指定一个(方言版本)值,或者按其自定规则应用某个默认版本。建议所有 JSON Schema 里都有 $schema 关键词,用于向读者和工具传达其预期的方言版本。因此,大多数时候,您都需要将其作为您的 schema 文档的根目录:

JSON Schema:

"$schema": "https://json-schema.org/draft/2020-12/schema"

Draft 4

The identifier for Draft 4 is http://json-schema.org/draft-04/schema#.

Draft 4 defined a value for $schema without a specific dialect (http://json-schema.org/schema#) which meant, use the latest dialect. This has since been deprecated and should no longer be used.

You might come across references to Draft 5. There is no Draft 5 release of JSON Schema. Draft 5 refers to a no-change revision of the Draft 4 release. It does not add, remove, or change any functionality. It only updates references, makes clarifications, and fixes bugs. Draft 5 describes the Draft 4 release. If you came here looking for information about Draft 5, you'll find it under Draft 4. We no longer use the "draft" terminology to refer to patch releases to avoid this confusion.

草案 4

草案 4 的标识符为 http://json-schema.org/draft-04/schema#

草案 4 时代的 $schema 还有一个没有特定版本的方言标识符( http://json-schema.org/schema# ),其本意为始终使用最新版。这已被放弃,不应再使用。

您可能还遇到过对草案 5 的引用。但 JSON Schema 其实没有针对草案 5 的方言版本。草案 5 对草案 4 无更改。没添加、删除或更改任何功能。它仅更新引用,进行澄清并修复错误。草案 5 复制了草案 4 。如果您想在这里找到有关草案 5 的信息,您会在草案 4 下找到它。为了避免这种混淆,我们以后将不再在标识符里使用术语“draft”来指代补丁版本。

Draft 6

The identifier for Draft 6 is http://json-schema.org/draft-06/schema#.

草案 6

草案 6 的标识符为 http://json-schema.org/draft-06/schema#

Draft 7

The identifier for Draft 7 is http://json-schema.org/draft-07/schema#.

草案 7

草案 7 的标识符为 http://json-schema.org/draft-07/schema#

Draft 2019-09

The identifier for Draft 2019-09 is https://json-schema.org/draft/2019-09/schema.

草案 2019-09

草案 2019-09 的标识符为 https://json-schema.org/draft/2019-09/schema

Vocabularies | 词汇

New in draft 2019-09

Documentation Coming Soon

Draft 4-7

Before the introduction of Vocabularies, you could still extend JSON Schema with your custom keywords but the process was much less formalized. The first thing you'll need is a meta-schema that includes your custom keywords. The best way to do this is to make a copy of the meta-schema for the version you want to extend and make your changes to your copy. You will need to choose a custom URI to identify your custom version. This URI must not be one of the URIs used to identify official JSON Schema specification drafts and should probably include a domain name you own. You can use this URI with the $schema keyword to declare that your schemas use your custom version.

草案 2019-09 中的新内容

敬请期待

草案 4-7

在引入词汇表之前,您仍然可以使用自定义关键词来扩展您的 JSON Schema ,但该做法极不正式。首先,您需要一个包含自定义关键词的 meta-schema 。执行此操作的最佳方法是为要扩展的 meta-schema 创建一个副本,在副本的基础上进行更改。您还需要选择一个自定义的 URI 来标识您的自定义版本。此 URI 不得与任一官方方言的 URI 相重复,最好用包含您自有域名的 URI。您就可以将此 URI 与 $schema 一起使用,以声明使用自定义版本的 schema 了。

Note

Not all implementations support custom meta-schemas and custom keyword implementations.

注意

并非所有实现(指市面上现有的验证器)都支持自定义 meta-schemas 和自定义关键词。

Guidelines | 指南

One of the strengths of JSON Schema is that it can be written in JSON and used in a variety of environments. For example, it can be used for both front-end and back-end HTML Form validation. The problem with using custom vocabularies is that every environment where you want to use your schemas needs to understand how to evaluate your vocabulary's keywords. Meta-schemas can be used to ensure that schemas are written correctly, but each implementation will need custom code to understand how to evaluate the vocabulary's keywords.

Meta-data keywords are the most interoperable because they don't affect validation. For example, you could add a units keyword. This will always work as expecting with an compliant validator.

JSON Schema 的优势之一是它用 JSON 编写并能在各种环境中使用。例如,它可同时用于前、后端 的 HTML 表单验证。使用自定义词汇表的问题仅在于,让您想要使用 schema 的每个环境理解您的词汇表中的每个关键词。Meta-schemas 能用于确保 schema 编写正确,仅需在每个实现添加自定义代码来理解那些关键词而已。

元数据关键词是(环境)友好的,因为它们不会破坏(别的)验证。例如,您可以添加一个叫 units 的关键词。其将始终与任何合规的验证器一起按预期工作。

JSON Schema:

{
  "type": "number",
  "units": "kg"
}
JSON 注释 验证结果
42 V
"42" X

The next best candidates for custom keywords are keywords that don't apply other schemas and don't modify the behavior of existing keywords. An isEven keyword is an example. In contexts where some validation is better than no validation such as validating an HTML Form in the browser, this schema will perform as well as can be expected. Full validation would still be required and should use a validator that understands the custom keyword.

关于自定义关键词的另一个最佳实践是不要用别的 schema 重新定义或试图修改其他现有关键词部分的行为。以如下一个名为 isEven 的关键词为例。在通过验证以改善上下文(例如在浏览器中验证一个 HTML 表单)的应用中,此 schema 是能够按预期执行的。毕竟,让包括自定义关键词在内的所有关键词都被理解和参与验证,是每个验证器应该努力具备的能力。

JSON Schema:

{
  "type": "integer",
  "isEven": true
}
JSON 注释 验证结果
2 V
3 This passes because the validator doesn't understand isEven 因为不理解 isEven 是什么意思,所有不影响验证通过 V
"3" The schema isn't completely impaired because it doesn't understand isEven 因为不理解 isEven 是什么意思,所有不影响验证不通过 X

The least interoperable type of custom keyword is one that applies other schemas or modifies the behavior of existing keywords. An example would be something like requiredProperties that declares properties and makes them required. This example shows how the schema becomes almost completely useless when evaluated with a validator that doesn't understand the custom keyword. That doesn't necessarily mean that requiredProperties is a bad idea for a keyword, it's just not the right choice if the schema might need to be used in a context that doesn't understand custom keywords.

自定义关键词的最差做法,莫过于应用其他 shcema 重新定一个现有关键词或修改现有关键词的某些行为。拿关键词 requiredProperties 来举例,若把它的行为改成申明新的必要属性。如下所示,当使用不理解此自定义的验证程序时,shcema 变得几乎完全无用。这并不一定意味着这样的 requiredProperties 关键词是一个坏主意,只是说当不在如此理解该自定义关键词的上下文中使用,显然不是好主意。

JSON Schema:

{
  "type": "object",
  "requiredProperties": {
    "foo": { "type": "string" }
  }
}
JSON 注释 验证结果
{ "foo": "bar" } V
{} This passes because requiredProperties is not understood 因为不理解 requiredProperties 是什么意思,所有不影响验证通过 V
{ "foo": 42 } This passes because requiredProperties is not understood 因为不理解 requiredProperties 是什么意思,所有不影响验证通过 V

Structuring a complex schema | 构建复杂 schema

When writing computer programs of even moderate complexity, it's commonly accepted that “structuring” the program into reusable functions is better than copying-and-pasting duplicate bits of code everywhere they are used. Likewise in JSON Schema, for anything but the most trivial schema, it's really useful to structure the schema into parts that can be reused in a number of places. This chapter will present the tools available for reusing and structuring schemas as well as some practical examples that use those tools.

当需要编写稍微复杂一点的计算机程序时,人们已普遍接受的观点是,将程序“构建”为可重用的功能模块比到处复制粘贴重复的代码要好。在 JSON Schema 中,除非最琐碎的 schema ,构建可复用的 schema ,同样非常有用。本章将介绍可用于构建可复用 schema 的工具,以及使用这些工具的几个实例。

Schema Identification

Like any other code, schemas are easier to maintain if they can be broken down into logical units that reference each other as necessary. In order to reference a schema, we need a way to identify a schema. Schema documents are identified by non-relative URIs.

与任何其他代码一样,若将 schema 分解为根据需要相互引用的逻辑单元,会更易于维护。为了引用一个 schema ,我们需要一种针对 schema 的标识法。如 用非相对 URI 标识的 schema 文档。

Schema documents are not required to have an identifier, but you will need one if you want to reference one schema from another. In this documentation, we will refer to schemas with no identifier as “anonymous schemas”.

schema 文档默认是不需要什么标识符的,但如果要在某个 schema 引用另一个,就需要一个标识符了。在本文中,我们将没有标识符的 schema 称为“匿名-schema ”。

In the following sections we will see how the “identifier” for a schema is determined.

接下来,让我们看看如何定义一个 schema 的“标识符”。

Note

URI terminology can sometimes be unintuitive. In this document, the following definitions are used.

  • URI [1] or non-relative URI: A full URI containing a scheme (https). It may contain a URI fragment (#foo). Sometimes this document will use “non-relative URI” to make it extra clear that relative URIs are not allowed.
  • relative reference [2]: A partial URI that does not contain a scheme (https). It may contain a fragment (#foo).
  • URI-reference [3]: A relative reference or non-relative URI. It may contain a URI fragment (#foo).
  • absolute URI [4] A full URI containing a scheme (https) but not a URI fragment (#foo).

注意

URI 术语有时可能不直观。本文将采用如下这些定义:

Note

Even though schemas are identified by URIs, those identifiers are not necessarily network-addressable. They are just identifiers. Generally, implementations don't make HTTP requests (https://) or read from the file system (file://) to fetch schemas. Instead, they provide a way to load schemas into an internal schema database. When a schema is referenced by it's URI identifier, the schema is retrieved from the internal schema database.

注意

虽然很多 schema 由 URI 标识,但这些标识符也不一定都是网络可寻址的。它们只是标识符而已。通常,验证器不会发出 HTTP 请求 (https://) 或从文件系统读取 (file://) 来获取 schema 。相应地,它们提供了一种将全部 schema 预先加载到内部 schema 库的方法。当通过 URI 标识符引用某个 schema 时,将从该内部 schema 库中检索该 schema 。

Base URI

Using non-relative URIs can be cumbersome, so any URIs used in JSON Schema can be URI-references that resolve against the schema's base URI resulting in a non-relative URI. This section describes how a schema's base URI is determined.

使用 非相对-URI 可能很麻烦,因此 JSON Schema 中使用的任何 URI 都可以是 URI 引用,这些 URI 根据 schema 的根 URI 进行解析,形成 非相对-URI。本节介绍如何定义 根-URI。

Note

Base URI determination and relative reference resolution is defined by RFC-3986. If you are familiar with how this works in HTML, this section should feel very familiar.

注意

关于 根-URI 的定义和相对引用解析,请参见 RFC-3986 。如果您熟悉这种在 HTML 中常见的工作,那么本节应该非常熟悉。

Retrieval URI

The URI used to fetch a schema is known as the “retrieval URI”. It's often possible to pass an anonymous schema to an implementation in which case that schema would have no retrieval URI.

Let's assume a schema is referenced using the URI https://example.com/schemas/address and the following schema is retrieved.

用于提取一个 schema 的 URI 称为“检索-URI”。通常也可能将一个 匿名-schema 传给验证器,在这种情况下,该 schema 将不会有 检索-URI。

假设使用 URI https://example.com/schemas/address 来引用并检索某个 schema ,如下所示:

JSON Schema:

{
  "type": "object",
  "properties": {
    "street_address": { "type": "string" },
    "city": { "type": "string" },
    "state": { "type": "string" }
  },
  "required": ["street_address", "city", "state"]
}

The base URI for this schema is the same as the retrieval URI, https://example.com/schemas/address.

此 schema 的 根-URI 与 检索-URI 同为 https://example.com/schemas/address

$id

You can set the base URI by using the $id keyword at the root of the schema. The value of $id is a URI-reference without a fragment that resolves against the Retrieval URI. The resulting URI is the base URI for the schema.

可以在 schema 的根部使用关键词 $id 来设置 根-URI。$id 的值是一个不带片段的 URI 引用。其生成的 URI 即是该 schema 的 根-URI。

  • In Draft 4, $id is just id (without the dollar sign).
  • In Draft 4-7 it was allowed to have fragments in an $id (or id in Draft 4). However, the behavior when setting a base URI that contains a URI fragment is undefined and should not be used because implementations may treat them differently.

Note

This is analogous to the < base > tag in HTML.

注意

这类似于 HTML 中的< base > 标签

Note

When the $id keyword appears in a subschema, it means something slightly different. See the Bundling section for more.

注意

当关键词 $id 出现在子 schema 中时,它的含义略有不同。详细信息请参阅 Bundling 一节。

Let's assume the URIs https://example.com/schema/address and https://example.com/schema/billing-address both identify the following schema.

让我们假设 URI https://example.com/schema/addresshttps://example.com/schema/billing-address 两者都标识以下 schema 。

JSON Schema:

{
  "$id": "/schemas/address",

  "type": "object",
  "properties": {
    "street_address": { "type": "string" },
    "city": { "type": "string" },
    "state": { "type": "string" }
  },
  "required": ["street_address", "city", "state"]
}

No matter which of the two URIs is used to retrieve this schema, the base URI will be https://example.com/schemas/address, which is the result of the $id URI-reference resolving against the Retrieval URI.

无论使用两个 URI 中的哪一个来检索此 schema ,根-URI 都将是 https://example.com/schemas/address ,这是针对 检索-URI 解析 $id URI 引用的结果。这是关键词 $id 的作用。

However, using a relative reference when setting a base URI can be problematic. For example, we couldn't use this schema as an anonymous schema because there would be no Retrieval URI and you can't resolve a relative reference against nothing. For this and other reasons, it's recommended that you always use an absolute URI when declaring a base URI with $id.

但是,在设置 根-URI 时使用相对引用可能会出问题。例如,我们不能将此 schema 用作 匿名-schema ,因为没有 检索-UR I并且您无法解析相对引用。出于这个原因和其他原因,建议您在使用 $id 声明 根-URI 时尽量使用 绝对-URI 。

The base URI of the following schema will always be https://example.com/schemas/address no matter what the Retrieval URI was or if it's used as an anonymous schema.

以下 schema 的 根-URI 将始终是 https://example.com/schemas/address ,无论 检索-URI 是什么,或者它是否被用作 匿名-schema 。

JSON Schema:

{
  "$id": "https://example.com/schemas/address",

  "type": "object",
  "properties": {
    "street_address": { "type": "string" },
    "city": { "type": "string" },
    "state": { "type": "string" }
  },
  "required": ["street_address", "city", "state"]
}

JSON Pointer

In addition to identifying a schema document, you can also identify subschemas. The most common way to do that is to use a JSON Pointer in the URI fragment that points to the subschema.

除了标识 schema 文档,您还可以标识 子-schema 。最常见的方法是在指向 子-schema 的 URI 片段中使用 JSON-指针 。

A JSON Pointer describes a slash-separated path to traverse the keys in the objects in the document. Therefore, /properties/street_address means:

  1. find the value of the key properties
  2. within that object, find the value of the key street_address

JSON-指针 描述了一个以斜杠分隔的路径,用于遍历文档中的对象中的键。因此,/properties/street_address 表示:

  1. 查找名为 properties 的键对应的值(是一个对象)
  2. 在上述(值)对象中,查找名为 street_address 的键对应的值

The URI https://example.com/schemas/address#/properties/street_address identifies the highlighted subschema in the following schema.

URI https://example.com/schemas/address#/properties/street_address 标识以下 schema 中被高亮显示的 子-schema 。

JSON Schema:

{
  "$id": "https://example.com/schemas/address",

  "type": "object",
  "properties": {
    "street_address":
      { "type": "string" },
    "city": { "type": "string" },
    "state": { "type": "string" }
  },
  "required": ["street_address", "city", "state"]
}

译者注

原文中的 { "type": "string" }, 这一行有高亮标注。

$anchor

A less common way to identify a subschema is to create a named anchor in the schema using the $anchor keyword and using that name in the URI fragment. Anchors must start with a letter followed by any number of letters, digits, -, _, :, or ..

标识 子-schema 的一种不太常见的方法是使用关键词 $anchor 在 schema 中创建一个命名定位点(锚点),并在 URI 片段中使用该名称。锚点必须以字母开头,后面可跟任意数量的字母、数字、-(减号符) 、_(下划线) 、:(冒号) 或 .(点号) 。

  • In Draft 4, you declare an anchor the same way you do in Draft 6-7 except that $id is just id (without the dollar sign).
  • In Draft 6-7, a named anchor is defined using an $id that contains only a URI fragment. The value of the URI fragment is the name of the anchor.

    JSON Schema doesn't define how $id should be interpreted when it contains both fragment and non-fragment URI parts. Therefore, when setting a named anchor, you should not use non-fragment URI parts in the URI-reference.

Note

If a named anchor is defined that doesn't follow these naming rules, then behavior is undefined. Your anchors might work in some implementation, but not others.

注意

如果定义的命名定位点不遵循上述命名规则,则其行为将不可知。您的锚点在某些实现中可能起作用,换到别的实现中可能又不起作用。

The URI https://example.com/schemas/address#street_address identifies the subschema on the highlighted part of the following schema.

URI https://example.com/schemas/address#street_address 标识的是以下 schema 里被高亮显示的那部分 子-schema 。

JSON Schema:

{
  "$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"]
}

译者注

原文中的以下四行代码为其高亮显示部分:

      {
        "$anchor": "street_address",
        "type": "string"
      },

$ref

A schema can reference another schema using the $ref keyword. The value of $ref is a URI-reference that is resolved against the schema's Base URI. When evaluating a $ref, an implementation uses the resolved identifier to retrieve the referenced schema and applies that schema to the instance.

关键词 $ref 用于在某个 schema 里引用另一个 schema 。$ref 的值是一个基于该 schema 的根 URI 的 URI 引用。当执行到 $ref 时,验证器将使用该可解析标识符去检索被引用的 schema ,并将该 schema 应用于具体的实例数据。

  • In Draft 4-7, $ref behaves a little differently. When an object contains a $ref property, the object is considered a reference, not a schema. Therefore, any other properties you put in that object will not be treated as JSON Schema keywords and will be ignored by the validator. $ref can only be used where a schema is expected.

在草案 4-7 中,$ref 的行为略有不同。当对象包含 $ref 属性时,该对象将仅仅被视为一个引用,而不是一个 schema 。因此,您在该对象中放置的任何其他属性都会被当成非 JSON Schema 关键词,而被验证器忽略。$ref 在仅需要某 schema 的地方使用。

For this example, let's say we want to define a customer record, where each customer may have both a shipping and a billing address. Addresses are always the same—they have a street address, city and state—so we don't want to duplicate that part of the schema everywhere we want to store an address. Not only would that make the schema more verbose, but it makes updating it in the future more difficult. If our imaginary company were to start doing international business in the future and we wanted to add a country field to all the addresses, it would be better to do this in a single place rather than everywhere that addresses are used.

如下所示,假设我们要定义一个客户记录,每个客户可能都需要一个送货地址和一个帐单地址。地址的内容都差不多——如,一般都少不了街道、所在城市和所属的州等——因此我们不希望在要存储地址的所有位置重复 schema 的该部分。这不仅会使 schema 变冗长,而且会使将来的更新操作变得更困难。比如公司将来打算开展国际业务,我们想为所有地址添加一个所在国家的字段,在单一位置执行此操作,显然远远好过在使用地址的所有地方。

JSON Schema:

{
  "$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"]
}

The URI-references in $ref resolve against the schema's Base URI (https://example.com/schemas/customer) which results in https://example.com/schemas/address. The implementation retrieves that schema and uses it to evaluate the “shipping_address” and “billing_address” properties.

$ref 中的 URI-references 通过解析本 schema 的 根-URI( https://example.com/schemas/customer ),推导出 https://example.com/schemas/address 。然后检索到该(关于地址的) schema 并使用它来执行与“shipping_address”和“billing_address”有关的属性验证。

Note

When using $ref in an anonymous schema, relative references may not be resolvable. Let's assume this example is used as an anonymous schema.

{
  "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"]
}

The $ref at /properties/shipping_address can resolve just fine without a non-relative base URI to resolve against, but the $ref at /properties/billing_address can't resolve to a non-relative URI and therefore can't can be used to retrieve the address schema.

注意

在匿名 schema 中使用 $ref 时,可能无法解析相对引用。例如将上述示例改成匿名 schema (去掉其中的 "$id" 部分)。

/properties/shipping_address 处的 $ref 在不具备非相对的 根 URI 的情况下依然可以解析得很好,但 /properties/billing_address 处的 $ref 则无法解析出其非相对 URI,因此将不能用于检索该地址 schema 。

$defs

Sometimes we have small subschemas that are only intended for use in the current schema and it doesn't make sense to define them as separate schemas. Although we can identify any subschema using JSON Pointers or named anchors, the $defs keyword gives us a standardized place to keep subschemas intended for reuse in the current schema document.

有时我们有一些仅用于当前 schema 的很小的 子-schema,小到不值得将它们定义为单独的 schema 。尽管我们可以使用 JSON-指针 或命名锚点,但关键词 $defs 为我们提供了一个标准化的位置来保存这种仅在当前 schema 文档中重用的 子-schema 。

Let's extend the previous customer schema example to use a common schema for the name properties. It doesn't make sense to define a new schema for this and it will only be used in this schema, so it's a good candidate for using $defs.

让我们将上述客户 schema 扩展一下,以便对其 name 属性成为一个通用的 schema 。为此单独定义一个新的 schema 意义不大,因为它只在此 schema 中使用,这是一个使用 $defs 的好地方。

JSON Schema:

{
  "$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 isn't just good for avoiding duplication. It can also be useful for writing schemas that are easier to read and maintain. Complex parts of the schema can be defined in $defs with descriptive names and referenced where it's needed. This allows readers of the schema to more quickly and easily understand the schema at a high level before diving into the more complex parts.

$ref 不仅有利于避免重复。它还有利于编写更易于阅读和维护的 schema 。schema 的复杂部分可以先通过 $defs 使用描述性名称进行定义,并在需要时引用。这有助于读者们在深入了解某 schema 的细节之前,更轻松、更愉快地,站在一个更高的层次上去理解该 schema 。

Note

It's possible to reference an external subschema, but generally you want to limit a $ref to referencing either an external schema or an internal subschema defined in $defs.

注意

虽然(技术上是)允许您引用外部 子-schema ,但通常还是希望您让 $ref 仅限于引用(整个)外部 schema 或引用一个通过 $defs 中定义的内部 子-schema 。

Recursion

The $ref keyword may be used to create recursive schemas that refer to themselves. For example, you might have a person schema that has an array of children, each of which are also person instances.

关键词 $ref 还可用于创建引用自身的 递归-schema 。例如,您可能有一个拥有一群孩子的人员 schema ,他的每个孩子同样也是一个人员数据实例。

JSON Schema:

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "children": {
      "type": "array",
      "items": { "$ref": "#" }
    }
  }
}

JSONV

A snippet of the British royal family tree

英国王室家谱的一个片段

{
  "name": "Elizabeth",
  "children": [
    {
      "name": "Charles",
      "children": [
        {
          "name": "William",
          "children": [
            { "name": "George" },
            { "name": "Charlotte" }
          ]
        },
        {
          "name": "Harry"
        }
      ]
    }
  ]
}

Above, we created a schema that refers to itself, effectively creating a “loop” in the validator, which is both allowed and useful. Note, however, that a $ref referring to another $ref could cause an infinite loop in the resolver, and is explicitly disallowed.

上面,我们创建了一个引用自身的 schema ,创建了一个有效的验证“循环”,这既是允许的,也是有用的。但请注意,通过一个 $ref 引用另一个 $ref 会触发死循环,这是明确不允许的。如下所示(千万别这么做):

JSON Schema:

{
  "$defs": {
    "alice": { "$ref": "#/$defs/bob" },
    "bob": { "$ref": "#/$defs/alice" }
  }
}

Extending Recursive Schemas

New in draft 2019-09

Documentation Coming Soon

草案 2019-09 中的新内容

文档还在准备中,敬请期待

Bundling

Working with multiple schema documents is convenient for development, but it's often more convenient for distribution to bundle all of your schemas into a single schema document. This can be done using the $id keyword in a subschema. When $id is used in a subschema, it indicates an embedded schema. The identifier for the embedded schema is the value of $id resolved against the Base URI of the schema it appears in. A schema document that includes embedded schemas is called a Compound Schema Document. Each schema with an $id in a Compound Schema Document is called a Schema Resource.

虽然开发过程中难免会同时使用多个 schema 文档,但将所有 schema 捆绑到单一 schema 文档中,通常更方便分发。这可以通过在 子-schema 中使用关键词 $id 来实现。当 $id 出现在 子-schema 中时,它表示嵌入式 schema 。嵌入式 schema 的标识符是根据解析它所在的 schema 的 根-URI 得到的 $id 值。包含嵌入式 schema 的 schema 文档称为 复合 schema 文档,复合 schema 文档中的每个带有 $id 的 schema 称为一个 源-schema 。

  • In Draft 4, $id is just id (without the dollar sign).
  • In Draft 4-7, an $id in a subschema did not indicate an embedded schema. Instead it was simply a base URI change in a single schema document.

Note

This is analogous to the < iframe > tag in HTML.

注意

这类似于 HTML 中的 < iframe > 标签。

Note

It is unusual to use embedded schemas when developing schemas. It's generally best not to use this feature explicitly and use schema bundling tools to construct bundled schemas if such a thing is needed.

注意

开发阶段,很少直接使用嵌入式 schema 。通常最好不要显式使用此功能,如果一定要用,请使用 schema 捆绑工具来构造 绑定型 schema 。

This example shows the customer schema example and the address schema example bundled into a Compound Schema Document.

下面展示如何将前文所述的 客户 schema 和 地址 schema 绑定为一个 复合-schema 文档。

JSON Schema:

{
  "$id": "https://example.com/schemas/customer",
  "$schema": "https://json-schema.org/draft/2020-12/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 ..."] }
      }
    }
  }
}

All references in a Compound Schema Document need to be the same whether the Schema Resources are bundled or not. Notice that the $ref keywords from the customer schema have not changed. The only difference is that the address schema is now defined at /$defs/address instead of a separate schema document. You couldn't use #/$defs/address to reference the address schema because if you unbundled the schema, that reference would no longer point to the address schema.

无论是否绑定了 源-schema ,复合-schema 文档 中的所有引用都必须相同。请注意,客户 schema 中的关键词 $ref 没做更改。唯一改变的是地址 schema 现在定义在 /$defs/address中,而非另一个单独的 schema 文档中。您不能使用 #/$defs/address 引用该地址 schema ,因为如果当您需要对该 schema 进行解绑时,该引用将无法再指向地址 schema 。

  • In Draft 4-7, both of these URIs are valid because a subschema $id only represented a base URI change, not an embedded schema. However, even though it's allowed, it's still highly recommended that JSON Pointers don't cross a schema with a base URI change.

You should also see that "$ref": "#/definitions/state" resolves to the definitions keyword in the address schema rather than the one at the top level schema like it would if the embedded schema wasn't used.

您还应该注意到,键值对 "$ref": "#/definitions/state" 将解析进一步深入该地址 schema 中的关键词 definitions(中的 state ) ,而不是某个顶级 schema ,就像未使用嵌入式 schema 时那样。

Each Schema Resource is evaluated independently and may use different JSON Schema dialects. The example above has the address Schema Resource using Draft 7 while the customer Schema Resource uses Draft 2020-12. If no $schema is declared in an embedded schema, it defaults to using the dialect of the parent schema.

源-schema 之间是相互独立的,即可以使用不同的 JSON Schema 方言版本。上面的示例中, 地址 源-schema 依赖的是 草案 7 ,而 客户 源-schema 使用 草案 2019-09。如果某个嵌入式 schema 没有声明 $schema ,则默认沿用其 父-schema 的方言版本。

  • In Draft 4-7, a subschema $id is just a base URI change and not considered an independent Schema Resource. Because $schema is only allowed at the root of a Schema Resource, all schemas bundled using subschema $id must use the same dialect.