类型关键字
当然,如果我们只想接受任何 JSON 文档,我们就不会使用 JSON Schema。在 JSON Schema 中最常见的事情是限制为特定类型,type
关键字就用于此。
当本书提到 JSON Schema“关键字”时,它指的是对象中键/值对的“键”部分。编写 JSON Schema 的大部分工作都涉及将特殊的“关键字”映射到对象中的值。
例如,在下面,只接受字符串:
{ "type": "string" }
"I'm a string" // OK
42 // not OK
type
关键字在[特定类型关键字](#type-specific -keywords)进行了更详细的描述。
如果您曾经使用过 XML Schema、RelaxNG 或 ASN.1,您可能已经知道什么是模式,并且可以愉快地跳到下一部分。如果这一切对您来说听起来像天书,那么您来对地方了。要定义 JSON Schema 是什么,我们可能应该首先定义 JSON 是什么。
JSON 代表“JavaScript Object Notation”,一种简单的数据交换格式。它最初是作为万维网的符号。由于 JavaScript 存在于大多数 Web 浏览器中,并且 JSON 基于 JavaScript,因此很容易支持。然而,它已被证明足够有用且足够简单,以至于它现在被用于许多其他不涉及网上冲浪的环境中。
从本质上讲,JSON 建立在以下数据结构上:
对象(object)
{ "key1": "value1", "key2": "value2" }
数组(array)
[ "first", "second", "third" ]
数字(integer/number)
42
3.1415926字符串(string)
"This is a string"
布尔值(boolean)
true
false
null
null
在大多数编程语言中都有类似类型,尽管它们可能有不同的名称。
下表从 JSON 类型的名称映射到它们在 Python 中的类似类型:
JSON | Python |
---|---|
string | string [4] |
number | int/float [5] |
object | dict |
array | list |
boolean | bool |
null | None |
下表将 JSON 类型的名称映射到它们在 Ruby 中的类似类型:
JSON | Ruby |
---|---|
string | String |
number | Integer/Float [6] |
object | Hash |
array | Array |
boolean | TrueClass/FalseClass |
null | NilClass |
通过这些简单的数据类型,各种结构化数据都可以被表示。然而,这种巨大的灵活性伴随着巨大的责任,因为同一个概念可以以多种方式表示。例如,您可以想象以不同的方式在 JSON 中表示一个人的信息:
{
"name": "George Washington",
"birthday": "February 22, 1732",
"address": "Mount Vernon, Virginia, United States"
}
{
"first_name": "George",
"last_name": "Washington",
"birthday": "1732-02-22",
"address": {
"street_address": "3200 Mount Vernon Memorial Highway",
"city": "Mount Vernon",
"state": "Virginia",
"country": "United States"
}
}
尽管第二种显然比第一种更正式,但是两种表述同样有效。记录的设计在很大程度上取决于它在应用程序中的预期用途,因此这里没有正确或错误的答案。然而,当应用程序说“给我一个人的 JSON 记录”时,准确地知道该记录应该如何组织是很重要的。例如,我们需要知道哪些字段是预期的,以及这些值是如何表示的。这就是 JSON Schema 的用武之地。以下 JSON Schema 片段描述了上面第二个示例的结构。现在不要太担心细节。它们将在后续章节中进行解释。
{
"type": "object",
"properties": {
"first_name": { "type": "string" },
"last_name": { "type": "string" },
"birthday": { "type": "string", "format": "date" },
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"country": { "type" : "string" }
}
}
}
}
通过针对此模式“验证”的一个失败案例如下:
{
"name": "George Washington",
"birthday": "February 22, 1732",
"address": "Mount Vernon, Virginia, United States"
}
然而,第二个例子通过了,如下:
{
"first_name": "George",
"last_name": "Washington",
"birthday": "1732-02-22",
"address": {
"street_address": "3200 Mount Vernon Memorial Highway",
"city": "Mount Vernon",
"state": "Virginia",
"country": "United States"
}
}
您可能已经注意到 JSON Schema 本身是用 JSON 编写的。它是数据本身,而不是计算机程序。它只是一种用于“描述其他数据结构”的声明性格式。这既是它的优点也是它的缺点(它与其他类似的模式语言共享)。简明地描述数据的表面结构并根据它自动验证数据很容易。但是,由于 JSON Schema 不能包含任意代码,因此在表达数据元素之间的关系上有所限制。因此,用于足够复杂的数据格式的任何“验证工具”都可能有两个验证阶段:一个在模式(或结构)级别,一个在语义级别。后一种检查可能需要使用更通用的编程语言来实现。