Json 面向方面的架构 Json 文件
Json Schema for Aspect Oriented Json files
所以我的 json 结构是面向方面的,这意味着 json 是一种结构,每个数据都由一个键表示,该键将定义其内容的结构。
例如:
[
{
"nv": [{ "ln": 123 }]
},
{
"metadata": [{ "name": "nodes" }, { "name": "edges" }]
},
{
"nodes": [{ "@id": 1 }, { "@id": 2 }]
},
{
"edges": [
{ "@id": 1, "nodeId": 1 },
{ "@id": 2, "nodeId": 2 }
]
},
{
"status": [{ "success": true }]
}
]
如图所示,有 3 个对象(nv、元数据、状态),根据元数据中的 name
,json 文件中会有对象。
我试过这样的事情:
{
"type": "array",
"items": [
{
"type": "object",
"properties": {
"nv": { "type": "array", "items": { "$ref": "#definitions/nv" } }
},
"required": ["nv"]
},
{
"type": "object",
"properties": {
"metaData": {
"type": "array",
"items": { "$ref": "#definitions/metadata" }
}
},
"required": ["metaData"]
},
{
"anyOf": [
{
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": { "$ref": "#definitions/nodes" }
}
}
},
{
"type": "object",
"properties": {
"edges": {
"type": "array",
"items": { "$ref": "#definitions/edges" }
}
}
},
{
"type": "object",
"properties": {
"edgeAttribute": {
"type": "array",
"items": { "$ref": "#definitions/edgeAttribute" }
}
}
},
{
"type": "object",
"properties": {
"nodeAttribute": {
"type": "array",
"items": { "$ref": "#definitions/nodeAttribute" }
}
}
}
]
},
{
"type": "object",
"properties": {
"status": {
"type": "array",
"items": { "$ref": "#definitions/status" }
}
},
"required": ["status"]
}
],
"definitions": {
"status": {
"type": "object",
"properties": {
"success": { "type": "boolean" }
}
"etc..."
}
}
}
但是如果我定义一个空数组,它将被接受,如果数组只包含 3 个必需对象之一,它也会被接受。
那么有没有一种方法可以使用 json-schemas 来验证类似示例的内容?
实际场景中元数据中可能不止有 2 个对象,这就是我没有使用 if -> then -> else
条件的原因。如果解决方案是使用它们,请告诉我。
我建议将您的每个“类型”移动到 $defs
中以供参考。
{
"$defs": {
"nvObj": {
"type": "object",
"properties": {
"nv": { "type": "array", "items": { "$ref": "#/$defs/nv" } }
},
"required": ["nv"]
},
... // other defitions
}
}
(我已将 $ref
更新为使用 $defs
而不是 definitions
,因为这是自草案 7 以来的新关键字。)
然后你可以把很多引用放到一个oneOf
.
{
"$defs": {
... // from above
},
"type": "array",
"items": {
"oneOf": [
{ "$ref": "#/$defs/nvObj" },
... // all of the other object definitions
]
}
}
对于这种情况,您避免 if
/then
/else
是正确的。 oneOf
是最好的选择。
数据的结构使它变得粗略,但是您可以使用一些模式来获得您想要的行为。让我们一个接一个。
声明一个可以包含任意多个对象的数组
通常人们为此使用 oneOf
,但我不推荐这样做,因为它可能会导致性能不佳和难以理解的错误消息。通常这意味着 if
/then
,但在这种情况下,您可以通过将项目定义为单个对象(每个对象一次只允许一个 属性)来获得良好的结果。
{
"items": {
"type": "object",
"properties": {
"nv": { "$ref": "#/definitions/nv" },
"metadata": { "$ref": "#/definitions/metadata" },
"status": { "$ref": "#/definitions/status" },
"nodes": { "$ref": "#/definitions/nodes" },
"edges": { "$ref": "#/definitions/edges" }
},
"minProperties": 1,
"maxProperties": 1
}
}
编辑:之前推荐dependencies
,后来发现这个更好
断言数组包含一个需要的对象
为此,您需要断言数组 contains
是一个具有 required
属性.
的对象
{ "contains": { "type": "object", "required": ["nv"] } }
您必须在 allOf
中组合此模式来表达额外的必需项。
{
"allOf": [
{ "contains": { "type": "object", "required": ["nv"] } },
{ "contains": { "type": "object", "required": ["metadata"] } },
{ "contains": { "type": "object", "required": ["status"] } }
]
}
有条件地断言数组包含一个需要的对象
这里棘手的部分是让 if
中的所有嵌套 contains
和 properties
能够断言“名称”是某个值。 then
只是使用我们上面使用的相同模式来断言数组中需要一个对象。
{
"if": {
"type": "array",
"contains": {
"type": "object",
"properties": {
"metadata": {
"type": "array",
"contains": {
"type": "object",
"properties": {
"name": { "const": "nodes" }
},
"required": ["name"]
}
}
},
"required": ["metadata"]
}
},
"then": { "contains": { "type": "object", "required": ["nodes"] } }
}
以上示例显示了有条件地需要“节点”对象。您需要为“边缘”对象重复此模式并将它们与 allOf
组合。我建议使用 definitions
来帮助提高可读性。
{
"allOf": [
{ "$ref": "#/definitions/if-metadata-has-nodes-then-require-nodes-object" },
{ "$ref": "#/definitions/if-metadata-has-edges-then-require-edges-object" }
]
}
所以我的 json 结构是面向方面的,这意味着 json 是一种结构,每个数据都由一个键表示,该键将定义其内容的结构。
例如:
[
{
"nv": [{ "ln": 123 }]
},
{
"metadata": [{ "name": "nodes" }, { "name": "edges" }]
},
{
"nodes": [{ "@id": 1 }, { "@id": 2 }]
},
{
"edges": [
{ "@id": 1, "nodeId": 1 },
{ "@id": 2, "nodeId": 2 }
]
},
{
"status": [{ "success": true }]
}
]
如图所示,有 3 个对象(nv、元数据、状态),根据元数据中的 name
,json 文件中会有对象。
我试过这样的事情:
{
"type": "array",
"items": [
{
"type": "object",
"properties": {
"nv": { "type": "array", "items": { "$ref": "#definitions/nv" } }
},
"required": ["nv"]
},
{
"type": "object",
"properties": {
"metaData": {
"type": "array",
"items": { "$ref": "#definitions/metadata" }
}
},
"required": ["metaData"]
},
{
"anyOf": [
{
"type": "object",
"properties": {
"nodes": {
"type": "array",
"items": { "$ref": "#definitions/nodes" }
}
}
},
{
"type": "object",
"properties": {
"edges": {
"type": "array",
"items": { "$ref": "#definitions/edges" }
}
}
},
{
"type": "object",
"properties": {
"edgeAttribute": {
"type": "array",
"items": { "$ref": "#definitions/edgeAttribute" }
}
}
},
{
"type": "object",
"properties": {
"nodeAttribute": {
"type": "array",
"items": { "$ref": "#definitions/nodeAttribute" }
}
}
}
]
},
{
"type": "object",
"properties": {
"status": {
"type": "array",
"items": { "$ref": "#definitions/status" }
}
},
"required": ["status"]
}
],
"definitions": {
"status": {
"type": "object",
"properties": {
"success": { "type": "boolean" }
}
"etc..."
}
}
}
但是如果我定义一个空数组,它将被接受,如果数组只包含 3 个必需对象之一,它也会被接受。
那么有没有一种方法可以使用 json-schemas 来验证类似示例的内容?
实际场景中元数据中可能不止有 2 个对象,这就是我没有使用 if -> then -> else
条件的原因。如果解决方案是使用它们,请告诉我。
我建议将您的每个“类型”移动到 $defs
中以供参考。
{
"$defs": {
"nvObj": {
"type": "object",
"properties": {
"nv": { "type": "array", "items": { "$ref": "#/$defs/nv" } }
},
"required": ["nv"]
},
... // other defitions
}
}
(我已将 $ref
更新为使用 $defs
而不是 definitions
,因为这是自草案 7 以来的新关键字。)
然后你可以把很多引用放到一个oneOf
.
{
"$defs": {
... // from above
},
"type": "array",
"items": {
"oneOf": [
{ "$ref": "#/$defs/nvObj" },
... // all of the other object definitions
]
}
}
对于这种情况,您避免 if
/then
/else
是正确的。 oneOf
是最好的选择。
数据的结构使它变得粗略,但是您可以使用一些模式来获得您想要的行为。让我们一个接一个。
声明一个可以包含任意多个对象的数组
通常人们为此使用 oneOf
,但我不推荐这样做,因为它可能会导致性能不佳和难以理解的错误消息。通常这意味着 if
/then
,但在这种情况下,您可以通过将项目定义为单个对象(每个对象一次只允许一个 属性)来获得良好的结果。
{
"items": {
"type": "object",
"properties": {
"nv": { "$ref": "#/definitions/nv" },
"metadata": { "$ref": "#/definitions/metadata" },
"status": { "$ref": "#/definitions/status" },
"nodes": { "$ref": "#/definitions/nodes" },
"edges": { "$ref": "#/definitions/edges" }
},
"minProperties": 1,
"maxProperties": 1
}
}
编辑:之前推荐dependencies
,后来发现这个更好
断言数组包含一个需要的对象
为此,您需要断言数组 contains
是一个具有 required
属性.
{ "contains": { "type": "object", "required": ["nv"] } }
您必须在 allOf
中组合此模式来表达额外的必需项。
{
"allOf": [
{ "contains": { "type": "object", "required": ["nv"] } },
{ "contains": { "type": "object", "required": ["metadata"] } },
{ "contains": { "type": "object", "required": ["status"] } }
]
}
有条件地断言数组包含一个需要的对象
这里棘手的部分是让 if
中的所有嵌套 contains
和 properties
能够断言“名称”是某个值。 then
只是使用我们上面使用的相同模式来断言数组中需要一个对象。
{
"if": {
"type": "array",
"contains": {
"type": "object",
"properties": {
"metadata": {
"type": "array",
"contains": {
"type": "object",
"properties": {
"name": { "const": "nodes" }
},
"required": ["name"]
}
}
},
"required": ["metadata"]
}
},
"then": { "contains": { "type": "object", "required": ["nodes"] } }
}
以上示例显示了有条件地需要“节点”对象。您需要为“边缘”对象重复此模式并将它们与 allOf
组合。我建议使用 definitions
来帮助提高可读性。
{
"allOf": [
{ "$ref": "#/definitions/if-metadata-has-nodes-then-require-nodes-object" },
{ "$ref": "#/definitions/if-metadata-has-edges-then-require-edges-object" }
]
}