基于动态 属性 值的条件 JSON 架构

Conditional JSON schema based on dynamic property value

我正在尝试验证包含多个相同类型的嵌套组件的 JSON 文件。每个组件都有一个 class 字符串 属性。我正在尝试根据 class 的值将我的定义中的不同验证模式应用于每个组件。此外,class的值可以是"button-open"、"button-close"、"icon-message"、"icon-..."、"container",等等,我想对所有 "buttons-" 应用相同的验证模式,另一个应用到 "icons-",另一个应用到其余的。

我提供的代码是我试过的。为了简单起见,我排除了 icons-。如您所见,每当 class 中存在 button 时,我都尝试使用正则表达式进行匹配。那么它应该将子元素的最小值约束为1。

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": ["results"],
    "properties": {
        "results": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "object",
                "anyOf": [
                    {
                        "$ref": "#/definitions/genericComponent"
                    },
                    {
                        "$ref": "#/definitions/button"
                    }
                ]
            }
        }
    },
    "definitions": {
        "genericComponent": {
            "type": "object",
            "$id": "#/definitions/genericComponent",
            "required":[
                "class",
                "children"
            ],
            "properties":{
                "class": {
                    "type": "string",
                    "description": "predicted class of the element(img, icon..)"
                },
                "children":{
                    "type": "array",
                    "description": "this element can contain more of the same type",
                    "items":{
                        "type": "object",
                        "anyOf":[
                            {"$ref": "#/definitions/button"},
                            {"$ref": "#/definitions/genericComponent"}
                        ]
                    }
                }
            }
        },
        "button": {
            "$id": "#/definitions/button",
            "allOf":[
                {"$ref": "#/definitions/genericComponent"},
                {"properties": {
                    "class":{
                        "type":"string",
                        "pattern": "(button)"
                    },
                    "children":{
                        "type": "array",
                        "description": "this element must contain one generic element",
                        "items":{
                            "type": "object",
                            "$ref": "#/definitions/genericComponent"
                        },
                        "minItems": 1,
                        "maxItems": 1
                    }
                }}
            ]
        }
    }
}

我也尝试有条件地应用 属性 作为:

{
    "type": "object",
    "required": ["results"],
    "properties": {
        "results": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "object",
                "$ref": "#/definitions/genericComponent"
            }
        }
    },
    "definitions": {
        "genericComponent": {
            "type": "object",
            "$id": "#/definitions/genericComponent",
            "required":[
                "class",
                "children"
            ],
            "properties":{
                "class":{
                    "type": "string"
                },
                "children":{
                    "type": "array",
                    "items": {
                        "type": "object",
                        "anyOf":[
                            {"$ref":"#/definitions/genericComponent"},
                            {"$ref":"#/definitions/button"}
                        ]
                    }
                }
            },  
            "if": {
                "properties": {"class": {"pattern": "^button-rect$"}}
            },
            "then": {
                "properties": {
                    "children":{
                        "type": "array",
                        "items": {
                            "type": "object",
                            "$ref": "#/definitions/genericComponent"
                         },
                         "minItems": 1,
                    }
                }
            },
            "else": {
                "properties": {
                    "children":{
                        "type": "array",
                        "items": {
                            "type": "object",
                            "$ref": "#/definitions/genericComponent"
                        }
                    }
                }
            }
        }
    }
}

编辑:这个样本通过了,但它不应该因为其中一个按钮的子项数量大于 1。

{"results": [
  {
    "class": "box",
    "children": [
      {
        "class": "icon",
        "children": []
      },
      {
        "class": "button-rect",
        "children": [
          {
            "class": "label",
            "children": []
          }
        ]
      },
      {
        "class": "button-round",
        "children": [
          {
            "class": "label",
            "children": []
          },
          {
            "class": "label",
            "children": []
          }
        ]
      }
    ]
  }
]
}

您的有条件申请方法很接近,但有一些错误。

无法解析 #/definitions/button 的引用,因此您可能看到了一个错误。

您在 if 条件中使用的正则表达式用于 button-rect,而您要求它覆盖示例中的 button-round。您当然可以将其更改为非锚定 ^button-,这听起来像您想要的。

这是架构。

{
  "type": "object",
  "required": [
    "results"
  ],
  "properties": {
    "results": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "$ref": "#/definitions/genericComponent"
      }
    }
  },
  "definitions": {
    "genericComponent": {
      "type": "object",
      "$id": "#/definitions/genericComponent",
      "required": [
        "class",
        "children"
      ],
      "properties": {
        "class": {
          "type": "string"
        },
        "children": {
          "type": "array",
          "items": {
            "type": "object",
            "anyOf": [
              {
                "$ref": "#/definitions/genericComponent"
              }
            ]
          }
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "class": {
                "pattern": "^button-round$"
              }
            }
          },
          "then": {
            "properties": {
              "children": {
                "maxItems": 1
              }
            }
          }
        }
      ]
    }
  }
}

then 架构应用于实例。您不需要重复该架构的其他部分(使用 #/definitions/genericComponent$id)已经表达的约束。推而广之,您也不需要 else 。 (这与使用执行流程编写代码不同。)

您可以在 https://jsonschema.dev 查看此模式对您的 JSON 实例数据的作用(link 预加载了您的模式和数据)

如果您有任何问题,请告诉我。第一种方法存在许多问题,但鉴于这是更好的方法,我不确定 "fixing" 第一种是否在这个问题的范围内。 =]