对象(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的示例,但这次设置 additionalProperties
为false
.
{
"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 }
您可以additionalProperties
与properties
和patternProperties
组合起来使用。在以下示例中,基于 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" }
属性数量
可以使用minProperties
和maxProperties
关键字来限制对象上的属性数量 。这些中的每一个都必须是非负整数。
{
"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