【问题标题】:JSON schema validation of conditional array objects条件数组对象的 JSON 模式验证
【发布时间】:2020-07-28 03:18:03
【问题描述】:

我有两种类型的数据集,即 csv 或固定长度数据。在 csv 数据中,字段列表只是一个名称列表, 而在固定长度数据中,每个字段由 fieldName 和 fieldLength 指定。 我需要一个 json 模式来验证这两种情况,但在尝试了几种解决方案之后,包括 these,我不确定可以做到。或者我对 JSON 模式的理解还不够完善。

json:

{
      "dataset": "csv data",
      "dataFormat": "csv",
      "fieldList": [{
                  "fieldName": "id"
            },
            {
                  "fieldName": "num"
            },
            {
                  "fieldName": "struct"
            }
      ]
}

{
    "dataset": "fixed length",
    "dataFormat": "fixed",
    "fieldList": [{
            "fieldName": "id",
            "fieldLength": 13
        },
        {
            "fieldName": "num"
        },
        {
            "fieldName": "struct"
        }
    ]
}

JSON 架构:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [
    "dataset",
    "dataFormat",
    "fieldList"
  ],
  "properties": {
    "dataset": {
      "$id": "#/properties/dataset",
      "type": "string"
    },
    "dataFormat": {
      "$id": "#/properties/dataFormat",
      "type": "string",
      "enum": [
        "csv",
        "fixed"
      ]
    },
    "fieldList": {
      "$id": "#/properties/fieldList",
      "type": "array",
      "additionalItems": true,
      "items": {
        "$id": "#/properties/fieldList/items",
        "type": "object",
        "additionalProperties": true,
        "required": [
          "fieldName"
        ],
        "if": {
          "properties": {
            "dataFormat": {
              "const": "fixed"
            }
          }
        },
        "then": {"items":{
          "required": [
            "fieldLength"
          ]}
        },
        "properties": {
          "fieldName": {
            "$id": "#/properties/fieldList/items/properties/fieldName",
            "type": "string"
          },
          "fieldLength": {
            "$id": "#/properties/fieldList/items/properties/fieldLength",
            "type": "integer"
          }
        }
      }
    }
  }
}

两个文档都经过了肯定验证,即使在“固定”类型中只有第一项包含所需的字段长度。 有什么建议吗?

【问题讨论】:

    标签: json schema jsonschema


    【解决方案1】:

    您的架构中有一些可以改进的地方:

    1. if/then 放错了位置。现在,if"fieldList" items 中查找"dataFormat" 属性,但从未找到。 then 同样试图强制在"fieldList".items.items 中存在"fieldLength" 属性(并且由于"fieldList".itemsobject 而不是array,这将被简单地忽略。
    2. 您应该删除additionalItems 属性。引用json-schema.org

      items 为单一模式时,additionalItems 关键字无意义,不宜使用。

    3. 您可以删除additionalProperties 属性,因为它的默认值已经是true。来自json-schema.org 的另一句话:

      additionalProperties 关键字用于控制额外内容的处理,即properties,其名称未在属性关键字中列出。默认情况下允许任何其他属性。

    4. $id 属性没有增加太多价值(并且与较新的 2019-09 草案不兼容,它们只能在新的 $anchor 关键字中使用)。您可能想省略这些。

    您的主要问题是这里的第 1 点。 您应该能够通过在顶层添加类似的内容来实现您想要的:

    "oneOf": [
      {
        "properties": {
          "dataFormat": { "const": "csv" }
        }
      },
      {
        "properties": {
          "dataFormat": { "const": "fixed" },
          "fieldList": {
            "items": {
              "required": ["fieldLength"]
            }
          }
        }
      }
    ]
    

    完整的架构可能如下所示:

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "type": "object",
      "required": [
        "dataset",
        "dataFormat",
        "fieldList"
      ],
      "properties": {
        "dataset": {
          "$id": "#/properties/dataset",
          "type": "string"
        },
        "dataFormat": {
          "$id": "#/properties/dataFormat",
          "type": "string",
          "enum": [
            "csv",
            "fixed"
          ]
        },
        "fieldList": {
          "$id": "#/properties/fieldList",
          "type": "array",
          "items": {
            "$id": "#/properties/fieldList/items",
            "type": "object",
            "required": [
              "fieldName"
            ],
            "properties": {
              "fieldName": {
                "$id": "#/properties/fieldList/items/properties/fieldName",
                "type": "string"
              },
              "fieldLength": {
                "$id": "#/properties/fieldList/items/properties/fieldLength",
                "type": "integer"
              }
            }
          }
        }
      },
      "oneOf": [
        {
          "properties": {
            "dataFormat": {
              "const": "csv"
            }
          }
        },
        {
          "properties": {
            "dataFormat": {
              "const": "fixed"
            },
            "fieldList": {
              "items": {
                "required": [
                  "fieldLength"
                ]
              }
            }
          }
        }
      ]
    }
    

    为了完整起见:您也可以使用 if/then 实现相同的效果:

    "if": {
      "properties": {
        "dataFormat": {
          "const": "fixed"
        }
      }
    },
    "then": {
      "properties": {
        "fieldList": {
          "items": {
            "required": [
              "fieldLength"
            ]
          }
        }
      }
    }
    

    【讨论】:

    • 谢谢,您的解决方案运行良好!不幸的是,我的用例比我的问题中的用例复杂一点:数据集是一个数组,每个项目都有自己的字段列表。我试图通过在字段列表之前添加数据集/项目来调整您的“oneOf”解决方案,但没有成功......
    • @mre 可能会通过编辑将其添加到您的问题底部,我也可以尝试为您提供帮助
    • @mre 你必须在fieldList 之前添加dataset/items/properties。不要忘记最后一个properties
    • 再次感谢@Carsten,最后一个properties 成功了,现在一切正常!!!
    猜你喜欢
    • 2020-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    • 2017-10-23
    • 2015-10-24
    • 1970-01-01
    • 2018-03-20
    相关资源
    最近更新 更多