检查 JSON 架构中的不同嵌套属性
Check differently nested properties in JSON Schema
有没有办法在嵌套的 JSON 模式中实现 Postgres 等同于 CHECK 约束?假设我们的数据有两个属性,每个属性都有嵌套属性。 JSON Schema 如何使第一个对象的所需内容依赖于第二个对象?
我的真实案例场景是为 GeoJSON 对象构建一个 JSON 模式,它有一个几何对象(即点或多边形,或空),以及 "properties" 对象。我想根据几何类型更改所需的属性。
我在以下两种解决方案中都失败了:
- 在"anyOf"中嵌套"allOf"以涵盖所有可能性
- 复制 "definitions" 以获得 attributes_no_geom、geometry_no_geom、attribute_with_geom 和 geometry_with_geom,并在 "anyOf"[= 中声明它们36=]
这将得到验证,因为 attribute/place 弥补了几何图形的缺失:
{
"attributes": {
"name": "Person2",
"place": "City2"
},
"geometry": null
}
这也将有效,因为几何不再需要 attribute/place:
{
"attributes": {
"name": "Person1"
},
"geometry": {
"type": "Point",
"coordinates": []
}
}
编辑
基于 Relequestual 的回答,这是我得到的不令人满意的结果:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometryIsPoint": {
"type": "object",
"required": ["type"],
"properties": {
"type": {
"const": "Point"
}
}
},
"partialAttributes": {
"type": "object",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"fullAttributes": {
"type": "object",
"required": ["name", "place"],
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"conditionalAttributes": {
"allOf": [
{
"if": {
"$ref": "#/definitions/geometryIsPoint"
},
"then": {
"$ref": "#/definitions/partialAttributes"
},
"else": {
"$ref": "#/definitions/fullAttributes"
}
}
]
}
},
"properties": {
"attributes": {
"$ref": "#/definitions/conditionalAttributes"
},
"geometry": {
"$ref": "#/definitions/geometryIsPoint"
}
}
}
如果删除 attributes/place
属性,此架构将不会验证以下内容。
{
"attributes": {
"name": "Person",
"place": "INVALID IF THIS LINE IS REMOVED ;-("
},
"geometry": {
"type": "Point",
"coordinates": {}
}
}
您可以使用 if/then/else
keywords 有条件地应用子模式。
我们只需要 if
和 then
作为您的解决方案。
两者的值都必须是 JSON 架构。
如果 if
的值导致肯定断言(当模式应用于实例并成功验证时),则 then
的模式值应用于实例.
这是架构。
我 pre-loaded 架构和数据位于 https://jsonschema.dev,因此您可以对其进行实时测试。
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometryIsPoint": {
"required": [
"type"
],
"properties": {
"type": {
"const": "Point"
}
}
},
"geometryAsPoint": {
"required": [
"coordinates"
],
"properties": {
"coordinates": {
"type": "array"
}
}
},
"geometry": {
"allOf": [
{
"if": {
"$ref": "#/definitions/geometryIsPoint"
},
"then": {
"$ref": "#/definitions/geometryAsPoint"
}
}
]
}
},
"properties": {
"geometry": {
"$ref": "#/definitions/geometry"
}
}
}
属性 geometry
引用定义 geometry
.
allOf
是模式数组。
allOf[0].if
的值引用定义为 geometryIsPoint
的架构。
定义为 geometryIsPoint
的架构应用于 geometry
值。如果验证成功,则会应用 then
引用的架构。
您不必使用引用来执行任何这些操作,但我觉得它使意图更清晰。
根据需要扩展架构,将架构添加到 allOf
以获得您想要识别的尽可能多的几何类型。
编辑:
您达到了条件的 else
条件,因为 if
验证失败。让我解释一下。
这是一个更新的架构,涵盖您修改后的用例。
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometry": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"Point",
"somethingelse",
null
]
}
}
},
"geometryIsPoint": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"const": "Point"
}
}
},
"attributes": {
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"partialAttributes": {
"type": "object",
"required": [
"name"
]
},
"fullAttributes": {
"type": "object",
"required": [
"name",
"place"
]
},
"conditionalAttributes": {
"allOf": [
{
"if": {
"required": [
"geometry"
],
"properties": {
"geometry": {
"$ref": "#/definitions/geometryIsPoint"
}
}
},
"then": {
"required": [
"attributes"
],
"properties": {
"attributes": {
"$ref": "#/definitions/partialAttributes"
}
}
},
"else": {
"required": [
"attributes"
],
"properties": {
"attributes": {
"$ref": "#/definitions/fullAttributes"
}
}
}
}
]
}
},
"properties": {
"attributes": {
"$ref": "#/definitions/attributes"
},
"geometry": {
"$ref": "#/definitions/geometry"
}
},
"allOf": [
{
"$ref": "#/definitions/conditionalAttributes"
}
]
}
这里有一个 JSON Schema dev link 你可以测试一下。
我们在这里所做的是分散关注点。
attributes
和geometry
的“形状”在definitions中用相应的key定义。这些模式不会断言这些对象中需要哪些键,只有在提供时它们必须是什么。
因为模式中的 $ref
会忽略模式中的所有其他关键字(对于 draft-7 或更低版本),在根级别,我将对 conditionalAttributes
的引用包装在一个allOf
.
conditionalAttributes
是定义的 JSON 架构。我使用了 allOf
,因此您可以添加更多条件检查。
conditionalAttributes.allOf[0].if
的值是一个 JSON 架构,并应用于您的 JSON 实例的根。它需要 geometry
的键和 geometryIsPoint
的值。 (如果您省略 required
,您最终会遇到验证问题,因为省略该键将通过 if 条件)。
当实例为 if
值模式生成 true
断言(验证有效)时,将在根级别应用 then
值模式。
因为它在根级别应用并且您想检查嵌套 属性 的值,所以您必须像在架构的根级别一样使用 properties
. 这 是您如何跨实例的不同深度执行条件模式应用程序 (if/then/else
)。
您可以通过将其中一个架构值更改为 false
并查看错误来测试条件解析。请记住,true
和 false
是有效的 JSON 模式,因此如果您希望应用 then
模式(如在中,if
模式断言验证正常)。
有没有办法在嵌套的 JSON 模式中实现 Postgres 等同于 CHECK 约束?假设我们的数据有两个属性,每个属性都有嵌套属性。 JSON Schema 如何使第一个对象的所需内容依赖于第二个对象?
我的真实案例场景是为 GeoJSON 对象构建一个 JSON 模式,它有一个几何对象(即点或多边形,或空),以及 "properties" 对象。我想根据几何类型更改所需的属性。
我在以下两种解决方案中都失败了:
- 在"anyOf"中嵌套"allOf"以涵盖所有可能性
- 复制 "definitions" 以获得 attributes_no_geom、geometry_no_geom、attribute_with_geom 和 geometry_with_geom,并在 "anyOf"[= 中声明它们36=]
这将得到验证,因为 attribute/place 弥补了几何图形的缺失:
{
"attributes": {
"name": "Person2",
"place": "City2"
},
"geometry": null
}
这也将有效,因为几何不再需要 attribute/place:
{
"attributes": {
"name": "Person1"
},
"geometry": {
"type": "Point",
"coordinates": []
}
}
编辑
基于 Relequestual 的回答,这是我得到的不令人满意的结果:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometryIsPoint": {
"type": "object",
"required": ["type"],
"properties": {
"type": {
"const": "Point"
}
}
},
"partialAttributes": {
"type": "object",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"fullAttributes": {
"type": "object",
"required": ["name", "place"],
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"conditionalAttributes": {
"allOf": [
{
"if": {
"$ref": "#/definitions/geometryIsPoint"
},
"then": {
"$ref": "#/definitions/partialAttributes"
},
"else": {
"$ref": "#/definitions/fullAttributes"
}
}
]
}
},
"properties": {
"attributes": {
"$ref": "#/definitions/conditionalAttributes"
},
"geometry": {
"$ref": "#/definitions/geometryIsPoint"
}
}
}
如果删除 attributes/place
属性,此架构将不会验证以下内容。
{
"attributes": {
"name": "Person",
"place": "INVALID IF THIS LINE IS REMOVED ;-("
},
"geometry": {
"type": "Point",
"coordinates": {}
}
}
您可以使用 if/then/else
keywords 有条件地应用子模式。
我们只需要 if
和 then
作为您的解决方案。
两者的值都必须是 JSON 架构。
如果 if
的值导致肯定断言(当模式应用于实例并成功验证时),则 then
的模式值应用于实例.
这是架构。
我 pre-loaded 架构和数据位于 https://jsonschema.dev,因此您可以对其进行实时测试。
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometryIsPoint": {
"required": [
"type"
],
"properties": {
"type": {
"const": "Point"
}
}
},
"geometryAsPoint": {
"required": [
"coordinates"
],
"properties": {
"coordinates": {
"type": "array"
}
}
},
"geometry": {
"allOf": [
{
"if": {
"$ref": "#/definitions/geometryIsPoint"
},
"then": {
"$ref": "#/definitions/geometryAsPoint"
}
}
]
}
},
"properties": {
"geometry": {
"$ref": "#/definitions/geometry"
}
}
}
属性 geometry
引用定义 geometry
.
allOf
是模式数组。
allOf[0].if
的值引用定义为 geometryIsPoint
的架构。
定义为 geometryIsPoint
的架构应用于 geometry
值。如果验证成功,则会应用 then
引用的架构。
您不必使用引用来执行任何这些操作,但我觉得它使意图更清晰。
根据需要扩展架构,将架构添加到 allOf
以获得您想要识别的尽可能多的几何类型。
编辑:
您达到了条件的 else
条件,因为 if
验证失败。让我解释一下。
这是一个更新的架构,涵盖您修改后的用例。
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometry": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"Point",
"somethingelse",
null
]
}
}
},
"geometryIsPoint": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"const": "Point"
}
}
},
"attributes": {
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"partialAttributes": {
"type": "object",
"required": [
"name"
]
},
"fullAttributes": {
"type": "object",
"required": [
"name",
"place"
]
},
"conditionalAttributes": {
"allOf": [
{
"if": {
"required": [
"geometry"
],
"properties": {
"geometry": {
"$ref": "#/definitions/geometryIsPoint"
}
}
},
"then": {
"required": [
"attributes"
],
"properties": {
"attributes": {
"$ref": "#/definitions/partialAttributes"
}
}
},
"else": {
"required": [
"attributes"
],
"properties": {
"attributes": {
"$ref": "#/definitions/fullAttributes"
}
}
}
}
]
}
},
"properties": {
"attributes": {
"$ref": "#/definitions/attributes"
},
"geometry": {
"$ref": "#/definitions/geometry"
}
},
"allOf": [
{
"$ref": "#/definitions/conditionalAttributes"
}
]
}
这里有一个 JSON Schema dev link 你可以测试一下。
我们在这里所做的是分散关注点。
attributes
和geometry
的“形状”在definitions中用相应的key定义。这些模式不会断言这些对象中需要哪些键,只有在提供时它们必须是什么。
因为模式中的 $ref
会忽略模式中的所有其他关键字(对于 draft-7 或更低版本),在根级别,我将对 conditionalAttributes
的引用包装在一个allOf
.
conditionalAttributes
是定义的 JSON 架构。我使用了 allOf
,因此您可以添加更多条件检查。
conditionalAttributes.allOf[0].if
的值是一个 JSON 架构,并应用于您的 JSON 实例的根。它需要 geometry
的键和 geometryIsPoint
的值。 (如果您省略 required
,您最终会遇到验证问题,因为省略该键将通过 if 条件)。
当实例为 if
值模式生成 true
断言(验证有效)时,将在根级别应用 then
值模式。
因为它在根级别应用并且您想检查嵌套 属性 的值,所以您必须像在架构的根级别一样使用 properties
. 这 是您如何跨实例的不同深度执行条件模式应用程序 (if/then/else
)。
您可以通过将其中一个架构值更改为 false
并查看错误来测试条件解析。请记住,true
和 false
是有效的 JSON 模式,因此如果您希望应用 then
模式(如在中,if
模式断言验证正常)。