Attributo jsonSchema richiesto in modo condizionale


96

In jsonSchema puoi indicare se i campi definiti sono obbligatori o meno utilizzando l' requiredattributo:

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "header": {
            "type": "object",
            "properties": {
                "messageName": {
                    "type": "string"
                },
                "messageVersion": {
                    "type": "string"
                }
            },
            "required": [
                "messageName",
                "messageVersion"
            ]
        }
    },
    "required": [
        "header"
    ]
}

In alcuni casi, vorrei che il messageVersioncampo non fosse obbligatorio. C'è un modo per condizionare l'obbligatorietà di questo campo?


Sì, dovrebbe essere possibile. Quali informazioni nei dati farebbero scattare l'obbligatorietà?
jruizaranguren

@SarveswaranMeenakshiSundaram - Non so di aver usato solo v4 dello schema json
tom redfern

È possibile nella versione 3?
Sarvesh

@SarveswaranMeenakshiSundaram - Non lo so. Provalo e facci sapere per favore!
tom redfern

Risposte:


261

A seconda della situazione, esistono diversi approcci. Posso pensare a quattro modi diversi per richiedere in modo condizionale un campo.

Dipendenze

La dependenciesparola chiave è una variazione condizionale della requiredparola chiave. Foreach proprietà in dependencies, se la proprietà è presente nel JSON da convalidare, anche lo schema associato a quella chiave deve essere valido. Se è presente la proprietà "foo", è richiesta la proprietà "bar"

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "dependencies": {
    "foo": { "required": ["bar"] }
  }
}

C'è anche una forma breve se lo schema contiene solo la requiredparola chiave.

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "dependencies": {
    "foo": ["bar"]
  }
}

Coinvolgimento

Se la tua condizione dipende dal valore di un campo, puoi utilizzare un concetto logico booleano chiamato implicazione. "A implica B" significa effettivamente, se A è vero, allora anche B deve essere vero. L'implicazione può anche essere espressa come "! A o B". O la proprietà "foo" non è uguale a "bar" oppure è richiesta la proprietà "bar" . Oppure, in altre parole: se la proprietà "foo" è uguale a "bar", allora è richiesta la proprietà "bar"

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "anyOf": [
    {
      "not": {
        "properties": {
          "foo": { "const": "bar" }
        },
        "required": ["foo"]
      }
    },
    { "required": ["bar"] }
  ]
}

Se "foo" non è uguale a "bar", la #/anyOf/0corrispondenza e la convalida hanno esito positivo. Se "foo" è uguale a "bar", #/anyOf/0fallisce e #/anyOf/1deve essere valido affinché la anyOfconvalida abbia successo.

Enum

Se il tuo condizionale è basato su un'enumerazione, è un po 'più semplice. "foo" può essere "bar" o "baz". Se "foo" è uguale a "bar", allora "bar" è obbligatorio. Se "foo" è uguale a "baz", è necessario "baz".

{
  "type": "object",
  "properties": {
    "foo": { "enum": ["bar", "baz"] },
    "bar": { "type": "string" },
    "baz": { "type": "string" }
  },
  "anyOf": [
    {
      "properties": {
        "foo": { "const": "bar" }
      },
      "required": ["bar"]
    },
    {
      "properties": {
        "foo": { "const": "baz" }
      },
      "required": ["baz"]
    }
  ]
}

If-Then-Else

Una relativamente nuova aggiunta alla JSON Schema (progetto-07) aggiunge i if, thene le elseparole chiave. Se la proprietà "foo" è uguale a "bar", allora è richiesta la proprietà "bar"

{
  "type": "object",
  "properties": {
    "foo": { "type": "string" },
    "bar": { "type": "string" }
  },
  "if": {
    "properties": {
      "foo": { "const": "bar" }
    },
    "required": ["foo"]
  },
  "then": { "required": ["bar"] }
}

EDIT 12/23/2017: sezione Implication aggiornata e sezione If-Then-Else aggiunta.

EDIT 06/04/2018: Correzione del bug per If-Then-Else e aggiornamento dei singleton enumda utilizzare const.


7
@scubbo Non sono un fan delle if-then-elseparole chiave e mi rifiuto di usarle. Ma, se scegli di usarlo, ti suggerisco sempre di racchiuderli in un allOfche contiene solo quelle tre parole chiave. { ...other_keywords..., "allOf": [{ "if": ..., "then": ..., "else": ... }], ...more_keywords... }
Jason Desrosiers

2
@ Jason Perché non un fan di if...? Penso che una breve opinione su questo nella tua risposta sarebbe del tutto giustificata. O è una lunga storia?
Clay Bridges

6
@ClayBridges La sezione dei commenti non è il posto giusto per quella discussione, ma ecco la versione breve. Come regola generale, le parole chiave dello schema JSON sono senza stato. Nessuna informazione diversa dal valore della parola chiave può essere utilizzata per convalidare l'istanza. if, thene elseviolano questa regola perché dipendono l'uno dall'altro.
Jason Desrosiers

3
@GGirard, questo è il miglior trattamento dell'uso di questi modelli nello schema JSON di cui sono a conoscenza. Le operazioni booleane sono ufficialmente documentate ma il resto è solo matematica. allOf== AND, anyOf== OR, oneOf== XOR e not== NOT. Puoi google "algebra booleana" per più risorse sulla matematica (come l'implicazione).
Jason Desrosiers,

2
@AlexeyShrub Volevo scrivere su questo da un po ', ma sono stato distratto da altre cose. Sono un fan dell'idea di un condizionale. Rende più facile la comprensione per le persone. La mia obiezione riguarda il modo in cui è stata definita come tre parole chiave stateful separate (vedi commento precedente). La presenza di parole chiave che violano le proprietà architettoniche seguite da altre parole chiave rende i validatori di schemi JSON più difficili da implementare e meno efficienti. Se i condizionali fossero definiti in un modo diverso che fosse apolide, non avrei obiezioni.
Jason Desrosiers
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.