如何制作可在另一个架构中的任何位置使用的自定义 jsonschema 关键字(词汇)?

问题描述 投票:0回答:1

我正在尝试创建一个自定义 jsonschema 关键字来进行一些基本评估。一个例子是“parallelArrays”,其中将检查提供的列表以确保它们的长度相同。

我在很大程度上成功地做到了这一点,但我最近意识到我犯了一个错误。我想在架构中使用此关键字来表示我的实际数据。为了确保我正确使用关键字,我想根据元模式验证模式本身,这将确保(除其他外)“parallelArrays”关键字在模式中格式良好。

当我在架构的顶级对象中使用自定义关键字时,此元架构验证效果很好,但当我在其他地方(例如在嵌套对象中)使用它时,它会失败。

我在下面有一个示例,其中包含自定义关键字“myKeyword”,它不执行任何操作,但必须是一个对象。请注意,下面的示例使用 jschon python 库,但我在 python-jsonschema 中观察到了同样的问题。我假设我一开始形成词汇的方式有问题,但我无法弄清楚

假设以下文件位于同一文件夹中:

meta.schema.json

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://example.com/myKeyword/meta.schema.json",
    "$vocabulary": {
      "https://json-schema.org/draft/2020-12/vocab/core": true,
      "https://json-schema.org/draft/2020-12/vocab/applicator": true,
      "https://json-schema.org/draft/2020-12/vocab/validation": true,
      "https://json-schema.org/draft/2020-12/vocab/meta-data": true,
      "https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
      "https://json-schema.org/draft/2020-12/vocab/content": true,
      "https://json-schema.org/draft/2020-12/vocab/unevaluated": true
    },
    "allOf": [
      { "$ref": "https://json-schema.org/draft/2020-12/schema" },
      { "$ref": "https://example.com/myKeyword/vocab.schema.json" }
    ]
}

vocab.schema.json

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "$id": "https://example.com/myKeyword/meta.schema.json",
    "$vocabulary": {
      "https://json-schema.org/draft/2020-12/vocab/core": true,
      "https://json-schema.org/draft/2020-12/vocab/applicator": true,
      "https://json-schema.org/draft/2020-12/vocab/validation": true,
      "https://json-schema.org/draft/2020-12/vocab/meta-data": true,
      "https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
      "https://json-schema.org/draft/2020-12/vocab/content": true,
      "https://json-schema.org/draft/2020-12/vocab/unevaluated": true
    },
    "allOf": [
      { "$ref": "https://json-schema.org/draft/2020-12/schema" },
      { "$ref": "https://example.com/myKeyword/vocab.schema.json" }
    ]
}

test.py(您需要 pip install jschon)

import os
import jschon

# This just helps jschon locate our schema files
catalog = jschon.create_catalog("2020-12")
catalog.add_uri_source(jschon.URI("https://example.com/myKeyword/"), jschon.LocalSource(os.path.dirname(__file__)))


### Test 1 ###
# myKeyword is in the top level of the schema and is an object
user_schema = jschon.JSONSchema({
  "$schema": "https://example.com/myKeyword/meta.schema.json",
  "$id": "https://example.com/mySchema",

  "type": "object",
  "myKeyword": {},
  "properties": {
    "favoriteNumber": {
      "type": "integer",
    }
  }
})

assert(user_schema.validate().valid is True) # Passes


### Test 2 ###
# myKeyword is in the top level of the schema and is NOT an object
user_schema = jschon.JSONSchema({
  "$schema": "https://example.com/myKeyword/meta.schema.json",
  "$id": "https://example.com/mySchema",

  "type": "object",
  "myKeyword": [],
  "properties": {
    "favoriteNumber": {
      "type": "integer",
    }
  }
})

assert(user_schema.validate().valid is False) # Passes


### Test 3 ###
# myKeyword is NOT in the top level of the schema and is an object
user_schema = jschon.JSONSchema({
  "$schema": "https://example.com/myKeyword/meta.schema.json",
  "$id": "https://example.com/mySchema",

  "type": "object",
  "properties": {
    "favoriteNumber": {
      "type": "integer",
      "myKeyword": {}
    }
  }
})

assert(user_schema.validate().valid is True) # Passes (but trivially, see below)


### Test 4 ###
# myKeyword is NOT in the top level of the schema and is NOT an object
user_schema = jschon.JSONSchema({
  "$schema": "https://example.com/myKeyword/meta.schema.json",
  "$id": "https://example.com/mySchema",

  "type": "object",
  "properties": {
    "favoriteNumber": {
      "type": "integer",
      "myKeyword": []
    }
  }
})

assert(user_schema.validate().valid is False) # Fails!

# Essentially, when "myKeyword" is not in the top level, it is always marked as valid because
# for some reason the vocab.schema.json is not checked. This is why Test 3 passes but I called
# it trivial.
jsonschema python-jsonschema
1个回答
0
投票

JSON 模式作者之一有一些关于这个主题的精彩博客文章。

https://blog.json-everything.net/posts/updating-vocabs/

https://docs.json-everything.net/schema/vocabs/data-2023/

查看您的架构,似乎您的词汇架构有很多不必要的定义

我相当确定这会让您到达您想要的位置。

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/myKeyword/vocab.schema.json",
  "$defs": {
    "myKeyword": {}
  },
  "title": "my keyword for parallel arrays",
  "$ref": "#/$defs/myKeyword"
}
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/schema/meta/myKeyword",
  "$dynamicAnchor": "meta",
  "$vocabulary": {
    <All core vocabs>, 
    "https://example.com/meta/myKeyword/vocab.schema.json": true
  },
  "allOf": [
    {"$ref": "https://json-schema.org/draft/2020-12/schema"},
    {"$ref": "https://example.com/myKeyword/vocab.schema.json"}]
}
© www.soinside.com 2019 - 2024. All rights reserved.