【问题标题】:How to perform JSON schema property validation based on enum value in another property如何根据另一个属性中的枚举值执行 JSON 模式属性验证
【发布时间】:2020-04-11 23:06:43
【问题描述】:

基于给定的 JSON 模式,如果我必须根据在 DayHeader 中选择的“Day”为“DayActivity”构建“必需”(例如,如果 Day 是 SUNDAY,则应该只需要 PhysicalActivity),我该如何构建JSON模式?我尝试了各种方法,例如 if then else 和定义。当我基于 JSON 模式生成 JSON 文件时,它无法验证“Day”属性选择的所需“DayActivity”。 基本上我如何引用在其他属性中选择的值并构建“必需”?感谢您对此问题的任何参考。

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "DayHeader": {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "properties": {
        "Day": {
          "type": "string",
          "enum": [
            "SUNDAY",
            "MONDAY",
            "TUESDAY",
            "WEDNESDAY",
            "THURSDAY",
            "FRIDAY",
            "SATURDAY"
          ]
        }
      },
      "required": [
        "day"
      ]
    },
    "ActivityDetail": {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "properties": {
        "DayActivity": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "PhysicalActivity": {
                "type": "string",
                "enum": [
                  "Walking",
                  "Running"
                ]
              },
              "StudyActivity": {
                "type": "string",
                "enum": [
                  "Maths Class",
                  "Science Class"
                ]
              },
              "ArtActivity": {
                "type": "string",
                "enum": [
                  "Drawing",
                  "Dance"
                ]
              }
            }
          }
        }
      }
    }
  }
}

【问题讨论】:

  • 您能否提供一个您希望验证失败的示例 JSON 实例?那会让事情变得容易一些。另外:小心外壳。您在DayHeader 上定义了两个属性:“Day”和“day”(通过“required”)。 DayActivity 也是“必需的”并且“minItems”为 1 吗?只是将PhysicalActivity 设为“必需”似乎会留下很多漏洞,因此仍然可以忽略它。这是故意的,还是你没有得到你想要的结果的原因。 if/then 听起来是正确的方法。也许在这里也包括你的尝试。
  • 您不需要(也不应该)在架构根以外的任何级别重新定义$schema
  • 这能回答你的问题吗? JSON Schema - conditional validation
  • @Carsten DayActivity 需要将 minItems 设为 1。
  • @Relequestual 感谢分享。我会尝试一下并更新这个帖子。

标签: json jsonschema


【解决方案1】:

一般来说,这个问题已经有了一个很棒的通用答案here

话虽如此,您也许可以改进 "DayActivity" 方面的数据结构,这也将更容易制定相应的 JSON Schema。


您的"DayActivity" 当前是一个对象数组,每个对象最多同时包含三个属性:"PhysicalActivity"/"StudyActivity"/"ArtActivity"。像下面这样的东西怎么样,它只允许三个属性之一出现在单个数组项中:

"DayActivity": {
  "type": "array",
  "minItems": 1,
  "items": {
    "type": "object",
    "oneOf": [
      {
        "properties": {
          "PhysicalActivity": {
            "type": "string",
            "enum": ["Walking", "Running"]
          }
        },
        "required": ["PhysicalActivity"]
      },
      {
        "properties": {
          "StudyActivity": {
            "type": "string",
            "enum": ["Maths Class", "Science Class"]
          }
        },
        "required": ["StudyActivity"]
      },
      {
        "properties": {
          "ArtActivity": {
            "type": "string",
            "enum": ["Drawing", "Dance"]
          }
        },
        "required": ["ArtActivity"]
      }
    ]
  },
  "contains": {
    "required": ["PhysicalActivity"]
  }
}

注意最后的"contains" 关键字,以确保"DayActivity" 数组中始终需要至少有一个"PhysicalActivity" 条目。

