跳到主要内容

类型关键字

当然,如果我们只想接受任何 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 中的类似类型:

JSONPython
stringstring [4]
numberint/float [5]
objectdict
arraylist
booleanbool
nullNone

下表将 JSON 类型的名称映射到它们在 Ruby 中的类似类型:

JSONRuby
stringString
numberInteger/Float [6]
objectHash
arrayArray
booleanTrueClass/FalseClass
nullNilClass

通过这些简单的数据类型,各种结构化数据都可以被表示。然而,这种巨大的灵活性伴随着巨大的责任,因为同一个概念可以以多种方式表示。例如,您可以想象以不同的方式在 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 不能包含任意代码,因此在表达数据元素之间的关系上有所限制。因此,用于足够复杂的数据格式的任何“验证工具”都可能有两个验证阶段:一个在模式(或结构)级别,一个在语义级别。后一种检查可能需要使用更通用的编程语言来实现。