Схема JSON для принудительного выполнения содержимого массива

Всем привет и заранее спасибо.

Я пытаюсь создать схему JSON, чтобы заставить массив содержать один объект A и B и N объектов C, где A и B - объекты C, а N - целое число включительно от 0 до бесконечности.

Для этого:

[A, B] [A, B, C1] [A, B, C1, .., CN]

Однако все действительны:

[A] [A, C1] [A, C1, .., CN]

недействительны.

Чтобы прояснить, должны присутствовать A и B. Объекты C необязательны, хотя их может быть сколько угодно.

Схемы объектов C:


{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "C Object",

  "type": "object",
  "required": ["id", "name"],

  "properties": {
    "id": {
      "type": "integer"
    },
    "name": {
      "type": "string"
    }
  },
  "additionalProperties": false
}

Таким образом, объект C - это любой допустимый объект JSON, содержащий только свойства «id» и «name», где «id» - целое число, а «name» - строка.

Схемы объектов A и B:


{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "A Object",

  "type": "object",
  "required": ["id", "name"],

  "properties": {
    "id": {
      "type": "integer"
    },
    "name": {
      "type": "string",
      "enum": ["A"]
    }
  },
  "additionalProperties": false
}

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "B Object",

  "type": "object",
  "required": ["id", "name"],

  "properties": {
    "id": {
      "type": "integer"
    },
    "name": {
      "type": "string",
      "enum": ["B"]
    }
  },
  "additionalProperties": false
}

Объекты A и B отличаются от объектов C тем, что в них применяется значение имени. Значение имени объекта A должно быть значением, содержащимся в поле enum, где enum содержит единственное значение.

Моя самая полная на сегодняшний день схема:


{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "To Date Solution",
  "description": "So far this is the most complete attempt at enforcing values to be contained within a JSON structure using JSON schemas.",

  "type": "array"
  "items": {
    "allOf": [
      {
        "$schema": "http://json-schema.org/draft-04/schema#",
        "title": "C Object",

        "type": "object",
        "required": ["id", "name"],

        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          }
        },
        "additionalProperties": false
      }
    ]
  }
}

Это приводит к тому, что все содержащиеся внутри объекты должны быть типа C, каковыми являются A и B, хотя я не уверен, как обеспечить, чтобы хотя бы один экземпляр A и B содержался в моем массиве.


person Dawson    schedule 30.10.2013    source источник
comment
Должны ли A и B быть первыми двумя (в таком порядке)? Или они могут появиться где угодно в списке?   -  person cloudfeet    schedule 06.11.2013


Ответы (2)


То, что вы ищете, называется «набором кортежей».

Если значение ключевого слова items является массивом, то элементы в данных массива должны совпадать со схемой в соответствующей позиции. Дополнительные элементы (за последним индексом) соответствуют additionalItems (или запрещены, если additionalItems равно false).

Итак, примерно то, что вы хотите, выглядит примерно так:

{
    "type": "array",
    "items": [
        {"$ref": "#/definitions/itemTypeA"},
        {"$ref": "#/definitions/itemTypeB"}
    ],
    "additionalItems": {"$ref": "#/definitions/itemTypeC"},
    "definitions": {
        ... actual definitions for A/B/C ...
    }
}

Если вы хотите гарантировать существование A и B, вы просто указываете минимальную длину, используя minItems, так что есть как минимум два элемента (которые из-за "типизации кортежа" должны совпадать с A и Б).

(Это также предполагает, что A и B являются первыми элементами в массиве. Если это не то, что вы хотите, тогда все становится немного сложнее - хотя существует _ 7_, предложенное для версии 5, поможет с этим аккуратно справиться.)

Чуть более подробная живая демонстрация:

person cloudfeet    schedule 06.11.2013
comment
Это соответствует ответу, к которому я пришел ниже, и это то, что я реализовал, чтобы двигаться вперед, хотя я ищу, чтобы он не зависел от позиции. Чем ты хоть подумал. Из этого я получил знания о типе кортежей и подумал о том, чтобы взглянуть на Json Schema v5 :) - person Dawson; 07.11.2013
comment
Вы можете сделать что-нибудь довольно ужасное в версии 4, если хотите быть независимым от позиции. Однако в целом я бы не советовал это, так как это трудно читать / понимать. - person cloudfeet; 07.11.2013
comment
Также стоит отметить, что как для взлома v4, так и для ключевого слова v5 contains ограничение составляет по крайней мере один - и additionalItems не применяется. Для v5 существует обходной путь, чтобы указать ровно один. - person cloudfeet; 07.11.2013
comment
Не могли бы вы связать документацию по версии 5, пожалуйста? Мне не удалось ее найти. - person Dawson; 07.11.2013
comment
На самом деле спецификация v5 все еще находится в стадии написания, хотя она обещана очень скоро. Однако различные предложенные ключевые слова уже есть в вики GitHub . У них нет гарантии, что все получится, но contains почти наверняка входит в состав. - person cloudfeet; 08.11.2013
comment
Для меня $ refs не сработает. Наконец, я понял, что для $ id было установлено значение / foo / bla /, что вызывает проблемы. Если ваши ссылки не работают, проверьте / удалите свой $ id! - person Christopher K.; 15.01.2021

Я нашел решение, которое решает мою проблему, обеспечивая, чтобы A и B присутствовали в массиве, хотя и позиционно, таким образом, требуя, чтобы объект JSON, который я проверяю, был упорядочен каким-либо образом.

Рабочая схема


{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "title": "Order dependent solution",

  "type": "array",
  "items": [
    {
      "$schema": "http://json-schema.org/draft-04/schema#",
      "title": "A Object",

      "type": "object",
      "required": ["id", "name"],

      "properties": {
        "id": {
          "type": "integer"
        },
        "name": {
          "type": "string",
          "enum": ["A"]
        }
      },
      "additionalProperties": false
    },
    {
      "$schema": "http://json-schema.org/draft-04/schema#",
      "title": "B Object",

      "type": "object",
      "required": ["id", "name"],

      "properties": {
        "id": {
          "type": "integer"
        },
        "name": {
          "type": "string",
          "enum": ["B"]
        }
      },
      "additionalProperties": false
    }
  ],

  "additionalItems": {

    "$schema": "http://json-schema.org/draft-04/schema#",
    "title": "C Object",

    "type": "object",
    "required": ["id", "name"],

    "properties": {
      "id": {
        "type": "integer"
      },
      "name": {
        "type": "string"
      }
    },
    "additionalProperties": false  
  }

}

Эта схема JSON проверяет массив JSON, содержащий объект A с индексом 0, объект B с индексом 1 и объекты C, составляющие все оставшиеся элементы. Это решение можно использовать и оно позволяет мне продвигаться вперед в разработке, хотя предпочтительнее было бы решение, не зависящее от порядка.

Любая помощь приветствуется! :)

PS - Эти схемы не оптимизированы и демонстрируют избыточность, которую я удалю в окончательной версии, используя ключевые слова «id» и «$ ref».

person Dawson    schedule 06.11.2013
comment
Кстати, вам не нужно $schema в каждой схеме, только в схеме верхнего уровня. - person cloudfeet; 06.11.2013
comment
В лицо, я считаю, что сейчас это запрещено! - person Relequestual; 25.07.2018