Json 使用 javascript 针对 Json 对象进行模式验证

Json schema validation against Json Object using javascript

我正在尝试根据 JSON 架构验证大约 100 JSON 个对象,以查看所有字段以及类型是否符合架构。

尝试了以下 JSON 从站点生成的架构。 以下架构的问题在于它不支持验证“文件”字段的多个项目,因为架构不完全正确。

添加到架构下方

     var schema ={
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "properties": {
        "contents": {
          "type": "array",
          "items": [
            {
              "type": "object",
              "properties": {
                "version": {
                  "type": "string"
                },
                "sequence": {
                  "type": "integer"
                },
                "files": {
                  "type": "array",
                  "items": [
                    {
                      "type": "object",
                      "properties": {
                        "fileName": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "fileSize": {
                          "type": "string"
                        },
                        "fileType": {
                          "type": "string"
                        },
                        "lastUpdatedDate": {
                          "type": "integer"
                        },
                        "fileLength": {
                          "type": "integer"
                        },
                        "version": {
                          "type": "integer"
                        }
                      },
                      "required": [
                        "fileName",
                        "name",
                        "fileSize",
                        "fileType",
                        "lastUpdatedDate",
                        "fileLength",
                        "version"
                      ]
                    }
                  ]
                }
              },
              "required": [
                "version",
                "sequence",
                "files"
              ]
            }
          ]
        }
      },
      "required": [
        "contents"
      ]
    }
  },
  "required": [
    "data"
  ]
}

  var validator = new Validator(schema)

  var json=
  {
      "data": {
          "contents": [
              {
                  "versionn": "2021-01-15T16:01:13.475Z",
                  "sequence": 1,
                  "files": [
                      {
                          "fileName": "us-producer-price-index.txt",
                          "name": "us-producer-price-index",
                          "fileSize": "54MB",
                          "fileType": "txt",
                          "lastUpdatedDate": 1610717473000,
                          "fileLength": 56614933,
                          "version": 2
                      }
                  ]
              }
          ]
      }
  };

  var check = validator.check(json);
   
  console.log(check);

  if(check._error==true)
  {
      console.log("Error in schema")
  }

虽然您的 JSON 模式是“有效的”,但它没有表达任何约束。

您错过了使用 properties 关键字的必要性。

The value of "properties" MUST be an object. Each value of this
object MUST be a valid JSON Schema.

Validation succeeds if, for each name that appears in both the
instance and as a name within this keyword's value, the child
instance for that name successfully validates against the
corresponding schema.

https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-02#section-9.3.2.1

为了将子模式应用于对象,您需要使用 properties 关键字。像这样...

{
  "required": ["data"],
  "properties": {
    "data": {
      "type": "object"
    }
  }
}

此要求也适用于每个子架构。未知关键字被忽略,因此模式根部的 data 被简单地忽略,导致没有表达约束。

您可能会发现查看 JSON 模式入门指南很有帮助:http://json-schema.org/learn/


更新: 在以答案的形式对您的问题添加更新后,看起来生成器几乎是正确的,但又不完全正确。

在 2020-12 草案前使用 items 关键字时,数组值仅将子模式项应用于相同的索引位置。如果您希望子模式值应用于适用数组中的所有项目,您需要使用模式对象作为值而不是模式值数组。

The value of "items" MUST be either a valid JSON Schema or an array
of valid JSON Schemas.

If "items" is a schema, validation succeeds if all elements in the array successfully validate against that schema.

If "items" is an array of schemas, validation succeeds if each
element of the instance validates against the schema at the same
position, if any.

JSON 架构草案 2019-09 - https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-02#section-9.3.1.1

请参阅上面链接的入门指南,其中涵盖了这一点。如果您希望维护您的架构,那将值得一读。

我假设您想要的是对数组中的所有项目应用相同的验证规则。

架构提供list validation and tuple validationlist 验证指定为 a schema,对数组中的任何项目应用相同的规则,tuple 被指定为 模式数组 并根据 schema.item[i].

验证 item[i]

请注意,您的 items 模式是一个元素的数组。这意味着只有第一个元素根据您的架构进行验证。我假设你想要的是这个模式。

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "properties": {
        "contents": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "version": {
                "type": "string"
              },
              "sequence": {
                "type": "integer"
              },
              "files": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "fileName": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "fileSize": {
                      "type": "string"
                    },
                    "fileType": {
                      "type": "string"
                    },
                    "lastUpdatedDate": {
                      "type": "integer"
                    },
                    "fileLength": {
                      "type": "integer"
                    },
                    "version": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "fileName",
                    "name",
                    "fileSize",
                    "fileType",
                    "lastUpdatedDate",
                    "fileLength",
                    "version"
                  ]
                }
              }
            },
            "required": [
              "version",
              "sequence",
              "files"
            ]
          }
        }
      },
      "required": [
        "contents"
      ]
    }
  },
  "required": [
    "data"
  ]
}

更多示例

为了说明数组验证的工作原理,我创建了一个非常有启发性的片段。

const Ajv = window.ajv7.default;
const ajv = new Ajv({strict: false});

function dumpJson(item){
  const el = document.createElement('pre');
  el.textContent = typeof(item) === 'string' ? item :  JSON.stringify(item)
  document.body.appendChild(el);
  return el;
}

function Test(schema, title){
  const validate = ajv.compile(schema)
  if(title)dumpJson(title).classList.add('title')
  dumpJson(JSON.stringify(schema, null, 2))
  const tester = {
    with: (item) => {
      const el = dumpJson(item)
      if(validate(item)){
        el.classList.add('valid');
      }else{
        el.classList.add('invalid');
      }
      return tester
    }
  }
  return tester;
}

Test({
  "$schema": "http://json-schema.org/draft-07/schema#",
  type: 'array', items: [{type: 'number'}, {type: 'string'}]
}, 'tuple validation: [number]')
.with([0])
.with([0, 1])
.with([0, "a"])
.with([0, "a", {}, [], null, false, true])
Test({
  "$schema": "http://json-schema.org/draft-07/schema#",
  type: 'array', items: [{type: 'number'}]
}, 'tuple validation: [number, string]')
.with([0])
.with([0, 1])
.with([0, "a"])
.with([0, "a", {}, [], null, false, true])

Test({
  "$schema": "http://json-schema.org/draft-07/schema#",
  type: 'array', items: {type: 'number'}
}, 'list validation: number[]')
.with([0])
.with([0, 1])
.with([0, "a"])
.with([0, "a", {}, [], null, false, true])


Test({
  "$schema": "http://json-schema.org/draft-07/schema#",
  type: 'array', items: [{type: 'number'}, {type: 'string'}]
}, 'tuple validation: [number, string]')
.with([0])
.with([0, 1])
.with([0, "a"])
.with([0, "a", {}, [], null, false, true])

Test({
  "$schema": "http://json-schema.org/draft-07/schema#",
  type: 'array', items: {'anyOf': [{type: 'number'}, {type: 'string'}]}
}, 'list validation: (number|string)[]')
.with([0])
.with([0, 1])
.with([0, "a"])
.with([0, "a", {}, [], null, false, true])
.with(['a', 'b', 'c'])
.with(['a', 0])
.with(['a', 0, false])
.valid {
  margin-left: 20px; color: green;
}
.invalid {
  margin-left: 20px; color: red;
}
.title {
  font-size: 2em;
}

body: {
  overflow: scroll;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/7.1.1/ajv7.min.js"></script>