Solución:
Hay varias formas de lograr el efecto requerido incluso sin usar JSON Schema draft-07 si-entonces-si no.
operador lógico e implicación (borrador-04 y superior)
Una implicación lógica aquí: si hay “medio”, entonces se requiere “voluminoso” se puede traducir a “medio” no está presente O “voluminoso” es “obligatorio” (este último implica “medio” está presente) que se puede desarrollar más a fondo para “medio” no es obligatorio O “voluminoso” es “obligatorio” (ya que si “medio” está presente, cumplirá la condición de ser requerido). Vea el esquema a continuación:
"properties": {
"smaller": {"type": "number"},
"larger": { "type": "number" },
"medium":{"type":"string"},
"bulky":{"type":"string"}
},
"required":["smaller","larger"],
"anyOf" : [
{
"not" : { "required" : ["medium"] }
},
{
"required" : ["bulky"]
}
],
"additionalProperties" : false
Consulte aquí para referencia:
Esquema JSON: válido si el objeto * no * contiene una propiedad en particular
http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.7
“anyOf” – OR lógico, “oneOf” – XOR, “allOf” – AND, “not” – negación, pero preste atención a las especificaciones:
Una instancia es válida con esta palabra clave si no se valida correctamente con el esquema definido por esta palabra clave.
draft-06 – dependencias + propertyNames
Lo mas obvio. No estoy seguro de si excluyó este en su pregunta, así que ponlo aquí por si acaso. Tenga en cuenta que, en lugar de “additionalProperties”, si simplemente desea limitar las claves válidas, se podría utilizar “propertyNames” (y es en realidad para lo que se agregó).
"properties": {
"smaller": {"type": "number"},
"larger": { "type": "number" },
"medium":{"type":"string"},
"bulky":{"type":"string"}
},
"required":["smaller","larger"],
"dependencies" : {
"medium" : ["bulky"]
},
"propertyNames" : {
"enum" : [
"smaller",
"larger",
"medium",
"bulky"
]
}
Consulte aquí para referencia: http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.5.7
Actualizar
Después de una aclaración en el comentario:
para el borrador-6 – aquí “no requiere” significa que si “medio” no existe, entonces “no debe estar presente” voluminoso
“no debe” significa evitar la presencia de objetos voluminosos.
Reformularé tu condición:
1. si existe “medio”, debe haber “voluminoso” -> ambas claves deben estar presentes al mismo tiempo
2. si “medio” no existe “voluminoso” no debe estar presente también -> ambas teclas no debe estar presente al mismo tiempo
¿Puede existir “bulky” y “medium” no existe?
No. Ver 2. Y viceversa (ver 1.). Igualdad booleana (complementaria al XOR lógico).
Por lo tanto, si existe “voluminoso”, significa que el “medio” debe estar siempre allí … Implica que ambos son requerido o ambos no debe ser requerido (o incluso permitido).
Dado que es draft-06, también puede usar “propertyNames” para definir nombres de propiedad permitidos (una especie de atajo a esta lógica).
operador lógico e implicación (borrador-06 y superior)
La operación lógica adecuada traducida a JSOn Schema se vería así:
"oneOf" : [
{ "required" : ["medium","bulky"] }, <== this schema is satisfied if both keys appear in validated instance
{
"allOf" : [ <== !medium ^ !bulky - due to how "not" works in schema context
{"not" : { "required" : ["medium"] } },
{"not" : { "required" : ["bulky"] } },
]
}
]
Un XOR – O (ambos obligatorios) O (no se requiere medio Y no se requiere voluminoso).
Tenga en cuenta que no estoy haciendo “no requerido” : [“medium”,”bulky”] } como cuando solo una de esas claves está presente, el esquema “requerido” fallaría, lo que significaría que “no” devolvería un resultado de validación exitoso. Hay que reformularlo utilizando las leyes de De Morgan:
"oneOf" : [
{ "required" : ["medium","bulky"] },
{
"not" : { <=== !medium ^ !bulky = !(medium v bulky)
"anyOf" : [
{ "required" : ["medium"] },
{ "required" : ["bulky"] },
]
}
}
]
Sin embargo, el uso de “propertyNames” también funcionará. Consulte el siguiente esquema:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"properties": {
"smaller": {"type": "number"},
"larger": { "type": "number" },
"medium":{"type":"string"},
"bulky":{"type":"string"}
},
"required":["smaller","larger"],
"anyOf" : [
{
"required" : ["medium","bulky"]
},
{
"propertyNames" : {
"enum" : [
"smaller",
"larger"
]
},
}
],
"examples" : [
{
"smaller" : 1,
"larger" : 2,
},
{
"smaller" : 1,
"larger" : 2,
"bulky" : "test",
"medium" : ""
},
{
"smaller" : 1,
"larger" : 2,
"medium" : ""
},
{
"smaller" : 1,
"larger" : 2,
"bulky" : "test",
},
]
}
¿Responde a tu pregunta?
JSON Schema Draft-07 ha incluido estas nuevas palabras clave if
, then
y else
que le permiten tener esquemas condicionales.
En este ejemplo:
- Solo el
foo
la propiedad es requerida - Sin embargo, si
foo
se establece en"bar"
entonces elbar
la propiedad también se vuelve necesaria
var ajv = new Ajv({
allErrors: true
});
var schema = {
"properties": {
"foo": {
"type": "string"
},
"bar": {
"type": "string"
},
},
"required": ["foo"],
"if": {
"properties": {
"foo": {
"enum": ["bar"]
}
}
},
"then": {
"required": ["bar"]
}
}
var validate = ajv.compile(schema);
test({
"foo": "bar",
"bar": "baz"
}); // VALID
test({
"foo": "xyz"
}); // VALID
test({
"foo": "bar",
}); // NOT VALID
function test(data) {
var valid = validate(data);
if (valid) console.log('VALID', data);
else console.log('NOT VALID', data);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/6.5.5/ajv.min.js"></script>
Con suerte, esto tiene sentido y puede adaptar su código en consecuencia.
PD: en su esquema tiene el require
propiedad que no estoy seguro de que sea una palabra clave de esquema JSON válida. Probablemente quisiste decir required
en lugar de.