3

我正在使用 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://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00)下定义的

4

2 回答 2

1

如果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"]
    }
  }
}
于 2018-03-16T02:43:49.917 回答
0

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

{
  "$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(在撰写本文时是最新的),您可以使用if, then, else,这可能更直观,但我认为您仍然需要使用required来实现这一点,因为您希望子模式if通过或失败。有条件地应用子模式的关键字

于 2018-03-15T09:25:47.333 回答