基于动态属性值的条件JSON模式

时间:2019-07-17 12:52:34

标签: json jsonschema

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

我提供的代码是我尝试过的。为简单起见,我排除了icons-。如您所见,只要button中有class,我就会尝试与正则表达式匹配。然后,应将子元素的最小值限制为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": []
          }
        ]
      }
    ]
  }
]
}

1 个答案:

答案 0 :(得分:0)

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

无法解析对#/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模式应用于实例。您无需重复该模式的另一部分(用$id的{​​{1}}表示的约束)。通过扩展,您也不需要#/definitions/genericComponent。 (这与通过执行流程编写代码不同。)

您可以在https://jsonschema.dev看到针对您的JSON实例数据的该模式(链接已预加载了您的模式和数据)

如果您有任何疑问,请告诉我。第一种方法存在很多问题,但是鉴于这是更好的方法,因此我不确定“修复”第一种方法是否属于该问题。 =]