Ошибочная успешная проверка JSON-схемой - PullRequest
0 голосов
/ 01 ноября 2019

Поля в узлах зависят от значения объекта. То есть, если entity = "pd", то у узлов есть несколько полей, а entity = "top" - у узлов совершенно разные поля, несмотря на то, что они строго обязательны. По какой-то причине строка JSON принимается допустимой схемой, даже если в узлах нет полей, определенных как обязательные. Я уже всю голову сломал, где может быть ошибка в самой схеме? JSON-схема:

{
  "definitions": {},
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/root.json",
  "type": "object",
  "title": "The Root Schema",
  "required": [
    "virtual"
  ],
  "properties": {
    "virtual": {
      "$id": "#/properties/virtual",
      "type": "array",
      "title": "The Virtual Schema",
      "items": {
        "$id": "#/properties/virtual/items",
        "type": "object",
        "title": "The Items Schema",
        "required": [
          "type",
          "path",
          "entity",
          "nodes"
        ],
        "properties": {
          "type": {
            "$id": "#/properties/virtual/items/properties/type",
            "type": "string",
            "title": "The Type Schema",
            "default": "",
            "examples": [
              "bus"
            ],
            "pattern": "^(.*)$"
          },
          "path": {
            "$id": "#/properties/virtual/items/properties/path",
            "type": "string",
            "title": "The Path Schema",
            "default": "",
            "examples": [
              "VBUS2"
            ],
            "pattern": "^(.*)$"
          },
          "entity": {
            "$id": "#/properties/virtual/items/properties/entity",
            "type": "string",
            "title": "The Entity Schema",
            "default": "",
            "examples": [
              "topaz"
            ],
            "enum": ["pde", "topaz"],
            "pattern": "^(.*)$"
          },
          "nodes": {
            "$id": "#/properties/virtual/items/properties/nodes",
            "type": "array",
            "title": "The Nodes Schema",
            "items": {
                "$id": "#/properties/virtual/items/properties/nodes/items",
                "type": "object",
                "title": "The Items Schema"
            }
          }
        }
      }
    }
  },
  "anyOf": [
    {       
        "if": {
            "properties": { "virtual": { "properties": { "entity": { "const": "topaz" } } } } 
        },
        "then": {
            "properties": { 
                "virtual": { 
                    "properties": { 
                        "nodes": {  
                            "items": {
                                "required": [
                                    "uid",
                                    "utype",
                                    "uaddress",
                                    "unozzles"
                                ],
                                "properties": {
                                    "uid": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/uid",
                                        "type": "integer",
                                        "title": "The Uid Schema",
                                        "default": 0,
                                        "examples": [
                                            1
                                        ]
                                    },
                                    "utype": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/utype",
                                        "type": "string",
                                        "title": "The Utype Schema",
                                        "default": "",
                                        "examples": [
                                            "dispenser"
                                        ],
                                        "pattern": "^(.*)$" 
                                    },
                                    "uaddress": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/uaddress",
                                        "type": "string",
                                        "title": "The Uaddress Schema",
                                        "default": "",
                                        "examples": [
                                            "false"
                                        ],
                                        "pattern": "^(.*)$"
                                    },
                                    "unozzles": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/unozzles",
                                        "type": "boolean",
                                        "title": "The Unozzles Schema",
                                        "default": false,
                                        "examples": [
                                            false
                                        ]
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        "if": { 
            "properties": { "virtual": { "properties": { "entity": { "const" : "pde" } } } }
        },
        "then": {
            "properties": {
                "virtual": {
                    "properties": {
                        "nodes": {
                            "items": {
                                "required": [                                   
                                    "id",
                                    "type",
                                    "address",
                                    "nozzles"
                                ],
                                "properties": {
                                    "id": {                     
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/id",
                                            "type": "string",
                                            "title": "The Id Schema",
                                            "default": "",
                                            "examples": [
                                                "vrt_1"
                                            ],
                                        "pattern": "^(.*)$"
                                    },
                                    "type": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/type",
                                        "type": "string",
                                        "title": "The Type Schema",
                                        "default": "",
                                        "examples": [
                                            "dispenser"
                                        ],
                                        "pattern": "^(.*)$"
                                    },
                                    "address": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/address",
                                        "type": "integer",
                                        "title": "The Address Schema",
                                        "default": 0,
                                        "examples": [
                                            1
                                        ]
                                    },
                                    "nozzles": {
                                        "$id": "#/properties/virtual/items/properties/nodes/items/properties/nozzles",
                                        "type": "array",
                                        "title": "The Nozzles Schema",
                                        "items": {
                                            "$id": "#/properties/virtual/items/properties/nodes/items/properties/nozzles/items",
                                            "type": "integer",
                                            "title": "The Items Schema",
                                            "default": 0,
                                            "examples": [
                                                1,
                                                2,
                                                3
                                            ]
                                        }
                                    }
                                }
                            }                                           
                        }
                    }
                }
            }
        }
    }
  ]  
}

Этот JSON действителен:

{
    "virtual": [
        {
            "type": "bus",
            "path": "VUS1",
            "entity": "pde",
            "nodes": [
                {
                    "id": "vrt_1",
                    "type": "string",
                    "address": 1,
                    "nozzles": [1, 2, 3]
                },
                {
                    "id": "vrt_2",
                    "type": "string",
                    "address": 2,
                    "nozzles": [1, 2, 3]
                }
            ]
        },
        {
            "type": "bus",
            "path": "VUS2",
            "entity": "topaz",
            "nodes": [          
                {
                    "uid": 1,
                    "utype": "string",
                    "uaddress": "false",
                    "unozzles": false
                },
                {
                    "uid": "vrt_1",
                    "utype": "string",
                    "uaddress": "false",
                    "unozzles": false
                }
            ]
        }
    ]
}

И этот JSON не должен применяться, но считается действительным:

{
    "virtual": [
        {
            "type": "bus",
            "path": "VUS1",
            "entity": "pde",
            "nodes": [
                {
                    "id_not_valid": "failure",
                    "type": 1,
                    "address": false,
                    "nozzles": [1, 2, 3]
                },
                {
                    "id": "vrt_2",
                    "type": "string",
                    "address": false,
                    "nozzles": [1, 2, 3]
                }
            ]
        },
        {
            "type": "bus",
            "path": "VUS2",
            "entity": "topaz",
            "nodes": [          
                {
                    "uid_not_valid": "failure",
                    "utype": 1,
                    "uaddress": "false",
                    "unozzles": false
                }
            ]
        }
    ]
}

ВТеория, вторая JSON не должна быть проверена. По нескольким причинам:

  1. Для entity = "pd" обязательные поля: "id", "type", "address" и "nozzles". Во второй строке JSON вместо поля «id» заменяется поле «id_not_valid» -> обязательное поле «id» отсутствует и проверка должна завершиться неудачей. То же самое для entity = "top" - "uid" заменяется на "id_not_valid"
  2. Для entity = "pd" поле адреса имеет токен типа, во второй строке JSON установлено значение false, что соответствует типу «логический», но проверка все еще происходит (то же самое, если вы присваиваете массиву или строковому значению адрес). Для типа entity = "top" типом является строка, но присвоенное ему целочисленное значение 1 также считается корректной строкой.

Но онлайн-валидаторы по ссылкам нижеговорят, что все в порядке и оба JSON соответствуют схеме.

Первый сайт

Второй сайт

Третий веб-сайт

Так что я считаю, что в схеме есть ошибка.
Сама схема была сделана на этом примере Пример компиляции схемы JSON

Любые комментарии и советы по исправлению JSON-схемы просьба

1 Ответ

1 голос
/ 01 ноября 2019

Схема неверна .

(Я игнорирую тот факт, что состояния схемы entity должны быть "pde" или "topaz", но экземпляры имеют "pd" и "top". Я предполагаю, что это опечатка.)

Внутри anyOf у вас есть два элемента, каждый с условным ключевым словом if. Схема, представленная этим ключевым словом:

{
  "properties": {
    "virtual": {
      "properties": {
        "entity": {
          "const": "topaz"
        }
      }
    }
  }
}

Это говорит о том, что , если virtual имеет свойство entity, тогда оно должно быть "topaz". Но способ, которым работает properties, заключается в том, что он не проходит проверку , только если экземпляр является объектом . Однако в #/properties вы объявляете, что virtual должен быть массивом объектов, где каждый элемент содержит свойство entity.

Поскольку virtual является массивом в вашемНапример, ни одно из ключевых слов условия if в проходе anyOf, поэтому они относятся к ключевым словам else для тех подсхем, которые не существуют (поэтому проход по умолчанию). Это приводит к обеим подсхемам для прохождения anyOf.

Я думаю , что вы пытаетесь сделать, это проверить каждый из элементов в массиве на основе значения entity свойство для этого элемента. Это означает, что вы можете иметь как элемент pde, так и элемент topaz в массиве.

Для этого вам нужно выделить место, где находится дисперсия. В вашем случае это уровень элемента в массиве virtual. Здесь вам нужно поставить anyOf.

, поэтому вы захотите добавить anyOf к #/properties/virtual/items. Это единственная точка в схеме, где конструкция if / then может отключить свойство entity и применить свойство nodes.


Редактировать Вещи, которые я бы изменил

  1. Удалите все внутренние $id декларации. Они только повторяют расположение в документе и не предоставляют никаких дополнительных функций.
  2. Удалите объявления type и pattern из entity. enum здесь достаточно, потому что он объявляет, что значения должны быть одним из элементов в массиве. Поскольку оба они являются строками и соответствуют заданному шаблону, эти ключевые слова являются избыточными.
  3. Переместите anyOf рядом с ключевым словом properties внутри virtual и измените его на oneOf. Это наиболее конкретное место, где вы можете получить доступ как к свойству entities, так и к свойству nodes. Изменение его на oneOf гарантирует, что в точности может быть истина.
  4. Удалите конструкцию if / then и просто включите постоянное значение в часть then.

В конце концов, это будет структурировано примерно так:

{
  ... ,
  "properties": {
    "virtual": {
      "type": "array",
      "title": "The Virtual Schema",
      "items": {
        "type": "object",
        "title": "The Items Schema",
        "required": [ "type", "path", "entity", "nodes" ],
        "properties": {
          "type": { ... },
          "path": { ... },
          "entity": {
            "title": "The Entity Schema",
            "default": "",
            "examples": [
              "topaz"
            ],
            "enum": ["pde", "topaz"]
          }
        },
        "oneOf": [
            {
                "properties": {
                    "entity": {"const": "topaz"},
                    "nodes": { ... }
                }
            },
            {
                "properties": {
                    "entity": {"const": "pde"},
                    "nodes": { ... }
                }
            }
        ]
      }
    }
  } 
}

Здесь мы заявляем, что элементы в массиве virtual должны быть объектами, требующими 4 свойств: type,path, entity и nodes. Мы явно определяем type, path, entity, используя ключевое слово properties. Но мы условно определяем свойство nodes, используя oneOf и определяя постоянное значение для свойства entity в каждом случае.

...