json schema — элементы родительского массива (массив объектов) имеют внутренний массив (массив примитивов) с заданными значениями

Пожалуйста, не стесняйтесь обновить подходящий заголовок для этого вопроса.

Я пытаюсь добиться чего-то вроде это. Входной JSON/данные JSON должен иметь учетную запись OWNER и CHARGE_TO, но они не обязательно должны быть в одной и той же учетной записи (т. е. одна учетная запись может быть OWNER, другая может быть CHARGE_TO) и не должна содержать учетную запись с какими-либо другими ролями.

ПРИМЕЧАНИЕ. Необходимо определить схему JSON, которая должна быть простой в обслуживании. т. е. должно быть легко добавить новую роль в условие. Мои действительные и недействительные JSON:

*************************** VALID JSON1 *********************************
{
  "user": [
    {
      "name": "user1",
      "roles": ["OWNER"]
    },
    {
      "name": "user2",
      "roles": ["ANY_OTHER_ROLE"]
    },
    {
      "name": "user3",
      "roles": ["CHARGE_TO"]
    }]  
}
*************************** VALID JSON2 *********************************
{
  "user": [
    {
      "name": "user1",
      "roles": ["OWNER", "CHARGE_TO"]
    },
    {
      "name": "user2",
      "roles": ["ANY_OTHER_ROLE"]
    }]  
}
*************************** INVALID JSON *********************************
{
  "user": [
    {
      "name": "user1",
      "roles": ["OWNER"]
    },
    {
      "name": "user2",
      "roles": ["ANY_OTHER_ROLE"]
    }]  
}

JSON действителен, если у него есть пользователь с ролями ("OWNER" & "CHARGE_TO") или если пользователи с ролями (user1 — "OWNER", user3 — "CHARGE_TO", другие пользователи с любой другой ролью).

Ниже приведена схема JSON, которую я пробовал (draft_07). ЭТО НЕ РАБОТАЮЩАЯ СХЕМА.

{
"$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Complex inner array",
  "type": "object",
  "properties": {
    "user": {
      "type": "array",
      "contains": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "orderRoles": {
            "type": "array",
            "minItems": 1,
            "items": { "type": "string" }
          }
        },
        "oneOf": [
          { "properties": { "roles": { "enum": ["OWNER", "CHARGE_TO"] }}},
          { "properties": { "roles": { "enum": ["OWNER"] }}},
          { "properties": { "roles": { "enum": ["CHARGE_TO"] }}}
        ]
      },
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "orderRoles": {
            "type": "array",
            "minItems": 1,
            "items": { "type": "string" }
          }
        }
      }
    }
  }
}

person Vinni    schedule 08.05.2018    source источник
comment
Изменение использования enum на const поможет вам в этом. enum предназначен для определенного значения, а не для определенного значения В массиве. Я также предлагаю вам попробовать использовать jsonschemavalidator.net, чтобы исправить свою схему. Хороший способ отладки — заменить подсхемы на false, чтобы увидеть, оценивается ли путь или нет. Если у вас все еще есть проблемы после того, как вы попробовали еще несколько, дайте мне знать, и я, возможно, смогу помочь.   -  person Relequestual    schedule 09.05.2018
comment
Довольно сложно понять, о чем вы спрашиваете. Вместо того, чтобы ссылаться на другой вопрос и говорить подобное, объясните здесь свои требования и объясните свои правила, а также то, что вы ожидаете, но не происходит.   -  person Relequestual    schedule 09.05.2018
comment
@Relequestual - я обновил вопрос, чтобы больше объяснить свой сценарий. Надеюсь теперь понятно.   -  person Vinni    schedule 10.05.2018


Ответы (2)


Ниже моя рабочая схема. Это не элегантное решение, так как схема становится огромной, если добавляется новая роль ("ADMIN"), т. е. условие схемы будет An input JSON/data JSON must have an OWNER, ADMIN and a CHARGE_TO Account, but these don't have to be on the same Account (I.e. one Account can be OWNER, one Account can be ADMIN & another can be CHARGE_TO) and must not contain account with any other roles. Пожалуйста, не стесняйтесь улучшить это. Спасибо.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Complex inner array",
  "type": "object",
  "allOf": [
    {
      "properties": {
        "account": {
          "type": "array",
          "contains": {
            "type": "object",
            "properties": {
              "roles": {
                "type": "array",
                "minItems": 1,
                "contains": { "enum": ["OWNER"] }
              }
            }
          }
        }
      }
    },
    {
      "properties": {
        "account": {
          "type": "array",
          "contains": {
            "type": "object",
            "properties": {
              "roles": {
                "type": "array",
                "minItems": 1,
                "contains": { "enum": ["CHARGE_TO"] }
              }
            }
          }
        }
      }
    },
    {
      "properties": {
        "account": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "roles": {
                "type": "array",
                "minItems": 1,
                "items":{
                  "enum": ["CHARGE_TO", "OWNER"]
                }
              }
            }
          }
        }
      }
    }
  ]
}
person Vinni    schedule 09.05.2018

Вам нужно изолировать часть схемы, которая проверяет наличие определенной роли. Затем вы можете просто объединить их с allOf. Существует как можно меньше дублирования, и вы можете легко добавить еще одно ограничение.

{
  "type": "object",
  "properties": {
    "user": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "roles": {
            "type": "array",
            "items": { "type": "string" }
          }
        }
      },
      "allOf": [
        { "$ref": "#/definitions/require-role-owner" },
        { "$ref": "#/definitions/require-role-charge-to" }
      ]
    }
  },
  "definitions": {
    "require-role-owner": {
      "contains": {
        "properties": {
          "roles": {
            "contains": { "const": "OWNER" },
            "allOf": [{ "$ref": "#/definitions/not-other-role" }]
          }
        }
      }
    },
    "require-role-charge-to": {
      "contains": {
        "properties": {
          "roles": {
            "contains": { "const": "CHARGE_TO" },
            "allOf": [{ "$ref": "#/definitions/not-other-role" }]
          }
        }
      }
    },
    "not-other-role": {
      "items": { "enum": ["OWNER", "CHARGE_TO"] }
    }
  }
}
person Jason Desrosiers    schedule 10.05.2018
comment
Спасибо за ответ. Сделано что-то подобное в ответе, который я разместил. Но то, что вы опубликовали, не соответствует моему требованию. Пример: для этого проверка должна завершиться неудачно, так как в массиве есть новая роль, но вместо этого она прошла. { "user": [{ "name": "user1", "roles": ["OWNER", "CHARGE_TO", "ANY_OTHER_ROLE"] }] } - person Vinni; 10.05.2018
comment
Извините, я пропустил требование не содержать учетную запись с какими-либо другими ролями. Я обновил ответ, чтобы принять это во внимание. - person Jason Desrosiers; 10.05.2018