Условное объединение свойств схемы JSON

#json #intellisense #jsonschema #json-schema-validator

#json #intellisense #jsonschema #json-schema-validator

Вопрос:

Я пытаюсь создать схему JSON для проверки YAML для некоторого VSCode intellisense. То, что я пытаюсь сделать, это выбрать правильную подсхему для использования для свойства в основной схеме на основе значения смежного ключа.

Некоторые примеры JSON:

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

Поэтому мне нужно выбрать правильные схемы для mergeMe объектов на основе соответствия подстроки matchMe . После выполнения множества ответов я нахожусь в точке, где я могу либо сопоставить несколько, и ошибка моего линтера, либо не совпадать, но онлайн-валидатор говорит, что все в порядке (за исключением того, что ничего не совпадает, поскольку required поля не запускаются).

Я переместил свои подсхемы для объединения, definitions чтобы ссылаться на них, а затем использовал if / then для сопоставления. Это сработало с одним, но затем я попытался расширить его, чтобы выполнить сопоставление с деревом, и я не могу заставить это работать. Кто-то сказал, что я должен обернуть свои if / thens в allOf (я не уверен, почему это сработает, поскольку, конечно, не все из них будут совпадать?). Изменение его на an anyOf не приводит ни к одному из них, и я не получаю intellisense. Я также не совсем понимаю, почему я должен переносить отдельные if / thens или thens в allOf s.

Идея заключается в том, что на основе шаблона он использует 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 — идея заключается в том, что если я укажу еду с префиксом «fruit», я должен дать ей «косточки» и «ягоду», тогда как если я укажу «овощ», я должен дать ему совершенно другую схему, и они не перекрываются. https://jsonschema.dev/s/pHzGo

Комментарии:

1. Действительно сложно обосновать вашу схему и экземпляр, когда вы используете нереальные значения. Пожалуйста, можете ли вы заменить свои притворные значения реальными значениями? Я знаю, это кажется глупым, но оно предоставляет контекст, который может быть полезен. Бонусные баллы, если вы можете предоставить несколько ссылок на jsonschema.dev , показывающих вашу проблему.

2. Конечно, конечно — полностью понятно. Я попытался создать небольшой пример, используя фрукты и овощи (отредактировано в нижней части вопроса).

3. Не могли бы вы привести несколько примеров экземпляров, которые не проверяются должным образом. Вы на правильном пути. Я предполагаю, что у вас просто есть несколько крайних случаев, которые нужно сгладить.

4. Боюсь, в настоящее время ни один из примеров не проверяется должным образом — они представляют собой смесь того, что у меня было на момент публикации, и того, что у меня есть на момент редактирования в ссылке jsonschema.dev, с тем, что должно быть проверено для неверной схемы. Я обнаружил, что условие «шаблон» в «если» на самом деле не соответствует, заменив ссылку на простые «обязательные», чтобы более четко видеть, что происходит.

5. На самом деле я не совсем уверен, что это вопрос json-схемы больше — когда он сведен к базовому уровню «if type is string», то () else требует чего-то — он явно проверяет ok в онлайн-валидаторах, но VSCode просто отказывается проверять свойство в блоке «if», хотязатем может потребоваться, чтобы одно и то же свойство было другого типа в следующем блоке «else».

Ответ №1:

На самом деле это оказалось ошибкой в расширении VSCode YAML, которое поглощало мою схему, в результате if чего блоки не оценивались, и было поднято, исправлено и выпущено.