简体   繁体   English

具有多个嵌套 anyOf 的 JSON 模式

[英]JSON schema with multiple nested anyOf

Based on the previous answer I built a scheme that would meet my requirements.根据前面的答案,我构建了一个可以满足我要求的方案。 The question and the answer to it can be seen here .问题和答案可以在这里看到。

The resulting scheme:结果方案:

{   
    "definitions": {},
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": [
        "virtual"
    ],
    "properties": {
        "virtual": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "type",
                    "path",
                    "entity",
                    "nodes"
                ],
                "properties": {
                    "type": {
                        "type": "string"
                    },
                    "path": {
                        "type": "string"
                    },
                    "entity": {
                        "enum": ["pde", "topaz"]
                    }         
                },
                "anyOf": [
                    {
                        "properties": {
                            "entity": {"const": "pde"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "title": "The Items Schema",
                                    "required": [
                                        "id",
                                        "type",
                                        "address",
                                        "nozzles"
                                    ],
                                    "properties": {
                                        "id": {
                                            "type": "string"
                                        },
                                        "type": {
                                            "type": "string"
                                        },
                                        "address": {
                                            "type": "integer"
                                        },
                                        "nozzles": {
                                            "type": "array",
                                            "items": {
                                                "type": "integer"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    {
                        "properties": {
                            "entity": {"const": "topaz"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "uid",
                                        "utype",
                                        "uaddress",
                                        "unozzles"
                                    ],
                                    "properties": {
                                        "uid": {
                                            "type": "integer"
                                        },
                                        "utype": {                  
                                            "type": "string"
                                        },
                                        "uaddress": {
                                            "type": "string"
                                        },
                                        "unozzles": {
                                            "type": "boolean"
                                        }
                                    }
                                }
                            }
                        } 
                    }
                ]
            }
        }
    }
}

And JSON:和 JSON:

{
    "virtual": [
        {
            "type": "bus",
            "path": "VBUS1",
            "entity": "pde",
            "nodes": [
                {
                    "id": "vrt_1",
                    "type": "dispenser",
                    "address": 1,
                    "nozzles": [1, 2, 3]
                },
                {
                    "id": "vrt_2",
                    "type": "dispenser",
                    "address": 2,
                    "nozzles": [4, 5, 3]
                }
            ]
        },
        {
            "type": "bus",
            "path": "VBUS2",
            "entity": "topaz",
            "nodes": [          
                {
                    "uid": 1,
                    "utype": "dispenser",
                    "uaddress": "false",
                    "unozzles": true
                },
                {
                    "uid": 2,
                    "utype": "dispenser",
                    "uaddress": "true",
                    "unozzles": false
                }
            ]
        }
    ]
}

The following problem appeared.出现以下问题。 When type=bus JSON has path and entity fields.当 type=bus JSON 有路径和实体字段。 But, if type=io the path and entity fields are missing and the node field looks different from the above two.但是,如果 type=io 缺少 path 和 entity 字段,并且 node 字段看起来与上述两个不同。

Hence I need to have anyOf that would track the value of the type field and another anyOf that would work for type=bus.因此,我需要使用anyOf 来跟踪类型字段的值,以及另一个适用于type=bus 的anyOf。

I will try to explain more clearly.我将尝试更清楚地解释。 It is necessary to track the value of the type field and if it is equal to bus, then the path and entity fields appear.需要跟踪类型字段的值,如果等于总线,则出现路径和实体字段。 Depending on the value of entity, the node field has a certain structure (exactly what is written in the diagram above).根据entity的值,node字段有一定的结构(就是上图中写的)。

I tried to make a schema with nested anyOf:我试图用嵌套的 anyOf 创建一个模式:

