jsonSchema-Attribut bedingt erforderlich

94

In jsonSchema können Sie mithilfe des requiredAttributs angeben, ob definierte Felder obligatorisch sind oder nicht :

{
    "$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 bestimmten Fällen möchte ich, dass das messageVersionFeld nicht obligatorisch ist. Gibt es eine Möglichkeit, die Verpflichtung dieses Feldes abhängig zu machen?

Tom Redfern
quelle
Ja, das sollte möglich sein. Welche Informationen in den Daten würden die Pflicht auslösen?
Jruizaranguren
@SarveswaranMeenakshiSundaram - Ich weiß nicht, dass ich nur v4 des JSON-Schemas verwendet habe
Tom Redfern
Ist das in Version 3 überhaupt möglich?
Sarvesh
@SarveswaranMeenakshiSundaram - Ich weiß es nicht. Probieren Sie es aus und lassen Sie es uns bitte wissen!
Tom Redfern

Antworten:

258

Abhängig von Ihrer Situation gibt es verschiedene Ansätze. Ich kann mir vier verschiedene Möglichkeiten vorstellen, ein Feld bedingt zu benötigen.

Abhängigkeiten

Das dependenciesSchlüsselwort ist eine bedingte Variation des requiredSchlüsselworts. Für jede Eigenschaft in muss dependencies, wenn die Eigenschaft in dem zu validierenden JSON vorhanden ist, auch das diesem Schlüssel zugeordnete Schema gültig sein. Wenn die Eigenschaft "foo" vorhanden ist, ist die Eigenschaft "bar" erforderlich

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

Es gibt auch eine Kurzform, wenn das Schema nur das requiredSchlüsselwort enthält .

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

Implikation

Wenn Ihre Bedingung vom Wert eines Feldes abhängt, können Sie ein boolesches Logikkonzept namens Implikation verwenden. "A impliziert B" bedeutet effektiv, wenn B wahr ist, muss B auch wahr sein. Implikation kann auch als "! A oder B" ausgedrückt werden. Entweder entspricht die Eigenschaft "foo" nicht "bar", oder die Eigenschaft "bar" ist erforderlich . Oder mit anderen Worten: Wenn die Eigenschaft "foo" gleich "bar" ist, ist die Eigenschaft "bar" erforderlich

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

Wenn "foo" nicht gleich "bar" ist, sind #/anyOf/0Übereinstimmungen und Validierungen erfolgreich. Wenn "foo" gleich "bar" ist, #/anyOf/0schlägt dies fehl und #/anyOf/1muss gültig sein, damit die anyOfValidierung erfolgreich ist.

Aufzählung

Wenn Ihre Bedingung auf einer Aufzählung basiert, ist sie etwas einfacher. "foo" kann "bar" oder "baz" sein. Wenn "foo" gleich "bar" ist, ist "bar" erforderlich. Wenn "foo" gleich "baz" ist, ist "baz" erforderlich.

{
  "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"]
    }
  ]
}

Wenn-Dann-Sonst

Eine relativ neue Ergänzung zu JSON Schema (draft-07) fügt die if, thenund elseSchlüsselwörter. Wenn die Eigenschaft "foo" gleich "bar" ist, ist die Eigenschaft "bar" erforderlich

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

EDIT 23.12.2017: Implikationsabschnitt aktualisiert und If-Then-Else-Abschnitt hinzugefügt.

EDIT 06/04/2018: Bugfix für If-Then-Else und Update Singletons enumzur Verwendung const.

Jason Desrosiers
quelle
7
@scubbo Ich bin kein Fan der if-then-elseKeywords und lehne es ab, sie zu verwenden. Wenn Sie es jedoch verwenden möchten, empfehle ich, sie immer in ein Zeichen zu verpacken allOf, das nur diese drei Schlüsselwörter enthält. { ...other_keywords..., "allOf": [{ "if": ..., "then": ..., "else": ... }], ...more_keywords... }
Jason Desrosiers
2
@ Jason Warum nicht ein Fan von if...? Ich denke, eine kurze Meinung dazu in Ihrer Antwort wäre völlig gerechtfertigt. Oder ist es eine lange Geschichte?
Clay Bridges
6
@ClayBridges Der Kommentarbereich ist nicht der richtige Ort für diese Diskussion, aber hier ist die Kurzversion. JSON-Schema-Schlüsselwörter sind in der Regel zustandslos. Zur Validierung der Instanz können keine anderen Informationen als der Schlüsselwortwert verwendet werden. if, thenUnd elseverletzen diese Regel , weil sie voneinander abhängig sind .
Jason Desrosiers
3
@GGirard, dies ist die beste Behandlung für die Verwendung dieser Muster im JSON-Schema, die mir bekannt ist. Die booleschen Operationen sind offiziell dokumentiert, der Rest ist nur Mathematik. allOf== AND, anyOf== OR, oneOf== XOR und not== NOT. Sie können "Boolesche Algebra" googeln, um mehr Ressourcen für die Mathematik zu erhalten (z. B. Implikation).
Jason Desrosiers
2
@AlexeyShrub Ich wollte schon eine Weile darüber schreiben, wurde aber von anderen Dingen abgelenkt. Ich bin ein Fan der Idee einer Bedingung. Es macht es den Menschen leichter zu verstehen. Mein Einwand ist die Art und Weise, wie es als drei separate zustandsbehaftete Schlüsselwörter definiert wurde (siehe vorherigen Kommentar). Wenn Schlüsselwörter vorhanden sind, die die architektonischen Eigenschaften anderer Schlüsselwörter verletzen, sind JSON-Schema-Validatoren schwieriger zu implementieren und weniger effizient. Wenn Bedingungen auf eine andere Weise definiert würden, die staatenlos wäre, hätte ich nichts dagegen.
Jason Desrosiers