JSON Поддержка ограничения кросс-ключа схемы с использованием условных ключевых слов - PullRequest
3 голосов
/ 30 января 2020

Я хочу express условная проверка схемы, которая содержит условия перекрестного ключа. Есть ли поддержка этого в схеме JSON с доступными условными ключевыми словами (allOf / anyOf / if / then / else)

JSON Схема:

{
    "type": "object",
    "additionalProperties": false,
    "properties": {
        "x": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "value": {
                    "type": "string"
                }
            }
        },
        "y": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
                "key1": {
                    "type": "string",
                    "enum": ["a", "b", "c", "d", "e"]
                },
                "key2": {
                    "type": "string",
                    "enum": ["x", "y", "m", "n", "r", "s"]
                }
            },
            "anyOf": [{
                    "allOf": [{
                            "if": {
                                "properties": {
                                    "key1": {
                                        "enum": ["a", "b"]
                                    }
                                }
                            },
                            "then": {
                                "properties": {
                                    "key2": {
                                        "enum": ["x", "y"]
                                    }
                                }
                            }
                        },
                        {
                            "if": {
                                "x": {
                                    "properties": {
                                        "value": {
                                            "const": "myVal"
                                        }
                                    }
                                }
                            },
                            "then": {
                                "properties": {
                                    "key2": {
                                        "enum": ["x", "y"]
                                    }
                                }
                            }
                        }
                    ]
                },
                {
                    "if": {
                        "properties": {
                            "key1": {
                                "enum": ["c", "d"]
                            }
                        }
                    },
                    "then": {
                        "properties": {
                            "key2": {
                                "type": "string",
                                "enum": ["m", "n"]
                            }
                        }
                    }
                }
            ]
        }
    }
}

Пример JSON экземпляр будет выглядеть следующим образом

{
    "x": {
        "value": "myVal"
    },
    "y": {
        "key1": "a",
        "key2": "x"
    }
}

Условие, которое я хочу express - это следующие 2 условия

  1. Если (x .value == "myVal" AND (y.key1 == "a" ИЛИ y.key1 == "b") , тогда y.key2 должен иметь только "x" или "y"
    (ИЛИ)

  2. Если (y.key1 == "c" ИЛИ y.key1 == "d") затем y.key2 должен содержать только «m» или «n».

    (ИЛИ)

  3. y.key2 может принимать любые допустимые значения перечисления, определенные в y. свойство key2.

Условное обозначение, которое я использовал JSON, не работает. Я попытался проверить с помощью https://www.jsonschemavalidator.net/.

Любая помощь будет высоко ценится:)

Спасибо

1 Ответ

3 голосов
/ 31 января 2020

Так что я думаю, что это один из тех случаев, когда лучше забыть о ключевых словах if / then / else и просто определить хорошие состояния в oneOf. (Я предлагаю oneOf вместо anyOf, потому что должен совпадать ровно один из этих состояний.)

Итак, для вашей схемы вы хотите ОДИН ИЗ

  1. ВСЕ из
    • x.value == "myVal"
    • y.key1 in ["a", "b"]
    • y.key2 in ["x", "y"]
  2. ALL из
    • y.key1 in ["c", "d"]
    • y.key2 in ["m", "n"]
  3. ВСЁ
    • НЕ
      • ОДИН ИЗ
        • ВСЁ
          • x.value == "myVal"
          • y.key1 in ["a", "b"]
        • y.key1 in ["c", "d"]
    • true (или {}, если вы на предварительном этапе-6)

Похоже, вы сработали # 1 и # 2; просто бросьте условный лог c. Это НЕ в № 3, который делает работу. Здесь мы говорим, что если условие для # 1 ложно и условие для # 2 ложно, то любое значение, уже определенное в перечислении для y.key2, подходит.

Причина, по которой нам нужно явно express, что нам не нужны условия для # 1 и # 2, заключается в том, что без них у нас просто есть схема true, которая разрешает все (что ранее не ограничивалось).

Теперь другой недостаток заключается в том, что в одном из ваших состояний используется x, но ваша подсхема anyOf соответствует определению для y, поэтому она вообще не может видеть x. Чтобы это исправить, вам нужно переместить эту подсхему в root, а в качестве сестры - в properties. Здесь он может просматривать весь экземпляр, а не только значение в свойстве y.

...