{
    "definitions": {},
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": [
        "virtual"
    ],
    "properties": {
        "virtual": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "type"
                ],
                "properties": {
                    "type": {
                        "enum": ["bus", "io"]
                    }
                },
                "anyOf": [
                    {

                        "properties": {
                            "type": {"const": "bus"},
                            "path": { "type": "string" },
                            "entity": { "enum": ["topaz", "pde"] }
                        },
                        "anyOf":[
                        {
                            "properties":{
                                "entity": {"const": "pde"},
                                "nodes": {
                                    "type": "array",
                                    "items": {
                                        "type": "object",
                                        "required": [
                                            "id",
                                            "type",
                                            "address",
                                            "nozzles"
                                        ],
                                        "properties": {
                                            "id": { "type": "string" },
                                            "type": { "type": "string" },
                                            "address": { "type": "integer" },
                                            "nozzles": {
                                                "type": "array",
                                                "items": { "type": "integer" }
                                            }
                                        }
                                    }
                                }
                            }
                        },
                        {
                            "entity": {"const": "topaz"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "uid",
                                        "utype",
                                        "uaddress",
                                        "unozzles"
                                    ],
                                    "properties": {
                                        "uid": { "type": "integer" },
                                        "utype": { "type": "string" },
                                        "uaddress": { "type": "string" },
                                        "unozzles": { "type": "boolean" }
                                    }
                                }
                            }
                        }
                        ]
                    },
                    {
                        "properties": {
                            "type": {"const": "io"},
                            "nodes": {
                                "type": "array",
                                "items":{
                                    "type": "object",
                                    "required": [
                                        "num",
                                        "key",
                                        "title",
                                        "path"
                                    ],
                                    "properties": {
                                        "num": { "type": "integer" },
                                        "key": { "type": "integer" },
                                        "title": { "type": "string" },
                                        "path": { "type": "string" }
                                    }
                                }
                            }
                        }
                    }
                ]
            }
        }   
    }
} 

Example of checking the scheme on the site现场检查方案示例

But as expected, the scheme accepts even those schemes that should not be accepted.但正如预期的那样,该方案甚至接受那些不应该被接受的方案。

An example of a non-valid schema.无效模式的示例。 There is no required id field for type=bus, entity=pde. type=bus、entity=pde 不需要 id 字段。 There is no mandatory uid field for type=bus, entity=topaz. type=bus, entity=topaz 没有强制的 uid 字段。 It feels like the second nested anyOf is ignored.感觉就像第二个嵌套的 anyOf 被忽略了。

{
  "virtual": [
    {
      "type": "bus",
      "path": "VBUS1",
      "entity": "pde",
      "nodes": [
        {
          "not_id": "vrt_1",
          "type": "dispenser",
          "address": 1,
          "nozzles": [
            1,
            2,
            3
          ]
        },
        {
          "id": "vrt_2",
          "type": "dispenser",
          "address": 2,
          "nozzles": [
            4,
            5,
            3
          ]
        }
      ]
    },
    {
      "type": "bus",
      "path": "VBUS2",
      "entity": "topaz",
      "nodes": [
        {
          "not_uid": 1,
          "utype": "dispenser",
          "uaddress": "false",
          "unozzles": true
        },
        {
          "uid": 2,
          "utype": "dispenser",
          "uaddress": "true",
          "unozzles": false
        }
      ]
    },
    {
      "type": "io",
      "nodes": [
        {
          "num": 1,
          "key": 123,
          "title": "123",
          "path": "123"
        }
      ]
    }
  ]
}

Check the validity of the incorrect JSON .检查不正确的 JSON 的有效性

In this case, anyOf for the type field works as expected.在这种情况下,类型字段的 anyOf 按预期工作。 I assume that this problem appeared again because of the wrong layout of the scheme, but I could not find information on the Internet on nested anyOf.我假设这个问题再次出现是因为方案布局错误,但是我在 Internet 上找不到关于嵌套 anyOf 的信息。

When trying to insert all checks into one anyOf everything works as intended.当尝试将所有检查插入一个 anyOf 时,一切都按预期工作。

