跳到主要内容

数组(array)

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

在 Python 中,“数组”类似于 listtuple类型,具体取决于用法。但是,jsonPython 标准库中的模块将始终使用 Python 列表来表示 JSON 数组。

在 Ruby 中,“数组”类似于Array类型。

{ "type": "array" }

[1, 2, 3, 4, 5] // OK
[3, "different", { "types" : "of values" }] // OK
{"Not": "an array"} // not OK

元素

JSON 中数组的使用一般有两种方式:

  • 列表验证:任意长度的序列,其中每个项目都匹配相同的模式。
  • 元组验证:一个固定长度的序列,其中每个项目可能有不同的模式。在这种用法中,每个项目的索引(或位置)对于如何解释值是有意义的。(在某些编程语言中,这种用法通常被赋予一个完整的单独类型,例如 Python 的tuple)。

列表验证

列表验证对于任意长度的数组很有用,其中每个项目都匹配相同的模式。对于这种类型的数组,将items关键字设置为单个模式,将用于验证数组中所有元素。

笔记:当items是单模式时,additionalItems关键字没有意义,不应使用。

在下面的例子中,我们定义数组中的每一项都是一个数字:

{
"type": "array",
"items": {
"type": "number"
}
}

[1, 2, 3, 4, 5] // OK
[1, 2, "3", 4, 5] // not OK,单个“非数字”会导致整个数组无效
[] // OK,空数组始终有效

元组验证

当数组是一个元素的集合时,元组验证很有用,其中每个项目都有不同的架构并且每个项目的序数索引是有意义的。

例如,您可以表示街道地址,例如:

1600 Pennsylvania Avenue NW

作为以下形式的 4 元组:

[号码、街道名称、街道类型、方向]

这些字段中的每一个都将具有不同的模式:

  • number: 地址编号,必须是数字。
  • street_name: 街名,必须是字符串。
  • street_type: 街道类型,应该是来自一组固定值的字符串。
  • direction:地址所在城市象限,应该是来自不同值组成集合的字符串。

为此,我们将items关键字设置为一个数组,其中每个项目都是一个模式,对应于文档数组的每个索引。也就是说,一个数组,其中第一个元素验证输入数组的第一个元素,第二个元素验证输入数组的第二个元素,依此类推。

以下是示例:

{
"type": "array",
"items": [
{ "type": "number" },
{ "type": "string" },
{ "enum": ["Street", "Avenue", "Boulevard"] },
{ "enum": ["NW", "NE", "SW", "SE"] }
]
}

[1600, "Pennsylvania", "Avenue", "NW"] // OK
[24, "Sussex", "Drive"] // not OK,“Drive”不是可接受的街道类型之一
["Palais de l'Élysée"] // not OK,此地址缺少街道号码
[10, "Downing", "Street"] // OK,可以不提供所有项目
[1600, "Pennsylvania", "Avenue", "NW", "Washington"] // OK,默认情况下可以在尾部添加其他项目

附加元素

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

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

在这里,我们将重用上面的示例模式,但设置 additionalItemsfalse,这具有禁止数组中的额外项目的效果。

{
"type": "array",
"items": [
{ "type": "number" },
{ "type": "string" },
{ "enum": ["Street", "Avenue", "Boulevard"] },
{ "enum": ["NW", "NE", "SW", "SE"] }
],
"additionalItems": false
}

[1600, "Pennsylvania", "Avenue", "NW"] // OK
[1600, "Pennsylvania", "Avenue"] // OK,可以不提供所有元素
[1600, "Pennsylvania", "Avenue", "NW", "Washington"] // not OK,不能提供额外的元素

您可以通过使用非布尔模式来限制附加项可以具有的值来表达更复杂的约束。在这种情况下,我们可以说允许附加元素,只要它们都是字符串:

{
"type": "array",
"items": [
{ "type": "number" },
{ "type": "string" },
{ "enum": ["Street", "Avenue", "Boulevard"] },
{ "enum": ["NW", "NE", "SW", "SE"] }
],
"additionalItems": { "type": "string" }
}

[1600, "Pennsylvania", "Avenue", "NW", "Washington"] // OK,额外的字符串元素是可以的
[1600, "Pennsylvania", "Avenue", "NW", 20500] // not OK,额外的元素不是字符串

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

包含

Draft 6 中的新内容:虽然items模式必须对数组中的每一项都有效,但 contains模式只需要针对数组中的一项或多项进行验证。

{
"type": "array",
"contains": {
"type": "number"
}
}

["life", "universe", "everything", 42] // OK,包含一个 number 元素
["life", "universe", "everything", "forty-two"] // not OK,不包含 number 元素
[1, 2, 3, 4, 5] // OK

长度

可以使用minItemsmaxItems关键字指定数组的长度。每个关键字的值必须是非负数。无论是进行List 验证还是Tuple 验证,这些关键字都 有效

{
"type": "array",
"minItems": 2,
"maxItems": 3
}

[] // not OK,
[1] // not OK,
[1, 2] // OK
[1, 2, 3] // OK
[1, 2, 3, 4] // not OK

唯一性

只需将uniqueItems关键字设置为true,可以限制数组中的每个元素都是唯一的。

{
"type": "array",
"uniqueItems": true
}

[1, 2, 3, 4, 5] // OK
[1, 2, 3, 3, 4] // not OK
[] // OK 空数组总是通过