В дополнение к ответу Ульриха , вот пример того, что я бы сделал:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Component",
"type": "object",
"definitions": {
"base": {
"properties": {
"name": { "type": "string" },
"children": {
"type": "array",
"items": { "$ref": "#" }
}
},
"required": [ "_", "name" ]
},
"cpu": {
"properties": {
"_": { "const": "CPU" },
"freq_Unit": "MHZ"
}
},
"network": {
"properties": {
"_": { "const": "NETWORK" },
"unit": "Kb/s"
}
},
"disk": {
"properties": {
"_": { "const": "DISK" }
}
},
"window": {
"properties": {
"_": { "const": "WINDOW" },
"background": { "enum": [ "red", "orange", "yellow", ... ] }
}
}
},
"allOf": [
{ "$ref": "#/definitions/base" },
{
"oneOf": [
{ "$ref": "#/definitions/cpu" },
{ "$ref": "#/definitions/network" },
{ "$ref": "#/definitions/disk" },
{ "$ref": "#/definitions/window" }
]
}
]
}
Во-первых, мы требуем, чтобы любой экземпляр ДОЛЖЕН придерживаться base
, который объявляет _
и name
как обязательные свойства.Кроме того, мы объявляем свойство массива children
, которое требует, чтобы все элементы также соответствовали этой схеме (что дает нам рекурсивное поведение).Это на самом деле мало что дает, за исключением того, что позволяет нам объявлять эти вещи в одном месте вместо того, чтобы объявлять их в трех других определениях.
(Обратите внимание, что мы не объявляем _
всписок свойств. Это означает, что любое значение будет передано для этой части схемы. Мы очистим его в следующей части. Если вы хотите, чтобы будущие компоненты были объявлены со строками, то вы можете добавить"type": "string"
требование к этому свойству, но я не думаю, что оно необходимо, если другие не создают эти компоненты.)
Во-вторых, мы объявляем каждый из наших конкретных типов как отдельные определения, используя ключевое слово const
дляизолировать тот, который мы хотим.Эта конструкция аналогична инструкции switch
(или case
).Если экземпляр не соответствует ни одному из этих явных параметров, произойдет сбой.Если в нем отсутствует одно из обязательных базовых свойств, оно завершается неудачей.
Это приведет вас туда, где вы хотите быть.
Чтобы продвинуться дальше, есть еще две вещи, которые вы можете сделать:
- Добавьте
required
к другим определениям, чтобы сказать, что также необходимы определенные свойства (например, freq_Unit
для определения cpu
). - Объявите каждое из определений вотдельные файлы.Это позволит вам добавить новое определение, просто добавив новый файл и ссылаясь на него в основной схеме.На мой взгляд, это немного чище.Однако некоторые люди предпочитают хранить все это в одном файле.