Json 架构在 if 条件下添加 属性

Json schema add property on if condition

在 JSON 架构中,我想添加一个验证,如果负载匹配以下

{
   "key1": "value1", 
   "key1": "value2"
}

然后期待具有任何值的第三个键“key3”。

但如果 key1 和 key2 的值​​分别与 value1、value2 不匹配,则 key3 不应该存在。

JSON 架构如下所示

{
  "$async": true,
  "additionalProperties": false,
  "properties": {
    "key1": {
      "type": "string"
    }, 
    "key2": {
      "type": "string"
    }
  },
  "required": ["key1"],
  "allOf": [
    {
      "if": {
        "properties": {
          "key1": {
            "const": "value1"
          }, 
          "key2": {
            "const": "value2"
          }
        }
      },
      "then": {
        "properties": {
          "key3": {
            "type": "string"
          }
        },
        "required": ["key3"]
      },
      "else": {
      }
    }
  ]
}

有效输入是

{
   "key1": "value1", 
   "key2": "value2", 
   "key3": "some-value"
}
--------
{
    "key1": "value1", 
    "key2": "other-value"
}
---------
{
    "key1": "value1"
}
---------
{
    "key1": "other-value", 
    "key2": "value2"
}
---------
{
    "key1": "other-value1", 
    "key2": "other-value2"
}

无效输入是

{
   "key1": "value1", 
   "key2": "value2".   // key3 should be present
}
--------
{
   "key1": "hello", 
   "key2": "world",  
   "unexpected-key": "value"   // Any other key should not be allowed 
}
--------
{
    "key1": "value1", 
    "key2": "other-value", 
    "key3": "abc"    // should not be present
 
}
---------
{
    "key1": "other-value", 
    "key2": "value2",
    "key3": "abc"    // should not be present
}
---------
{
    "key1": "other-value1", 
    "key2": "other-value2",
    "key3": "abc"    // should not be present
}

对于以下负载,JSON schema validator

{
  "key1": "value1", 
  "key2": "value2", 
  "key3": "abc"
}

抛出以下错误

Property 'key3' has not been defined and the schema does not allow additional properties.

如何实现这个条件属性?

解决方案取决于您能够使用 JSON 架构的哪个版本(或“草稿”)。 Draft 2019-09 或更高版本提供了更简洁的解决方案,但在 draft-07 中仍然可行。

(在if/then/else之前也可以用implication method介绍,不过今天不讲了。

使用 2019-09 或 2020-12 的最佳解决方案。

unevaluatedProperties关键字可以“看穿”涂抹器关键字,如allOfifelse

与 draft-07 的 additionalProperties 不同,unevaluatedProperties 在架构架构对象中的所有其他应用程序之后 运行,并且可以知道在中定义的已成功验证的 属性 值更深的嵌套涂抹器。

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "unevaluatedProperties": false,
  "properties": {
    "key1": {
      "type": "string"
    },
    "key2": {
      "type": "string"
    }
  },
  "required": [
    "key1"
  ],
  "allOf": [
    {
      "if": {
        "required": ["key2"],
        "properties": {
          "key1": {
            "const": "value1"
          },
          "key2": {
            "const": "value2"
          }
        }
      },
      "then": {
        "required": ["key3"],
        "properties": {
          "key3": {
            "type": "string"
          }
        }
      }
    }
  ]
}

对于 2019-09 及更高版本的测试草案,我建议使用 https://json-schema.hyperjump.io playground

https://jsonschema.dev 尚不支持 2019-09 及以上草案)。

使用 draft-07 的解决方案。

要使 additionalProperties: false 正常工作,它需要在 properties(或匹配 patternProperties)中的同一架构对象中定义属性。

在第一个实例中,您不关心具体值,properties对象中的值就是true。稍后处理值验证。如果你觉得它更干净,你可以把它移到顶层。

通过此更改,我们的 if/then 从您的示例开始工作,除了它没有阻止 key3 应该阻止的情况。我们通过在 else.

中使用 not 来解决这个问题
{
  "$schema": "http://json-schema.org/draft-07/schema",
  "additionalProperties": false,
  "properties": {
    "key1": {
      "type": "string"
    }, 
    "key2": {
      "type": "string"
    },
    "key3": true
  },
  "required": ["key1"],
  "allOf": [
    {
      "if": {
        "required": ["key2"],
        "properties": {
          "key1": {
            "const": "value1"
          }, 
          "key2": {
            "const": "value2"
          }
        }
      },
      "then": {
        "required": ["key3"],
        "properties": {
          "key3": {
            "type": "string"
          }
        }
      },
      "else": {
        "not": {
          "required": ["key3"]
        }
      }
    }
  ]
}

演示:https://jsonschema.dev/s/ZTi4X