[英]Check differently nested properties in JSON Schema
Is there a way to implement the Postgres equivalent to CHECK constraint within a nested JSON Schema? 有没有一种方法可以在嵌套JSON模式中实现与CHECK约束等效的Postgres? Say we have data that has two properties, each of which has nested properties.
假设我们有两个属性的数据,每个属性都有嵌套的属性。 How can JSON Schema make the required contents of the first object depend on the second?
JSON Schema如何使第一个对象的必需内容取决于第二个对象?
My real case scenario is to build a JSON schema for a GeoJSON objects, that has a geometry object (ie Point or Polygon, or null), and other attributes in a "properties" object. 我的实际情况是为具有几何对象(即Point或Polygon或null)以及“ properties”对象中的其他属性的GeoJSON对象构建JSON模式。 I want to alter the required properties depending on the type of geometry.
我想根据几何类型更改所需的属性。
I failed with both the following solutions: 我无法通过以下两种解决方案:
This would validate since attribute/place covers for the lack of geometry: 这将验证,因为属性/位置涵盖了缺少几何图形的情况:
{
"attributes": {
"name": "Person2",
"place": "City2"
},
"geometry": null
}
This would also validate since attribute/place is no longer required with a geometry: 这也将验证,因为几何不再需要属性/位置:
{
"attributes": {
"name": "Person1"
},
"geometry": {
"type": "Point",
"coordinates": []
}
}
EDIT 编辑
Building on Relequestual's answer, this is the unsatisfactory result I'm getting : 基于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"
}
}
}
This schema will not validate the following if the attributes/place
property is removed. 如果删除了
attributes/place
属性,则该架构将无法验证以下内容。
{
"attributes": {
"name": "Person",
"place": "INVALID IF THIS LINE IS REMOVED ;-("
},
"geometry": {
"type": "Point",
"coordinates": {}
}
}
You can use if/then/else
keywords to apply subschemas conditionally. 您可以使用
if/then/else
关键字有条件地应用子计划。
We only want if
and then
for your solution. 我们只希望
if
和then
您的解决方案。
The value of both must be a JSON Schema. 两者的值都必须是JSON模式。
If the value of if
results in a positive assertion (when the schema is applied to the instance, and it validates successfully), then the schema value of then
is applied to the instance. 如果该值
if
得到正断言(当模式被应用到该实例,并成功验证),那么的模式值then
应用到该实例。
Here's the schema. 这是架构。
I've pre-loaded the schema and data at https://jsonschema.dev so you can test it live. 我已经在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"
}
}
}
The property geometry
references the definition geometry
. 属性
geometry
引用定义geometry
。
allOf
is an array of schemas. allOf
是一个模式数组。
The value of allOf[0].if
references the schema defined as geometryIsPoint
. allOf[0].if
的值引用定义为geometryIsPoint
的架构。
The schema defined as geometryIsPoint
is applied to the geometry
value. 定义为
geometryIsPoint
的架构将应用于该geometry
值。 If it validates successfully, then the then
referenced schema is applied. 如果验证成功,则将应用
then
引用的架构。
You don't have to use referencing to do any of this, but I feel it makes the intent clearer. 您不必使用引用来执行任何上述操作,但是我认为这样做可以使意图更清晰。
Extend the schema as required, adding schemas to allOf
for as many geometry types as you want to recognise. 根据需要扩展模式,将模式添加到
allOf
以便包含您要识别的多个几何类型。
Edit: 编辑:
You were hitting the else
condition of your conditional, because the if
failed validation. 您要达到条件的
else
条件,因为if
验证失败。 Let me explain. 让我解释。
Here's an updated schema to cover your modified use case. 这是一个更新的架构,涵盖了您修改后的用例。
{
"$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"
}
]
}
Here's a JSON Schema dev link so you can test it. 这是JSON Schema开发人员链接,因此您可以对其进行测试。
What we're doing here is splitting up the concerns. 我们在这里所做的是分散关注点。
The "shape" of attributes
and geometry
is defined in definitions with the corresponding key. attributes
和geometry
的“形状”是在定义中使用相应的键定义的。 Those schemas do not assert which keys are required in those objects, only what they must be if provided. 这些模式没有断言那些对象中需要哪些键,只有提供它们时才必须断言。
Because $ref
in a schema makes all other keywords in a schema ignored (for draft-7 or below), at the root level, I've wrapped the reference to conditionalAttributes
in an allOf
. 由于架构中的
$ref
会忽略架构中的所有其他关键字(对于draft-7或更低版本),因此在根级别,我将对conditionalAttributes
的引用包装在allOf
。
conditionalAttributes
is a defined JSON Schema. conditionalAttributes
是已定义的JSON模式。 I've used allOf
so you can add more conditional checks. 我使用过
allOf
因此您可以添加更多条件检查。
The value of conditionalAttributes.allOf[0].if
is a JSON Schema, and is applied to the root of your JSON instance. conditionalAttributes.allOf[0].if
的值是一个JSON模式,并应用于您的JSON实例的根。 It requires a key of geometry
and that the value is geometryIsPoint
. 它需要一个
geometry
键,并且值是geometryIsPoint
。 (If you omit the required
, you'll end up with validation issues, because omitting that key will then pass the if condition). (如果省略了
required
,则会遇到验证问题,因为省略该键将通过if条件)。
When the instance results in a true
assertion (validation valid) for the if
value schema, then the then
value schema is applied at the root level. 当实例为
if
值架构得出true
断言(验证有效)时,则在根级别应用then
值架构。
Because it's applied at the root level and you want to check the value of a nested property, you have to use properties
as you would if you were at the root level of your schema. 因为它是在根级别应用的,并且您要检查嵌套属性的值,所以您必须像在架构的根级别一样使用
properties
。 THIS is how you do conditional schema application ( if/then/else
) across different depths of your instance. 这是您在实例的不同深度进行条件模式应用程序(
if/then/else
)的方式。
You can test out the conditional resolution by changing one of the schema values to false
and looking at the errors. 您可以通过将模式值之一更改为
false
并查看错误来测试条件解析。 Remember, true
and false
are valid JSON Schemas, so you can write "then": false
to cause an error if you expect the then
schema to be applied (as in, the if
schema asserted validation OK). 请记住,
true
和false
是有效的JSON模式,因此,如果您希望应用then
模式, "then": false
可以编写"then": false
导致错误(例如, if
模式断言验证正常)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.