如何声明嵌套属性的依赖关系?

时间:2018-03-14 19:10:00

标签: node.js jsonschema ajv

我正在使用JSON Schema的Draft-04。是否可以根据子属性的存在来设置依赖关系,和/或依赖于子属性?或者我被迫使用allOf来管理这些类型的依赖项?

我有以下内容(您可以在https://repl.it/@neverendingqs/JsonSchemaNestedDependencies播放):

'use strict';

const Ajv = require('ajv');
const assert = require('chai').assert;

// Using ajv@5.5.1
const draft4 = require('ajv/lib/refs/json-schema-draft-04.json');

const schema = {
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "foo1": {
      "type": [ "object" ],
      "properties": {
        "bar1": { "type": "string" }
      }
    },
    "foo2": {
      "type": [ "object" ],
      "properties": {
        "bar2": { "type": "string" }
      }
    }
  },
  "dependencies": {
    "foo1": ["foo2"],

    // Is this possible?
    "foo1/bar1": ["foo2/bar2"]
  }
};

const schemaName = 'my-schema';

const ajv = new Ajv();
ajv.addMetaSchema(draft4);
ajv.addSchema(schema, schemaName);


assert.isTrue(
  ajv.validate(schemaName, {
    "foo1": { "bar1": "a" },
    "foo2": { "bar2": "c" }
  }),
  ajv.errorsText(ajv.errors, { dataVar: 'event' })
);

assert.isFalse(ajv.validate(schemaName, {
  "foo1": { "bar1": "a" }
}));

// Looking to cause this to pass
assert.isFalse(ajv.validate(schemaName, {
  "foo1": { "bar1": "a" },
  "foo2": {}
}));

我正在寻找Draft-04的答案,但我也对使用后期规范的答案感兴趣。

编辑: Draft-04 是指http://json-schema.org/specification-links.html#draft-4下的规范。具体来说,我使用的是dependencies,它是在验证规范(https://tools.ietf.org/html/draft-fge-json-schema-validation-00

下定义的

2 个答案:

答案 0 :(得分:0)

在草案4中实现这一点非常棘手! 您可以在草稿4中使用required来创建对象中所需的属性...

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "foo1": {
      "type": [ "object" ],
      "properties": {
        "bar1": { "type": "string" }
      }
    },
    "foo2": {
      "type": [ "object" ],
      "properties": {
        "bar2": { "type": "string" }
      },
      "required": [ "bar2" ]
    }
  }
}

我无法在repl.it中重新运行此更改,但我使用https://www.jsonschemavalidator.net

针对您要失败的架构进行了检查

对于draft-7(在撰写本文时最新),您可以使用ifthenelse,这可能更直观,但我认为你' d仍然需要使用required来实现这一点,因为您希望if中的子模式通过或失败。 Keywords for Applying Subschemas Conditionally

答案 1 :(得分:0)

如果dependencies支持JSON指针会很好,但事实并非如此。你必须用暗示来解决这个问题。我已经使用definitions将其分解,以帮助更清楚地了解正在发生的事情。

首先,我为我们要检查的案例定义模式:/foo1/bar1存在且/foo2/bar2存在。根据这两个定义,我使用anyOf表示/foo1/bar1不存在,或者/foo2/bar2是必需的。换句话说,/foo1/bar1暗示/foo2/bar2

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "foo1": {
      "type": [ "object" ],
      "properties": {
        "bar1": { "type": "string" }
      }
    },
    "foo2": {
      "type": [ "object" ],
      "properties": {
        "bar2": { "type": "string" }
      }
    }
  },
  "allOf": [{ "$ref": "#/definitions/foo1-bar1-implies-foo2-bar2" }],
  "dependencies": {
    "foo1": ["foo2"]
  },
  "definitions": {
    "foo1-bar1-implies-foo2-bar2": {
      "anyOf": [
        { "not": { "$ref": "#/definitions/foo1-bar1" } },
        { "$ref": "#/definitions/foo2-bar2" }
      ]
    },
    "foo1-bar1": {
      "properties": {
        "foo1": { "required": ["bar1"] }
      },
      "required": ["foo1"]
    },
    "foo2-bar2": {
      "properties": {
        "foo2": { "required": ["bar2"] }
      },
      "required": ["foo2"]
    }
  }
}