Проверка элемента в «объекте` на основе другого элемента в том же «объекте»

#json #jsonschema #json-schema-validator

Вопрос:

[Воспроизводится на https://www.jsonschemavalidator.net — просто скопируйте и вставьте объекты JSON (обратите внимание, что первый является примером).]

Итак, я ожидаю такой объект JSON:

 [
    {"k": "my_date", "v": "2021-08-04"},
    {"k": "item_1", "v": 1},
    {"k": "item_2", "v": 2.5},
    ...
    {"k": ". ", "v": <<type - number>>}
]
 

Я хочу разработать схему JSON , которая гарантирует, что «my_date» всегда будет a string , но все остальные элементы (независимо от их значения «k») являются числами.

То, что у меня есть сейчас, — это

 {
  "$id": "#/properties/my-output",
  "type": "array",
  "title": "The Output Schema",
  "items": {
    "type": "object",
    "properties": {
      "k": {
        "type": "string"
      },
      "v": {
        "type": "number"
      }
    }
  }
}
 

но это, очевидно, не работает, так как

 [
  {
    "k": "my_date",
    "v": "2021-08-04"
  },
  {
    "k": "any_name",
    "v": 123.2
  },
  {
    "sdf": "sdf"
  }
]
 

терпит неудачу, потому что:

  1. my_date имеет значение, которое является string , и это не разрешено схемой;
  2. sdf здесь вообще не должно быть, но схема принимает это.

Как я должен разработать схему?

P.S. Я ожидаю, что будут и другие значения «k», которые должны иметь string s в качестве значений «v», поэтому я хотел бы иметь возможность рассмотреть их.

Ответ №1:

Вы можете запретить использование дополнительного свойства «sdf» с "additionalProperties": false помощью (рядом с ключевым словом «свойства»). видишь https://json-schema.org/understanding-json-schema/reference/object.html#additional-properties

Что касается ваших дат, вы, кажется, говорите, что они могут и не могут быть строками, так что я не уверен, в чем собственно проблема.

Ответ №2:

Оказалось, что в ответе используется оператор if-else-then, подобный этому (спасибо @Ether за предложение использовать additionalProperties ):

 {
  "$id": "#/properties/my-output",
  "type": "array",
  "title": "The Output Schema",
  "items": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "k": {
        "type": "string",
      },
      "v": {
      }
    },
    "if": {
      "properties": {
        "k": {
          "enum": ["my_date"]
        }
      }
    },
    "then": {
      "properties": {
        "v": {
          "type": "string"
        }
      }
    },
    "else": {
      "properties": {
        "v": {
          "type": "number"
        }
      }
    }
  }
}
 

Здесь происходит следующее:
Изначально мы хотим, чтобы элемент в массиве имел k значение и v значение. k значение ограничено строкой — всегда; но мы не указываем ограничений для v … пока.

Затем мы явно указываем наши ограничения: если k это одно из "enum":["my_date", <<add others here>>] , то мы хотим , чтобы это k был тип string . Еще — нам нужен номер.

Приведенная выше схема корректно завершается ошибкой при следующем тестовом вводе (который вы можете попробовать https://www.jsonschemavalidator.net):

 [
  {
    "k": "my_date",
    "v": "2021-08-04"
  },
  {
    "k": "my_date_wrong",
    "v": "2021-08-04"
  },
  {
    "k": "some_item",
    "v": 123.2
  },
  {
    "k": "some_other_123item",
    "v": 123.2
  },
  {
    "sdf": "sdf"
  }
]
 

Приведенный выше ввод корректно завершается "k": "my_date_wrong" ошибкой , поскольку он не включен enum в инструкцию if. Он также корректно выходит из строя на sdf поле, так как он признан недействительным additionalProperties .

Очевидным недостатком этого подхода является то, что если у вас есть много v -s, которые должны быть строками, вам необходимо явно перечислить их в операторе if.

Ответ №3:

Таким образом, одним из подходов было бы использовать «oneOf» для схемы элементов в массиве.

 {
   "type": "object",
    "required": ["k", "v"],
      "properties": {
        "k": {
          "type": "string"
        },
        "v": {}
      },
    "additionalProperties": false,
    "oneOf": [
      {"$ref": "#/$defs/dateValue"},
      {"$ref": "#/$defs/anyOtherValue"}
    ],
    "$defs":{
      "dateValue": {
          "properties": {
            "k": {
              "const": "my_date"
            },
           "v": { "type": "string" }
          },
          "additionalProperties": false
      },
      "anyOtherValue": {
          "not": {
            "properties": {
              "k": {
                "enum": ["my_date"]
              }
            }
         }
      }
    }
}
 

Комментарии:

1. (Преимущество этого подхода заключается в том, что вы можете легко распространить его на дополнительные типы ключей, добавив конкретную схему в список «oneOf» вместе со значением ключа в список «перечисление» в «любое другое значение».)