如果您现在想在每个工作日有条件地强制执行 "StudyActivity""SUNDAY",您可以在主架构中添加以下内容(即在声明 "properties": { "DayHeader": ... } 的顶层:

"oneOf": [
  {
    "properties": {
      "DayHeader": {
        "properties": {
          "Day": {
            "const": "SUNDAY"
          }
        }
      }
    }
  },
  {
    "properties": {
      "DayHeader": {
        "properties": {
          "Day": {
            "enum": [
              "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"
            ]
          }
        }
      },
      "ActivityDetail": {
        "properties": {
          "DayActivity": {
            "contains": {
              "required": ["StudyActivity"]
            }
          }
        }
      }
    }
  }
]

一个完整的架构可能看起来像这样:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["DayHeader", "ActivityDetail"],
  "properties": {
    "DayHeader": {
      "type": "object",
      "properties": {
        "Day": {
          "type": "string",
          "enum": [
            "SUNDAY",
            "MONDAY",
            "TUESDAY",
            "WEDNESDAY",
            "THURSDAY",
            "FRIDAY",
            "SATURDAY"
          ]
        }
      },
      "required": [
        "Day"
      ]
    },
    "ActivityDetail": {
      "type": "object",
      "required": ["DayActivity"],
      "properties": {
        "DayActivity": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "oneOf": [
              {
                "properties": {
                  "PhysicalActivity": {
                    "type": "string",
                    "enum": ["Walking", "Running"]
                  }
                },
                "required": ["PhysicalActivity"]
              },
              {
                "properties": {
                  "StudyActivity": {
                    "type": "string",
                    "enum": ["Maths Class", "Science Class"]
                  }
                },
                "required": ["StudyActivity"]
              },
              {
                "properties": {
                  "ArtActivity": {
                    "type": "string",
                    "enum": ["Drawing", "Dance"]
                  }
                },
                "required": ["ArtActivity"]
              }
            ]
          },
          "contains": {
            "required": ["PhysicalActivity"]
          }
        }
      }
    }
  },
  "oneOf": [
    {
      "properties": {
        "DayHeader": {
          "properties": {
            "Day": {
              "const": "SUNDAY"
            }
          }
        }
      }
    },
    {
      "properties": {
        "DayHeader": {
          "properties": {
            "Day": {
              "enum": [
                "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY"
              ]
            }
          }
        },
        "ActivityDetail": {
          "properties": {
            "DayActivity": {
              "contains": {
                "required": ["StudyActivity"]
              }
            }
          }
        }
      }
    }
  ]
}

以上成功验证:

{
  "DayHeader": { "Day": "SUNDAY"},
  "ActivityDetail": {
    "DayActivity": [
      { "PhysicalActivity": "Walking" }
    ]
  }
}

但不反对以下内容(因为缺少"StudyActivity"

{
  "DayHeader": { "Day": "WEDNESDAY"},
  "ActivityDetail": {
    "DayActivity": [
      { "PhysicalActivity": "Walking" }
    ]
  }
}

【讨论】:

  • 谢谢。我会检查这个。现在,我通过输入 JSON 模式并生成输出来使用“json-schema-faker.js.org”,发现它没有正确生成。看起来我需要构建一个 JSON 模式验证器类并传递 json 和模式来验证。我会检查一下。如果可能,请告诉我您是如何验证它的。
  • 谢谢。我转换为 IF-else 结构,因为我必须根据 Day 标题添加条件,并且对于更多属性,例如 DayActivity 是此处列出的示例之一。我认为在“DayActivity”中使用 if-else 会更容易理解架构。我用 if-else 重建了它。请找到我更新的一个。如果我更改 DayHeader,它不会根据 DayHeader 验证 DayActivity。
  • @Sahank 我的意思是在您的问题底部添加您更改的架构 - 而不是我的答案。不过,我查看了您建议的编辑。你改错了oneOf。对于这些if/then 子句,您应该关注顶级架构中的oneOf(答案中我的示例底部的那个)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-11
  • 1970-01-01
  • 2021-08-08
  • 1970-01-01
相关资源
最近更新 更多