Проверка гетерогенных списков объектов с помощью JsonSchema и $ ref - PullRequest
0 голосов
/ 14 марта 2019

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

У меня есть гетерогенный массив объектов, которые я хотел бы проверить. Эти объекты имеют одинаковый формат на верхнем уровне, но дочерние объекты весьма различны и могут быть идентифицированы только по атрибутам, присутствующим в каждом дочернем объекте.

Проблема связана с проверкой следующих данных, хотя у меня в массиве более двух типов объектов:

{
  "heterogeneous_array": [{
      "arbitrary_name": "foobar",
      "params": {
        "aa": "foo",
        "ab": "bar"
      }
    },
    {
      "arbitrary_name": "barfoo",
      "params": {
        "ba": "baz",
        "bb": "bot"
      }
    }
  ]
}

Я использую следующую схему, которая утверждает, что проверяет ввод json, даже когда объекты под ключом «params» недопустимы. Как я могу исправить схему JSON?

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "arbitrary_name": {
          "type": "string"
        },
        "params": {
          "oneOf": [{
              "$ref": "#/definitions/schema_a"
            },
            {
              "$ref": "#/definitions/schema_b"
            }
          ]
        },
        "required": ["arbitrary_name", "params"]
      }
    },
    "schema_a": {
      "properties": {
        "aa": {
          "type": "string"
        },
        "ab": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["aa", "ab"]
    },
    "schema_b": {
      "properties": {
        "ba": {
          "type": "string"
        },
        "bb": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["ba", "bb"]
    }
  }
}

Заранее спасибо!

1 Ответ

2 голосов
/ 14 марта 2019

Первое, что бросается в глаза, это то, что parameters и arbitrary_name не являются ключевыми словами JSON Schema. Я думаю, что вам не хватает нескольких properties ключевых слов.

Попробуйте это:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "properties": {             // missing this
          "arbitrary_name": {
            "type": "string"
          },
          "params": {
            "oneOf": [{
                "$ref": "#/definitions/schema_a"
              },
              {
                "$ref": "#/definitions/schema_b"
              }
            ]
          }
        },
        "required": ["arbitrary_name", "params"]    // "arbitrary_name" was "name"
      }
    },
    "schema_a": {
      "properties": {             // was "parameters"
        "aa": {
          "type": "string"
        },
        "ab": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["aa", "ab"]
    },
    "schema_b": {
      "properties": {             // was "parameters"
        "ba": {
          "type": "string"
        },
        "bb": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": ["ba", "bb"]
    }
  }
}

Там есть несколько других вещей, которые я прокомментировал.

Последнее (чтобы исправить то, что у вас есть) является второстепенным, его следует отметить, и, вероятно, оно в любом случае поддерживается вашей библиотекой JSON: логические значения в JSON всегда строчные (например, false не False). (Они на самом деле определены как явные токены.)


Из вашего вопроса неясно, требует ли объект foobar параметров aa и ab, а объект barfoo требует параметров ba и bb. Если это так, вы можете сделать некоторые другие вещи, если используете JSON Schema draft 6 или новее.

Черновик 6 определяет свойство const, которое можно использовать для выделения значений для определенных свойств и принудительного применения подсхем в других частях объекта. Используя это, вы можете создать своего рода оператор switch .

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "heterogeneous_array": {
      "$ref": "#/definitions/heterogeneous_array"
    }
  },
  "definitions": {
    "heterogeneous_array": {
      "type": "array",
      "items": {
        "oneOf": [
          {"$ref": "#/definitions/schema_a"},
          {"$ref": "#/definitions/schema_b"}
        ],
        "required": ["arbitrary_name", "params"]
      }
    },
    "schema_a": {
      "properties": {
        "arbitrary_name": {"const": "foobar"},
        "params": {
          "properties": {
            "aa": {
              "type": "string"
            },
            "ab": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "required": ["aa", "ab"]
        }
      }
    },
    "schema_b": {
      "properties": {
        "arbitrary_name": {"const": "barfoo"},
        "params": {
          "properties": {
            "ba": {
              "type": "string"
            },
            "bb": {
              "type": "string"
            }
          },
          "additionalProperties": false,
          "required": ["ba", "bb"]
        }
      }
    }
  }
}

Это небольшая реорганизация, и вам потребуется schema_? для каждого значения arbitrary_name, которое у вас есть.

В дополнение к этому, если вы используете черновик 7, у вас также есть ключевые слова if / then / else, но я не думаю, что этот вариант использования будет чище.

...