首页 > 解决方案 > 有条件地合并 JSON 模式属性

问题描述

我正在尝试创建一个 JSON 模式来为某些 VSCode 智能感知验证 YAML。我要做的是根据相邻键的值选择正确的子模式以用于主模式中的属性。

一些 JSON 示例:

[
  {
    "name": "doesntmatter",
    "matchMe": "stringToMatch:123whatever",
    "mergeMe": {
        "key1": "value1",
        "key2": "value2"
    }
  }
]
[
  {
    "name": "doesntmatter",
    "matchMe": "anotherStringToMatch:123whatever",
    "mergeMe": {
        "anotherKey": "valueSomething",
        "anotherKey2": "cheese"
    }
  }
]

所以我需要mergeMe根据matchMe. 在遵循了一堆答案之后,我可以让它匹配多个,并错误我的 linter,或者不匹配,但是在线验证器说没关系(除了没有匹配的required字段没有触发) .

我移动了要合并的子模式以definitions引用它们,然后使用 if/then 进行匹配。这适用于一个,但后来我尝试扩展它以进行树匹配,但我无法让它工作。有人说我应该将我的 if/thens 包装在一个中allOf(我不确定为什么这会起作用,因为肯定不是所有的都匹配?)。将其更改为 ananyOf会使它们都不匹配,并且我没有智能感知。我也不明白为什么我应该在allOfs 中包装单个 if/thens 或 thens。

这个想法是基于模式,它使用definitions模式来匹配mergeMe属性,但条件逻辑并不完全正确。下面的细化架构:

{
    "$schema": "http://json-schema.org/draft-07/schema",
    "$id": "http://example.com/example.json",
    "type": "array",
    "title": "The root schema",
    "description": "The root schema comprises the entire JSON document.",
    "default": [],
    "additionalItems": true,
    "definitions": {
        "stringToMatch": {
            "$id": "#/definitions/stringToMatch",
            "type": "object",
            "properties": {
                "key1": {
                    "type": "string"
                }
            },
            "required": [
                "key1"
            ],
            "additionalProperties": true
        },
        "anotherStringToMatch": {
            "$id": "#/definitions/anotherStringToMatch",
            "type": "object",
            "properties": {
                "key2": {
                    "type": "string"
                }
            },
            "required": [
                "key2"
            ],
            "additionalProperties": true
        }
    },
    "items": {
        "$id": "#/items",
        "type": "object",
        "title": "main schema",
        "description": "An explanation about the purpose of this instance.",
        "default": {},
        "examples": [],
        "required": [
            "name",
            "matchMe",
            "mergeMe"
        ],
        "properties": {
            "name": {
                "$id": "#/items/name",
                "type": "string",
                "title": "The name schema",
                "description": "An explanation about the purpose of this instance.",
                "default": "",
                "examples": []
            },
            "matchMe": {
                "$id": "#/items/matchMe",
                "type": "string",
                "title": "The matchMe schema",
                "description": "An explanation about the purpose of this instance.",
                "default": "",
                "examples": []
            }
        },
        "allOf": [
            {
                "if": {
                    "properties": {
                        "matchMe": {
                            "pattern": "^stringToMatch:[0-9.]+"
                        }
                    }
                },
                "then": {
                    "allOf": [
                        {
                            "type": "object",
                            "properties": {
                                "mergeMe": {
                                    "$ref": "#/definitions/stringToMatch"
                                }
                            }
                        }
                    ]
                }
            },
            {
                "if": {
                    "properties": {
                        "gear": {
                            "pattern": "^anotherStringToMatch:[0-9.]+"
                        }
                    }
                },
                "then": {
                    "allOf": [
                        {
                            "type": "object",
                            "properties": {
                                "mergeMe": {
                                    "$ref": "#/definitions/anotherStringToMatch"
                                }
                            }
                        }
                    ]
                }
            }
        ],
        "additionalProperties": true
    }
}

我想要的 JS 看起来像

const schema = { name, matchMe }
if (matchMe == "string1") schema.mergeMe = ...subschema1;
else if (...)
else if (...)

但我真的无法解决。有人可以帮忙吗?

编辑:jsonschema.dev 操场 - 如果我将食物指定为以“水果”为前缀,我必须给它“pips”和“berry”,而如果我指定“vegetable”,我必须给它一个完全不同的模式,并且它们不重叠。 https://jsonschema.dev/s/pHzGo

标签: jsonintellisensejsonschemajson-schema-validator

解决方案


这实际上最终成为 VSCode YAML 扩展中的一个错误,它正在摄取我的模式,导致if块无法评估,并且已被提升、修复和发布。


推荐阅读