{   
    "definitions": {},
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": [
        "virtual"
    ],
    "properties": {
        "virtual": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "type"
                ],
                "properties": {
                    "type": { "enum": ["bus", "io"] }        
                },
                "anyOf": [
                    {
                        "properties": {
                            "type": {"const": "bus"},
                            "path": { "type": "string" },
                            "entity": {"const": "pde"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "title": "The Items Schema",
                                    "required": [
                                        "id",
                                        "type",
                                        "address",
                                        "nozzles"
                                    ],
                                    "properties": {
                                        "id": { "type": "string" },
                                        "type": { "type": "string" },
                                        "address": { "type": "integer" },
                                        "nozzles": {
                                            "type": "array",
                                            "items": { "type": "integer" }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    {
                        "properties": {
                            "type": {"const": "bus"},
                            "path": { "type": "string" },
                            "entity": {"const": "topaz"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "uid",
                                        "utype",
                                        "uaddress",
                                        "unozzles"
                                    ],
                                    "properties": {
                                        "uid": { "type": "integer" },
                                        "utype": { "type": "string" },
                                        "uaddress": { "type": "string" },
                                        "unozzles": { "type": "boolean" }
                                    }
                                }
                            }
                        } 
                    },
                    {
                        "properties": {
                            "type": {"const": "io"},
                            "nodes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": [
                                        "num",
                                        "key",
                                        "title",
                                        "path"
                                    ],
                                    "properties": {
                                        "num": { "type": "integer" },
                                        "key": { "type": "integer" },
                                        "title": { "type": "string" },
                                        "path": { "type": "string" }
                                    }
                                }
                            }
                        } 
                    }
                ]
            }
        }
    }
}

But:但:

  1. This scheme looks quite dirty这个方案看起来很脏
  2. It's not exactly what I'd like to see这不是我想看到的

The JSON schema itself, for which you want to create a schema: JSON 架构本身,您要为其创建架构:

{
    "virtual": [
        {
            "type": "bus",
            "path": "VBUS1",
            "entity": "pde",
            "nodes": [
                {
                    "id": "vrt_1",
                    "type": "dispenser",
                    "address": 1,
                    "nozzles": [1, 2, 3]
                },
                {
                    "id": "vrt_2",
                    "type": "dispenser",
                    "address": 2,
                    "nozzles": [4, 5, 3]
                }
            ]
        },
        {
            "type": "bus",
            "path": "VBUS2",
            "entity": "topaz",
            "nodes": [          
                {
                    "uid": 1,
                    "utype": "dispenser",
                    "uaddress": "false",
                    "unozzles": true
                },
                {
                    "uid": 2,
                    "utype": "dispenser",
                    "uaddress": "true",
                    "unozzles": false
                }
            ]
        },
        {
            "type": "io",
            "nodes": [
                "num": 4,
                "key": 123456,
                "title": "io",
                "path": "default"
            ]
        }
    ]
}

Full JSON has a rather complex structure and only part of it is represented here.完整的 JSON 的结构相当复杂,这里只展示了一部分。 Hence I would like to understand how to structure such things correctly (understand the idea itself, and preferably see an example of the correct scheme. At least schematic).因此,我想了解如何正确地构建这些东西(了解这个想法本身,最好看一个正确方案的例子。至少是示意图)。

So, to summarize.所以,总结一下。 I need to understand how any Of can be implemented in one of the anyOf variants.我需要了解 any Of 如何在 anyOf 变体之一中实现。 Is it feasible?可行吗? And, if so, where can I see examples and instructions for compiling such schemes?如果是这样,我在哪里可以看到编译此类方案的示例和说明? If not, is there any workaround?如果没有,是否有任何解决方法?

I think I've found a solution.我想我找到了解决办法。 However, if there are any comments or corrections-I will be glad to hear.但是,如果有任何意见或更正,我将很高兴听到。

Just in case I give an example of the resulting scheme:以防万一我举一个结果方案的例子:

