跳到主要内容

对象(object)

对象是 JSON 中的映射类型。他们将“键”映射到“值”。在 JSON 中,“键”必须始终是字符串。这些对中的每一组通常被称为“属性”。

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

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

{ "type": "object" }

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

{// OK
"Sun": 1.9891e30,
"Jupiter": 1.8986e27,
"Saturn": 5.6846e26,
"Neptune": 10.243e25,
"Uranus": 8.6810e25,
"Earth": 5.9736e24,
"Venus": 4.8685e24,
"Mars": 6.4185e23,
"Mercury": 3.3022e23,
"Moon": 7.349e22,
"Pluto": 1.25e22
}

{// not OK,使用非字符串作为键是无效的 JSON
0.01: "cm",
1: "m",
1000: "km"
}

"Not an object" // not OK,使用非字符串作为键是无效的 JSON

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

属性

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

注意:禁止不符合任何属性名称的属性properties,请参阅附加属性

例如,我们要为由数字、街道名称和街道类型组成的地址定义一个简单的模式:

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

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

// not OK,提供的号码类型错误,则无效
{ "number": "1600", "street_name": "Pennsylvania", "street_type": "Avenue" }

// OK,默认情况下,省略属性是有效的。请参阅必需属性。
{ "number": 1600, "street_name": "Pennsylvania" }

// OK,通过扩展,即使是空对象也是有效的
{ }

// OK,默认情况下,提供附加属性是有效的:
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "direction": "NW" }

模式属性

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

注意:正则表达式是没有锚定的,这意味着在为模式属性定义正则表达式时,需要注意该表达式可能与属性名称内的任何位置匹配。例如,正则表达式"p"将匹配任何包含一个p的属性名称(例如"apple"),而不仅仅是名称为"p"。因此,将正则表达式括在^...$ 中通常比较容易理解,例如,"^p$"

在以下示例中,名称以前缀开头的任何属性都S_必须是字符串,并且任何具有前缀的属性都 I_必须是整数。任何与任一正则表达式都不匹配的属性将被忽略。

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

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

// OK
{ "I_0": 42 }

// not OK,如果名称以 开头 S_,则必须是字符串
{ "S_0": 42 }

// not OK,如果名称以 开头 I_,则必须是整数
{ "I_42": "This is a string" }

// OK 这是一个不匹配任何正则表达式的键
{ "keyword": "value" }

额外属性

additionalProperties关键字用于控制的额外的东西,那就是性能,其名称没有在 properties 关键字中列出的或与 patternProperties 关键字中的任何正则表达式匹配的属性。默认情况下,允许任何其他属性。

additionalProperties关键字的值是一个模式,将用于验证实例中与properties或不匹配的任何属性patternProperties。将additionalProperties架构设置 为false意味着不允许其他属性。

重用Properties的示例,但这次设置 additionalPropertiesfalse.

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

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

// not OK,额外属性“direction”使对象无效
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "direction": "NW" }

您可以使用非布尔模式对实例的其他属性设置更复杂的约束。例如,可以允许额外的属性,但前提是它们都是一个字符串:

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

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

// OK,这是有效的,因为附加属性的值是一个字符串
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "direction": "NW" }

// not OK,这是无效的,因为附加属性的值不是字符串:
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "office_number": 201 }

您可以additionalPropertiespropertiespatternProperties组合起来使用。在以下示例中,基于 Pattern Properties 中的示例,我们添加了一个"builtin" 属性,该属性必须是数字,并声明所有其他属性(既不符合 properties定义,同时不匹配 patternProperties)必须是字符串:

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

// OK
{ "builtin": 42 }

// OK,这是一个不匹配任何正则表达式的键:
{ "keyword": "value" }

// not OK,额外属性必须是一个字符串:
{ "keyword": 42 }

必须属性

默认情况下,properties不需要关键字定义的属性。但是,可以使用required关键字提供所需属性的列表。

required关键字采用零个或多个字符串的数组。这些字符串中的每一个都必须是唯一的。

  • 在 dreft 4 中,required必须至少包含一个字符串。
{
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" },
"address": { "type": "string" },
"telephone": { "type": "string" }
},
"required": ["name", "email"]
}

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

// OK,提供额外的属性是可以的,即使是架构中没有定义的属性:
{
"name": "William Shakespeare",
"email": "bill@stratford-upon-avon.co.uk",
"address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
"authorship": "in question"
}

// not OK,缺少必需的“email”属性会使 JSON 文档无效
{
"name": "William Shakespeare",
"address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
}

// not OK,在 JSON 中,具有值的属性 null 不等同于不存在的属性。这失败,因为 null 不是“字符串”类型,而是“空”类型
{
"name": "William Shakespeare",
"address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
"email": null
}

属性名称

draft6 中的新内容

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

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

// OK
{
"_a_proper_token_001": "value"
}
// not OK
{
"001 invalid": "value"
}

由于对象键无论如何必须始终是字符串,因此暗示给定的模式propertyNames始终至少为:

{ "type": "string" }

属性数量

可以使用minPropertiesmaxProperties关键字来限制对象上的属性数量 。这些中的每一个都必须是非负整数。

{
"type": "object",
"minProperties": 2,
"maxProperties": 3
}

{} // not OK
{ "a": 0 } // not OK
{ "a": 0, "b": 1 } // OK
{ "a": 0, "b": 1, "c": 2 } // OK
{ "a": 0, "b": 1, "c": 2, "d": 3 } // not OK