如何指定 属性 不应该存在或包含 null?

How to specify if a property should not exist or contain null?

一年前我曾问过 ,我得到了很好的答案,从那以后我就一直在使用该架构。

现在源数据已更改 - 架构在以下情况下失败:

源数据包含许多属性,但其中只有两个与此问题相关:"key" 和 "value" - "value" 的类型取决于 "key"-

例如:
如果key是"comment",value的类型是{"Text":"commentValue"}.
如果key是"offset",那么value的类型就是{"seconds":int}.
如果key是"weather",那么value的类型就是{"value": Enum["sun", "clouds", "rain"...]}

一些键没有值 属性,因此模式应该禁止它与这些键一起出现 - 例如,如果键是 "standby",则值 属性 根本不应该出现——这就是我当前的架构做得很好的地方。

但是,现在数据源已经改变,我得到 "value" :{} 作为我的 Json 的一部分,它曾经被省略 - 而当前的模式不允许它。

所以我的问题是 - 如何允许这两个选项之一?我尝试了我能想到的 anyOf 的任意组合,但惨败 - Newtonsoft.Json.Schema.JSchema 无法解析文本。

这是我当前使用的架构的简化版本:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "TestOptionalObject",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "test"
  ],
  "properties": {
    "test": {
      "$ref": "#/definitions/test"
    }
  },
  "definitions": {
    "test": {
      "type": "object",
      "required": [
        "key"
      ],
      "properties": {
        "key": {
          "type": "string",
          "enum": [
            "comment",
            "offset",
            "standby",
            "status_unsure",
            "status_ok"
          ]
        }
      },
      "allOf": [
        {
          "if": {
            "properties": {
              "event": {
                "enum": [
                  "standby",
                  "status_unsure",
                  "status_ok"
                ]
              }
            }
          },
          "then": {
            "properties": {
              "value": false
            }
          }
        },
        {
          "if": {
            "properties": {
              "key": {
                "const": "comment"
              }
            }
          },
          "then": {
            "properties": {
              "value": {
                "$ref": "#/definitions/commentValue"
              }
            }
          }
        },
        {
          "if": {
            "properties": {
              "key": {
                "const": "offset"
              }
            }
          },
          "then": {
            "properties": {
              "value": {
                "$ref": "#/definitions/offsetValue"
              }
            }
          }
        }
      ]
    },
    "commentValue": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "text"
      ],
      "properties": {
        "text": {
          "type": "string"
        }
      }
    },
    "offsetValue": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "seconds"
      ],
      "properties": {
        "seconds": {
          "type": "integer",
          "format": "int32"
        }
      }
    }
  }
}

以下是我尝试过的一些方法:

"then": {
  "properties": {
    "anyOf": [
      { "value": false },
      { "value": null }
    ]
  }
}
"then": {
  "anyOf": [
  {
    "properties": {
      { "value": false }
    },
    "properties": {
      { "value": null }
    }
  ]  
}
"then": {
  "properties": {
    "value": 
      "anyOf": [false, null ]
  }
}

Json 个验证示例:

应该失败:

{
  "test": {
    "key": "comment",
      "value": {"seconds":12}
  }
}

{
  "test": {
    "key": "standby",
     "value": {"asdf":12}
  }
}

应该通过:

{
  "test": {
    "key": "comment",
     "value": {"text":"comment text"}
  }
}


{
  "test": {
    "key": "offset",
     "value": {"seconds":12}
  }
}

{
  "test": {
    "key": "standby"
  }
}

{
  "test": {
    "key": "standby",
     "value": {}
  }
}

请注意最后一个示例 - value 属性 是一个空对象 - 它也应该通过但在当前架构中失败,因为 value 属性 不应该对于这个键根本不存在。

你很接近,但不完全是。您必须记住 allOf 是一个子模式数组(JSON 模式)。 (Null 不是有效的架构,因此您可能遇到了一些 "not a valid schema" 错误。)

因此,考虑来自 allOf[0]...

的修改后的子模式
{
  "if": {
    "properties": {
      "key": {
        "enum": [
          "standby",
          "status_unsure",
          "status_ok"
        ]
      }
    }
  },
  "then": {
    "properties": {
      "value": {
        "type": [
          "object"
        ],
        "additionalProperties": false
      }
    }
  }
}

你可以在这里测试:https://jsonschema.dev/s/EfNI1

if块保持不变。 (虽然我已经更正了我认为在您从真实模式简化中使用 event 而不是 key 的错误。)

then块需要定义对象(已被definitions.test检查)有一个键value,其中value的值是一个对象,并且没有属性(又名空对象)。

要达到 "an empty object",您需要使用 additionalProperties

  • additionalProperties 将其值子模式应用于 properties 中未定义的所有属性或与 patternProperties.[=47= 中的键(正则表达式)匹配的所有属性]
  • false 作为模式总是无法通过验证。
没有 properites

additionalProperties 适用于所有属性,因此值为 false,验证 "is an empty object".