{   
    "definitions": {},
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": [
        "virtual"
    ],
    "properties": {
        "virtual": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "type"
                ],
                "properties": {
                    "type": {
                        "enum": ["bus", "io"]
                    }
                },
                "anyOf": [
                    {       
                        "properties":{
                            "type": {"const": "bus"},                       
                        },
                        "anyOf":[
                            {
                                "properties":{
                                    "path": { "type": "string" },
                                    "entity": {"const": "pde"},
                                    "nodes": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "id",
                                                "type",
                                                "address",
                                                "nozzles"
                                            ],
                                            "properties": {
                                                "id": { "type": "string" },
                                                "type": { "type": "string" },
                                                "address": { "type": "integer" },
                                                "nozzles": {
                                                    "type": "array",
                                                    "items": { "type": "integer" }
                                                }
                                            }
                                        }
                                    }
                                }
                            },
                            {
                                "properties":{
                                    "path": { "type": "string" },
                                    "entity": {"const": "topaz"},
                                    "nodes": {
                                        "type": "array",
                                        "items": {
                                            "type": "object",
                                            "required": [
                                                "uid",
                                                "utype",
                                                "uaddress",
                                                "unozzles"
                                            ],
                                            "properties": {
                                                "uid": { "type": "integer" },
                                                "utype": { "type": "string" },
                                                "uaddress": { "type": "string" },
                                                "unozzles": { "type": "boolean" }
                                            }
                                        }
                                    }
                                }
                            }
                        ]
                    },
                    {
                        "properties": {
                            "type": {"const": "io"},
                            "nodes": {
                                "type": "array",
                                "items":{
                                    "type": "object",
                                    "required": [
                                        "num",
                                        "key",
                                        "title",
                                        "path"
                                    ],
                                    "properties": {
                                        "num": { "type": "integer" },
                                        "key": { "type": "integer" },
                                        "title": { "type": "string" },
                                        "path": { "type": "string" }
                                    }
                                }
                            }
                        }
                    }
                ]
            }
        }   
    }
} 

Although nested anyOf works just fine in JSON Schema, I don't think that's the best solution in this case.尽管嵌套的anyOf在 JSON 模式中工作得很好,但我认为这不是这种情况下的最佳解决方案。 Flattening the anyOf s and using some definitions cleans up the schema tremendously making it easier to reason about.扁平化anyOf并使用一些definitions可以极大地清理模式,使其更容易推理。

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["virtual"],
  "properties": {
    "virtual": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["type"],
        "anyOf": [
          { "$ref": "#/definitions/pdm" },
          { "$ref": "#/definitions/topaz" },
          { "$ref": "#/definitions/io" }
        ]
      }
    }
  },
  "definitions": {
    "pdm": {
      "properties":{
        "type": { "const": "bus" },
        "entity": { "const": "pde" },
        ... type specific properties ...
      }
    },
    "topaz": {
      "properties": {
        "type": { "const": "bus" },
        "entity": { "const": "topaz" },
        ... type specific properties ...
      }
    },
    "io": {
      "properties": {
        "type": { "const": "io" },
        ... type specific properties ...
      }
    }
  }
}

If you use if / then / else or the Implication Pattern rather than the Enum Pattern, you can get better error messaging, but with a more complex schema.如果你使用if / then / else或暗示模式而不是枚举模式,你可以获得更好的错误消息,但模式更复杂。

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["virtual"],
  "properties": {
    "virtual": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["type"],
        "allOf": [
          { "$ref": "#/definitions/pdm" },
          { "$ref": "#/definitions/topaz" },
          { "$ref": "#/definitions/io" }
        ]
      }
    }
  },
  "definitions": {
    "pdm": {
      "if": {
        "properties":{
          "type": { "const": "bus" },
          "entity": { "const": "pde" }
        },
        "required": ["type", "entity"]
      },
      "then": {
        "properties": {
          ... type specific constraints ...
        }
      }
    },
    ... additional types ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM