Рассматривали ли вы
- не определяет тип B авансом
- с использованием ключевого слова "зависимости" для вашей схемы или соответствующего определения, содержащего ответ "Да" на вопрос А
- и определение типа вопроса B только в результате такой зависимости?
Давайте рассмотрим вашу суть:
"questionA": {
"type": "object",
"properties": {
"answer": {
"type": "string",
"minLength": 1,
"enum": ["Yes", "No"]
}
}
}
"questionB": {
"type": "object",
"properties": {
"answer": {
"type": null,
}
}
}
"questions": {
"type": "object",
"properties": {
"A": {"$ref": "#/definitions/questionA"},
"B": {"$ref": "#/definitions/questionB"}
},
"if": {
"properties" : {
"A": {"enum": ["Yes"]}
}
},
"then": {
"B": //Type = string and min length = 1 <-- Unsure what to put here to change the type of QuestionB
}
Если я правильно понимаю ваш вопрос, эффект, которого вы хотите достичь, будет:
Если респонденту нравятся машины, спросите его о любимой машине и возьмите ответ, иначе не беспокойтесь о любимой машине (и желательно, чтобы ответ был нулевым).
Как правильно сказал Relequestual в своем комментарии, JSON Schema затрудняет «переопределение» шрифта. Более того, каждый контент if-then-else должен быть отдельной действительной схемой.
Чтобы достичь этого эффекта, вы можете рассмотреть следующий подход:
- Определите вопрос A как enum, как вы это сделали
- Оставить свойство для вопроса B неопределенным заранее
- Определите две возможные схемы, которые могут работать как определение свойства для questionB и могут использоваться в результате зависимости
- Используйте правильное определение вопроса B относительно значения вопроса A
Ниже приведен пример схемы (совместимой с draft07), которая решает ваше дело. Также некоторые пояснения приведены ниже схемы.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type" : "object",
"propertyNames" : {
"enum" : [
"questionA",
"questionB",
]
},
"properties" : {
"questionA" : { "$ref" : "#/questionA" },
"questionB" : { "$ref" : "#/questionB" },
},
"dependencies" : {
"questionA" : {
"$ref" : "#/definitions/valid-combinations-of-qA-qB"
}
},
"definitions" : {
"does-like-cars":{
"properties" : {
"questionA" : {
"properties" : {
"answer" : { "enum" : ["Yes","y"] }
}
},
"questionB" : {
"properties" : {
"answer" : {
"$comment" : "Here #/questionB/answer becomes a type:string...",
"$ref" : "#/questionB/definitions/answer-def/string"
}
}
}
},
"required" : ["questionB"]
},
"doesnt-like-cars" :{
"properties" : {
"questionA" : {
"properties" : {
"answer" : { "enum" : ["No","n"] }
}
},
"questionB" : {
"properties" : {
"answer" : {
"$comment" : "Here #/questionB/answer becomes a type:null...",
"$ref" : "#/questionB/definitions/answer-def/null"
}
}
}
}
},
"valid-combinations-of-qA-qB" : {
"anyOf" : [
{ "$ref" : "#/definitions/doesnt-like-cars" },
{ "$ref" : "#/definitions/does-like-cars" }
]
},
},
"examples" : [
{
"questionA" : {
"answer" : "Yes",
},
"questionB" : {
"answer" : "Ass-kicking roadster",
},
},
{
"questionA" : {
"answer" : "No",
},
"questionB" : {
"answer" : null,
},
},
{
},
],
"questionA" : {
"$id" : "#/questionA",
"type" : "object",
"propertyNames" : {
"enum" : ["answer"]
},
"properties" : {
"answer" : {"$ref" : "#/questionA/definitions/answer-def"}
},
"definitions" : {
"answer-def" : {
"$comment" : "Consider using pattern instead of enum if case insensitiveness is required",
"type" : "string",
"enum" : ["Yes", "y", "No", "n"]
}
}
},
"questionB" : {
"$id" : "#/questionB",
"$comment" : "Please note no properties definitions here aside from propertyNames",
"type" : "object",
"propertyNames" : {
"enum" : ["answer"]
},
"definitions" : {
"answer-def" : {
"string" : {
"type" : "string",
"minLength" : 1,
},
"null" : {
"type" : "null"
}
}
}
},
}
Почему так сложно?
Потому что твоя суть сделала это так ;-) А если серьезно, это потому что:
В своей сути вы определяете оба вопроса как объекты. Там может быть
обоснованная причина этого, поэтому я сохранил это так (однако всякий раз, когда квартира
можно использовать список свойств, например «questionA-answer»,
«questionB-answer» Я бы предпочел, чтобы правила схемы были менее вложенными,
таким образом, более читабельным и простым в создании).
Из вашего вопроса и сути кажется, что это важно для вас
что «questionB / answer» является нулевым, а не проверенным
против / игнорируется, когда это не актуально, поэтому я сохранил это так
Шаг за шагом
Вопросы как объекты
Обратите внимание, что я создал отдельные подсхемы для "questionA" и "questionB". Это мое личное предпочтение, и ничто не мешает вам получить все внутри схемы «определений» основной схемы, однако я обычно делаю это так, потому что:
- легче разбить большую схему на несколько файлов меньшего размера после того, как вы заставите все работать как надо (поощряет повторное использование подсхем и помогает структурировать модели в языках программирования, если кто-то получит идею построить свою модель данных после моей схемы )
- обеспечивает правильную инкапсуляцию схем / подсхем объектов, а относительная ссылка обычно более понятна читателю
- помогает просматривать сложные схемы в редакторах, которые обрабатывают синтаксис JSON
"propertyNames"
Поскольку мы работаем здесь над «type»: «object», я использовал ключевое слово «propertyNames», чтобы определить схему для разрешенных имен свойств (поскольку классы в языках программирования обычно имеют статические наборы свойств). Попробуйте ввести в каждый объект свойство вне этого набора - проверка схемы не удалась. Это предотвращает мусор в ваших объектах. Если это нежелательное поведение, просто удалите схемы «propertyNames» из каждого объекта.
"questionB" - где находится трюк с изменением типа?
Хитрость в том, что не определяет тип свойства и другие соответствующие правила схемы заранее . Обратите внимание, что в схеме «questionB» отсутствует схема «properties». Вместо этого я использовал «определения», чтобы подготовить два возможных определения свойства «ответ» внутри объекта «вопрос В». Я буду использовать их в зависимости от значения ответа «questionA».
раздел "примеры"?
Некоторые объекты, которые должны иллюстрировать, как работает схема. Поиграйте со значениями ответов, наличием свойств и т. Д. Обратите внимание, что пустой объект также пройдет проверку, так как не требуется никаких свойств (как в вашей сущности) и есть только одна зависимость - если появляется «questionA», «questionB» должен также появиться.
Хорошо, хорошо, сверху вниз, пожалуйста,
Конечно.
Таким образом, основная схема может иметь два свойства:
questionA (объект, содержащий свойство "answer")
questionB (объект, содержащий свойство "answer")
Требуется ли "# / questionA"? -> Нет, по крайней мере, исходя из вашего смысла.
Требуется ли "questionB"? -> Только если появляется «# / questionA». Чтобы добавить оскорбление к травме :-) тип и допустимые значения "# / questionB / answer" строго зависят от значения "# / questionA / answer".
-> Я могу безопасно предварительно определить основной объект, основу для объектов вопросов, и мне нужно будет определить зависимость
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type" : "object",
"propertyNames" : {
"enum" : [
"questionA",
"questionB",
]
},
"properties" : {
"questionA" : { "$ref" : "#/questionA" },
"questionB" : { "$ref" : "#/questionB" },
},
"dependencies" : {
"questionA" : {
"$comment" : "when questionA prop appears in validated entity, do something to enforce questionB to be what it wants to be! (like Lady Gaga in Machette...)"
}
},
"questionA" : {
"$id" : "#/questionA",
"type" : "object",
"propertyNames" : {
"enum" : ["answer"]
},
},
"questionB" : {
"$id" : "#/questionB",
"type" : "object",
"propertyNames" : {
"enum" : ["answer"]
},
},
}
Обратите внимание Я сознательно устанавливаю относительную базовую ссылку с помощью ключевого слова "$ id" для подсхем вопроса, чтобы иметь возможность разбивать схему на несколько меньших файлов, а также для возможности чтения.
-> Я могу безопасно предварительно определить свойство «questionA / answer»: тип, допустимые значения и т. Д.
"questionA" : {
"$id" : "#/questionA",
"type" : "object",
"propertyNames" : {
"enum" : ["answer"]
},
"properties" : {
"answer" : {"$ref" : "#/questionA/definitions/answer-def"}
},
"definitions" : {
"answer-def" : {
"$comment" : "Consider using pattern instead of enum if case insensitiveness is required",
"type" : "string",
"enum" : ["Yes", "y", "No", "n"]
}
}
},
Примечание: Я использовал «определения», чтобы определить схему для конкретного свойства. На всякий случай, если мне нужно будет повторно использовать это определение где-нибудь еще ... (да, параноик по этому поводу)
-> Я не могу безопасно предварительно определить свойство "# / questionB / answer", как упомянуто выше, и должен выполнить часть "хитрости" в подсхеме "# / questionB"
"questionB" : {
"$id" : "#/questionB",
"$comment" : "Please note no properties definitions here aside from propertyNames",
"type" : "object",
"propertyNames" : {
"enum" : ["answer"]
},
"definitions" : {
"answer-def" : {
"string" : {
"type" : "string",
"minLength" : 1,
},
"null" : {
"type" : "null"
}
}
}
},
ПРИМЕЧАНИЕ: См. "# / Definitions / answer-def"? Для этого есть два подузла: "# / definitions / answer-def / string" и "# / Definitions / answer-def / null". Я не был полностью уверен, как я это сделаю в данный момент, но я знал, что мне определенно понадобится эта возможность жонглирования со схемой свойств "# / questionB / answer".
-> Я должен определить правила для допустимых комбинаций обоих ответов, и так как "# / questionB / answer" должен присутствовать всегда; Я делаю это в основной схеме, которая использует подсхемы вопросов, поскольку это верхний предел для них, который логически делает хорошее место для определения такого правила.
"definitions" : {
"does-like-cars":{
"properties" : {
"questionA" : {
"properties" : {
"answer" : { "enum" : ["Yes","y"] }
}
},
"questionB" : {
"properties" : {
"answer" : {
"$comment" : "Here #/questionB/answer becomes a type:string...",
"$ref" : "#/questionB/definitions/answer-def/string"
}
}
}
},
"required" : ["questionB"]
},
"doesnt-like-cars" :{
"properties" : {
"questionA" : {
"properties" : {
"answer" : { "enum" : ["No","n"] }
}
},
"questionB" : {
"properties" : {
"answer" : {
"$comment" : "Here #/questionB/answer becomes a type:null...",
"$ref" : "#/questionB/definitions/answer-def/null"
}
}
}
}
},
"valid-combinations-of-qA-qB" : {
"anyOf" : [
{ "$ref" : "#/definitions/doesnt-like-cars" },
{ "$ref" : "#/definitions/does-like-cars" }
]
},
Таким образом, есть те, кто любит автомобили - я в основном определяю допустимые значения "# / questionA / answer" и соответствующее определение свойства "# / questionB / answer". Поскольку это схема, оба набора должны совпадать, чтобы соответствовать этому определению. Обратите внимание, что я пометил ключ свойства «questionB» как необходимый, чтобы не проверять JSON, который содержит только ключ свойства «questionA» для схемы.
Я сделал то же самое для тех, кто не любит машины (как нельзя любить машины ?! Злые времена ...), и в конце я сказал в "valid-комбинации-of-qA-qB": или люди. Либо вы любите машины и даете мне ответ, либо вам не нравятся машины, и ответ должен быть нулевым. «XOR» («oneOf») приходит на ум автоматически, но так как я определил как автомобили И отвечаю и не люблю автомобили И отвечаю = ноль как полные схемы, логично ИЛИ вполне достаточно -> "anyOf".
В конце завершающим штрихом стало использование этого правила в разделе «зависимости» основной схемы, что означает: если в проверенном экземпляре появляется «questionA», то ... или ...
"dependencies" : {
"questionA" : {
"$ref" : "#/definitions/valid-combinations-of-qA-qB"
}
},
Надеюсь, это прояснит и поможет в вашем случае.
Открытые вопросы
Почему бы не использовать "ответы" объекта со свойствами, отражающими каждый ответ на вопрос, с ключом, идентифицирующим вопрос? Это может немного упростить правила и ссылки в отношении зависимостей между ответами (меньше печатать, да, я ленивый парень).
Почему "# / questionB / answer" должно быть нулевым, а просто игнорировать его, если "# / questionA / answer": {"enum": ["No"]}?
Рекомендуемое чтение
См. «Понимание схемы JSON»: https://json -schema.org / понимание-json-схема / index.html
Некоторые основные примеры: https://json -schema.org / learn /
Ссылка для проверки схемы JSON: https://json -schema.org / latest / json-schema-validation.html
Многие вопросы и ответы по StackOverflow дают хорошее представление о том, как управлять различными делами с помощью схемы JSON.
Также иногда может быть полезно проверить относительные JSON Pointers RFC.