Related
I'm trying to create a json schema for the following structure:
{
"stages":
{
"STAGE1":
{
"stage_type" : "GSX",
"params":
{
"x": "setting_x", <- x mandatory for stage type "GSX"
"y": "setting_y" <- y mandatory for stage type "GSX"
}
},
"STAGE2":
{
"stage_type" : "GSZ",
"params":
{
"z": "setting_z" <- z mandatory for stage type "GSZ"
}
}
}
}
The idea is that "stage_type" is an enum with possible values ["GSX", "GSZ", ...]. The logic that I would like to implement is:
If "stage_type" == "GSX" -> require "params": {"x"} and require "params": {"y"}
If "stage_type" == "GSZ" -> require "params": {"z"}
I'm failing however, at implementing this logic for required properties... Here is how far I've got:
{
"type": "object",
"properties":
{
"stages":
{
"type": "object",
"additionalProperties":
{
"type": "object",
"properties":
{
"stage_type":
{
"type": "string",
"enum": [ "GSX", "GSZ" ]
},
"params":
{
"type": "object",
"properties":
{
"x": { "type": "string" },
"y": { "type": "string" },
"z": { "type": "string" }
},
"additionalProperties": false
}
},
"required": ["stage_type", "params"],
"allOf":
[
{
"if": { "properties": { "stage_type": { "enum": ["GSX"] } } },
"then": { "required": ["x", "y"] }
},
{
"if": { "properties": { "stage_type": { "enum": ["GSZ"] } } },
"then": { "required": ["z"] }
}
]
},
"minProperties": 1,
"uniqueItems": true
}
},
"additionalProperties": false
}
I can't seem to make the nesting of the required fileds in the if-then clauses work... Help would be very much appreciated! :)
In your original schema, the allOf is applied to the schema level at the additionalProperties of "stages". At this level the validator has no scope of the child properties defined at the "params" property. A possible solution could be:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "JSON schema generated with JSONBuddy https://www.json-buddy.com",
"type": "object",
"definitions": {
"params": {
"type": "object",
"properties": {
"x": { "type": "string" },
"y": { "type": "string" },
"z": { "type": "string" }
},
"additionalProperties": false
},
"params_required_z": {
"allOf": [
{ "$ref": "#/definitions/params" },
{ "required": [ "z" ] }
]
},
"params_required_x_y": {
"allOf": [
{ "$ref": "#/definitions/params" },
{ "required": [ "x", "y" ] }
]
}
},
"properties": {
"stages": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"stage_type": {
"type": "string",
"enum": [ "GSX", "GSZ" ]
}
},
"allOf": [
{
"if": {
"properties": {
"stage_type": {
"enum": [ "GSX" ]
}
}
},
"then": {
"properties": {
"params": {
"$ref": "#/definitions/params_required_x_y"
}
}
}
},
{
"if": {
"properties": {
"stage_type": {
"enum": [ "GSZ" ]
}
}
},
"then": {
"properties": {
"params": {
"$ref": "#/definitions/params_required_z"
}
}
}
}
],
"required": [ "stage_type", "params" ]
},
"minProperties": 1,
"uniqueItems": true
}
},
"additionalProperties": false
}
I am attempting to validate the following JSON file:
{
"Transaction": {
"Header": {
"Workflow": "Rejection",
"Job-Offer": {
"Offer-Status": "New",
"Datetime-Offered": "2017-12-15T16:00:00",
"Accepted": "YES",
"Datetime-Accepted": "2017-12-15T16:00:00"
}
}
}
}
against the following schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Schema",
"description": "Schema",
"$ref": "#/defs/Schema",
"defs": {
"Schema": {
"type": "object",
"additionalProperties": false,
"properties": {
"Transaction": {
"$ref": "#/defs/Transaction"
}
},
"required": [
"Transaction"
],
"title": "Schema"
},
"Transaction": {
"type": "object",
"additionalProperties": false,
"properties": {
"Transaction-Header": {
"$ref": "#/defs/Transaction-Header"
}
},
"required": [
"Transaction-Header"
],
"title": "Transaction"
},
"Transaction-Header": {
"type": "object",
"additionalProperties": false,
"properties": {
"Workflow": {
"type": "string",
"enum": [
"Offer",
"Transfer",
"Acceptance",
"Rejection",
"Cancellation",
"Update"
]
},
"Job-Offer": {
"$ref": "#/defs/JobOffer"
}
},
"required": [
"Workflow"
],
"title": "Transaction-Header"
},
"JobOffer": {
"description": "Job Offer.",
"type": "object",
"additionalProperties": true,
"properties": {
"Offer-Status": {
"type": "string",
"enum": [
"New",
""
]
},
"Datetime-Offered": {
"type": "string",
"format": "date-time"
},
"Accepted": {
"type": "string",
"enum": [
"YES",
"NO",
""
]
},
"Datetime-Accepted": {
"type": "string",
"format": "date-time"
},
"Reason-Rejected": {
"type": "string",
"minLength": 0,
"maxLength": 30
},
"Offer-Cancelled": {
"type": "string",
"enum": [
"YES",
"NO",
""
]
},
"Datetime-Cancelled": {
"type": "string",
"format": "date-time"
}
},
"allOf": [
{ "$ref": "#/defs/JOBACCEPT" },
{ "$ref": "#/defs/JOBREJECT" }
],
"required": [
"Offer-Status"
],
"title": "JobOffer"
},
"JOBACCEPT": {
"properties": {
"Workflow": { "enum": [ "Acceptance" ] }
},
"required": [
"Accepted",
"Datetime-Accepted"
],
},
"JOBREJECT": {
"properties": {
"Workflow": { "enum": [ "Rejection" ] }
},
"required": [
"Reason-Rejected"
],
}
}
}
What I am after is:
If the Workflow of "Acceptance" is selected, the fields under JOBACCEPT are required.
If the Workflow of "Rejection" is selected, the fields under JOBREJECT are required.
I have tried many different combinations of oneOf, allOf, anyOf, if-then-else but nothing seems to work correctly.
Anyone have any ideas what needs to be done?
Re-worked json inline:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"type": "object",
"properties": {
"Transaction": {
"type": "object",
"properties": {
"Transaction-Header": {
"type": "object",
"properties": {
"Workflow": {
"type": "string",
"enum": [
"Offer",
"Transfer",
"Acceptance",
"Rejection",
"Cancellation",
"Update"
]
},
"Job-Offer": {
"type": "object",
"properties": {
"Offer-Status": {
"type": "string",
"enum": [
"New",
""
]
},
"Datetime-Offered": {
"type": "string",
"format": "date-time"
},
"Accepted": {
"type": "string",
"enum": [
"YES",
"NO",
""
]
},
"Datetime-Accepted": {
"type": "string",
"format": "date-time"
},
"Reason-Rejected": {
"type": "string",
"minLength": 0,
"maxLength": 30
},
"Offer-Cancelled": {
"type": "string",
"enum": [
"YES",
"NO",
""
]
},
"Datetime-Cancelled": {
"type": "string",
"format": "date-time"
}
},
"required": [
"Offer-Status"
]
},
"readOnly": true
},
"required": [
"Workflow"
]
}
},
"required": [
"Transaction-Header"
]
}
},
"allOf": [
{
"if": {
"properties": {
"Transaction": {
"properties": {
"Transaction-Header": {
"properties": {
"Workflow": {
"enum": [
"Acceptance"
]
}
},
"required": [
"Workflow"
]
}
}
}
}
},
"then": {
"properties": {
"Transaction": {
"properties": {
"Transaction-Header": {
"properties": {
"Job-Offer": {
"properties": {},
"required": [
"Accepted",
"Datetime-Accepted"
]
}
}
}
}
}
}
}
}
],
"required": [
"Transaction"
]}
You had the right idea. The problem is where you've placed the allOf with your conditionals. You have it in the "JobOffer" schema, but are trying to set constraints on the "Workflow" property which is in the "Transaction-Header" schema. There is no way to reference a property that is higher up in the JSON tree structure, so you need to move the allOf up into the "Transaction-Header" schema so you can set constraints on the "Workflow" property.
Now that it's in the right place, the best way to express your conditional constraints is with if/then. The context of the if/then is now the the "Transaction-Header" schema, so the then schemas needs to not just say what properties are required, they need to declare that those properties are in the "Job-Offer" object.
{
...
"defs": {
...
"Transaction-Header": {
...
"allOf": [
{ "$ref": "#/defs/JOBACCEPT" },
{ "$ref": "#/defs/JOBREJECT" }
]
},
"JOBACCEPT": {
"if": {
"type": "object",
"properties": {
"Workflow": { "enum": ["Acceptance"] }
},
"required": ["Workflow"]
},
"then": {
"properties": {
"Job-Offer": {
"required": ["Accepted", "Datetime-Accepted"]
}
}
}
},
"JOBREJECT": { ... Similar to JOBACCEPT ... }
}
}
You're abstracting everything away into definitions *, so it's tricky to express conditionals that reference things multiple layers deep. If you inline all the definitions, it gets a little easier to see what needs to be done.
The if/then keywords need to be at the level of 'Transaction'. In pseudocode:
"if the property 'Header' exists (i.e. required) and its value is ... (const), then require property ... with value (type=object, required properties=[...], property definitions=...)", and so on.
* by the way, in version 2020-12 the definitions keyword is $defs -- it may work the way you have it, but implementations will be unable to validate the schemas undef defs as they won't recognize them there, so some errors can slip through and be harder to find.
I'd like to reference and factor the following json schema in multiple files for a better handling regarding its properties. Files as "$ref": "book.json" and "$ref": "pencil.json" which each file has its own properties and validations (and of course, that it works "addProperties = false"), I have the following schema:
{
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["Pencil", "Book"]
},
"title": {
"type": "string"
},
"content": {
"type": "string"
},
"domain": {
"type": "string"
},
"img_url": {
"type": "string"
},
"url": {
"type": "string"
}
},
"allOf": [
{
"if": {
"properties": {
"type": {
"enum": ["Book"]
}
}
},
"then": {
"required": [
"domain", "img_url", "url"
],
"not" : {
"anyOf" : [
{ "required" : ["content"] }
]
}
}
},
{
"if": {
"properties": {
"type": {
"enum": ["Pencil"]
}
}
},
"then": {
"required": [
"content"
],
"not" : {
"anyOf" : [
{ "required" : ["domain"] },
{ "required" : ["img_url"] },
{ "required" : ["url"] }
]
}
}
}
]
}
and I would like something like this:
# book.json
{
"properties": {
"content": {
"type": "string"
}
},
"if": {
"properties": {
"type": {
"enum": ["Book"]
}
}
},
"then": {
"required": [
"content"
],
"not" : {
"anyOf" : [
{ "required" : ["domain"] },
{ "required" : ["img_url"] },
{ "required" : ["url"] }
]
}
}
}
# pencil.json
{
"properties":{
"domain": {
"type": "string"
},
"img_url": {
"type": "string"
},
"url": {
"type": "string"
}
},
"if": {
"properties": {
"type": {
"enum": ["Pencil"]
}
}
},
"then": {
"required": [
"domain", "img_url", "url"
],
"not" : {
"anyOf" : [
{ "required" : ["content"] }
]
}
}
}
# properties.json
{
"additionalProperties": false,
"properties": {
"$ref": book.json,
"$ref": pencil.json
}
I would like to simplify it, whether a property is of the book or pencil type then it refers to the file where this file has its properties and validations.
I am running into more children objects that are not validating correctly (object.actor, object.verb, object.object). I tried looking for any empty schema after changing my if/then structures in the object schema to if/then/else adding the false value for each else. I did not find anything obvious.
JSON -Should fail but doesn't
{
"actor": {
"objectType": "Agent",
"name": "xAPI account",
"mbox": "mailto:xapi#adlnet.gov"
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/attended",
"display": {
"en-GB": "attended",
"en-US": "attended"
}
},
"object": {
"objectType": "SubStatement",
"actor": {
"objectType": "should fail",
"name": "xAPI mbox",
"mbox": "mailto:should fail"
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/reported",
"display": {
"should fail": "reported",
"en-US": "reported"
}
},
"object": {
"objectType": "Activity",
"id": "should fail"
}
}
}
JSON - Fails at the root level only; substatement values are not checked. assuming empty schema coming from somewhere.
{
"actor": {
"objectType": "Agent",
"name": "xAPI account",
"mbox": "this fails"
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/attended",
"display": {
"this fails": "attended",
"en-US": "attended"
}
},
"object": {
"objectType": "SubStatement",
"actor": {
"objectType": "should fail",
"name": "xAPI mbox",
"mbox": "mailto:should fail"
},
"verb": {
"id": "http://adlnet.gov/expapi/verbs/reported",
"display": {
"should fail": "reported",
"en-US": "reported"
}
},
"object": {
"objectType": "Activity",
"id": "should fail"
}
}
}
JSON SCHEMA (stripped to the bone)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "xAPIValidator",
"description": "Validation schema for xAPI tests",
"type": "object",
"allOf": [
{
"$ref": "#/definitions/Statement"
},
{
"statements": [
{
"$ref": "#/definitions/Statement"
}
]
}
],
"definitions": {
"Statement": {
"additionalProperties": false,
"properties": {
"objectType": {
"type:": "string",
"enum": [
"Agent",
"Activity",
"Group",
"SubStatement",
"StatementRef"
]
},
"id": {
"allOf": [
{
"$ref": "#/definitions/uuid"
}
]
},
"actor": {
"$id": "#actor",
"allOf": [
{
"$ref": "#/definitions/allOfAgentGroup"
}
]
},
"verb": {
"$id": "#verb",
"type": "object",
"properties": {
"id": {
"allOf": [
{
"$ref": "#/definitions/URI"
}
]
},
"display": {
"type": "object",
"allOf": [
{
"$ref": "#/definitions/lang5646"
}
]
}
}
},
"object": {
"$id": "#object",
"type": "object",
"properties": {
"objectType": {
"type:": "string",
"enum": [
"Activity",
"Agent",
"Group",
"SubStatement",
"StatementRef"
]
}
},
"oneOf": [
{
"if": {
"properties": {
"objectType": {
"const": "SubStatement"
}
}
},
"then": {
"$comment": "Substatement object type",
"allOf": [
{
"$ref": "#/definitions/Statement"
}
],
"allOf": [
{
"not": {
"required": [
"id"
]
}
},
{
"not": {
"required": [
"authority"
]
}
},
{
"not": {
"required": [
"stored"
]
}
},
{"required":["actor","verb","object"]}
]
},
"else": false
}
]
}
},
"required": [
"actor",
"verb",
"object"
]
},
"Agent": {
"$id": "#Agent",
"maxProperties": 3,
"allOf": [
{
"$ref": "#/definitions/IFI"
}
]
},
"AnonGroup": {
"$id": "#AnonGroup",
"maxProperties": 3,
"properties": {
"member": {
"type": "array",
"items": [
{
"allOf": [
{
"$ref": "#/definitions/allOfAgentGroup"
}
]
}
]
}
},
"dependencies": {
"objectType": [
"member"
]
},
"required": [
"member"
],
"not": {
"required": [
"mbox"
]
},
"not": {
"required": [
"mbox_sha1sum"
]
},
"not": {
"required": [
"openid"
]
},
"not": {
"required": [
"account"
]
}
},
"IdGroup": {
"$id": "#IdGroup",
"maxProperties": 4,
"properties": {
"member": {
"type": "array",
"items": [
{
"oneOf": [
{
"$ref": "#/definitions/allOfAgentGroup"
}
]
}
]
}
},
"oneOf": [
{
"$ref": "#/definitions/IFI"
}
]
},
"allOfAgentGroup": {
"properties": {
"objectType": {
"type": "string",
"enum": [
"Agent",
"Group"
]
},
"name": {
"type": "string"
}
},
"oneOf": [
{
"if": {
"properties": {
"objectType": {
"const": "Agent"
}
}
},
"then": {
"allOf": [
{
"$ref": "#/definitions/Agent"
}
]
},
"else": false
},
{
"if": {
"properties": {
"objectType": {
"const": "Group"
}
}
},
"then": {
"oneOf": [
{
"allOf": [
{
"$ref": "#/definitions/IdGroup"
}
]
},
{
"allOf": [
{
"$ref": "#/definitions/AnonGroup"
}
]
}
]
},
"else": false
}
]
},
"IFI": {
"oneOf": [
{
"properties": {
"mbox": {
"allOf": [
{
"$ref": "#/definitions/mailto"
}
]
}
},
"required": [
"mbox"
]
},
{
"properties": {
"mbox_sha1sum": {
"type": "string",
"pattern": "\\b[0-9a-f]{5,40}\\b"
}
},
"required": [
"mbox_sha1sum"
]
},
{
"properties": {
"account": {
"properties": {
"homePage": {
"allOf": [
{
"$ref": "#/definitions/URI"
}
]
},
"name": {
"type": "string"
}
},
"required": [
"homePage",
"name"
]
}
},
"required": [
"account"
]
},
{
"properties": {
"openid": {
"allOf": [
{
"$ref": "#/definitions/URI"
}
]
}
},
"required": [
"openid"
]
}
]
},
"mailto": {
"type": "string",
"pattern": "(mailto:)(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")#(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"
},
"URI": {
"type": "string",
"pattern": "^(https?|ftp|file)://[-a-zA-Z0-9+&##/%?=~_|!:,.;]*[-a-zA-Z0-9+&##/%=~_|]"
},
"uuid": {
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
},
"lang5646": {
"type": "object",
"patternProperties": {
"^((?:(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?:([A-Za-z]{2,3}(-(?:[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?:[A-Za-z]{4}))?(-(?:[A-Za-z]{2}|[0-9]{3}))?(-(?:[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?:[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?:x(-[A-Za-z0-9]{1,8})+))?)|(?:x(-[A-Za-z0-9]{1,8})+))$": {
"type": "string"
}
},
"additionalProperties": false
},
"lang5646string": {
"type": "string",
"pattern": "^((?:(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?:([A-Za-z]{2,3}(-(?:[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?:[A-Za-z]{4}))?(-(?:[A-Za-z]{2}|[0-9]{3}))?(-(?:[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?:[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?:x(-[A-Za-z0-9]{1,8})+))?)|(?:x(-[A-Za-z0-9]{1,8})+))$"
}
}
}
In "$id": "#object" > oneOf > then, you define allOf twice in that JSON object.
The behaviour of duplicate keys in JSON is undefined.
Often the way it's handled is just to take the last occurrence of each key for an object.
You can see this working by having the following schema and an empty object instance: {}
Schema :
{
"allOf": [
false
],
"allOf": [
true
]
}
The JSON library will likely ignore the first allOf, taking the last occurrence, resulting in allways pass validation. Swap the true and false to double confirm.
Any time you've used a specific *of keyword more than once in the same object in the schema (or any key more than once in an object), you'll need to fix it.
I have a json file with nested objects.
{
"apiVersion":"0.0.9b",
"apiDate":"18.01.19",
"general":{
"documentType": "invoice",
"references":{
"invoiceId":"123",
"invoiceDate":"01.01.1970",
"creditNoteId":"123",
"creditNoteDate":"01.01.1970"
}
}
}
Now I would like to define that invoiceId and invoiceDate should be required if documentType is invoice, and also the other way arraound (creditNoteId and Date are required if documentType is creditNote).
All other Properties should be optional.
Pseudo-Code:
documentType = invoice
- required: invoiceId, invoiceDate
- optional: creditNoteId, creditNoteDate
documentType = creditNote
- required: creditNoteId, creditNoteDate
- optional: invoiceId, invoiceDate
If i store all properties in the same object I found this working solution:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"apiVersion",
"apiDate"
],
"properties": {
"apiVersion": {
"type": "string",
"description": "The version of the json file"
},
"apiDate": {
"type": "string",
"description": "The date when the json version was published"
},
"general": {
"$ref": "#/definitions/general_identifiers"
}
},
"definitions" : {
"general_identifiers" : {
"type": "object",
"required": [
"documentType"
],
"properties": {
"documentType": {
"enum": [
"invoice",
"creditNote"
]
},
"invoiceId": {
"type": "string"
},
"invoiceDate": {
"type": "string"
},
"creditNoteId": {
"type": "string"
},
"creditNoteDate": {
"type": "string"
}
},
"oneOf": [
{
"$comment": "Invoice",
"properties": {
"documentType": { "enum": ["invoice"] }
},
"required": ["invoiceId", "invoiceDate"]
},
{
"$comment": "CreditNote",
"properties": {
"documentType": { "enum": ["creditNote"] }
},
"required": ["creditNoteId", "creditNoteDate"]
}
]
}
}
}
Is there a way to display this dependency with nested objects used in the above json?
What I tried already was:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"apiVersion",
"apiDate"
],
"properties": {
"apiVersion": {
"type": "string",
"description": "The version of the json file"
},
"apiDate": {
"type": "string",
"description": "The date when the json version was published"
},
"general": {
"$ref": "#/definitions/general_identifiers"
},
"references": {
"type": "object",
"properties": {
"invoiceId": {
"type": "string"
},
"invoiceDate": {
"type": "string"
},
"creditNoteId": {
"type": "string"
},
"creditNoteDate": {
"type": "string"
}
},
"oneOf": [
{
"$comment": "Invoice",
"properties": {
"documentType": { "enum": ["invoice"] }
},
"required": ["invoiceId", "invoiceDate"]
},
{
"$comment": "CreditNote",
"properties": {
"documentType": { "enum": ["creditNote"] }
},
"required": ["creditNoteId", "creditNoteDate"]
}
]
}
},
"definitions" : {
"general_identifiers" : {
"type": "object",
"required": [
"documentType"
],
"properties": {
"documentType": {
"enum": [
"invoice",
"creditNote"
]
}
}
}
}
}
But with this i get an Error from https://www.jsonschemavalidator.net
Message: JSON is valid against more than one schema from 'oneOf'. Valid schema indexes: 0, 1.
What have I missed?
You're very close. You just need to pull your oneOf up to the top level so you can reference #/properties/general and #/properties/references from the same schema.
Also, you almost always want to use anyOf instead of oneOf. oneOf enforces that one and only one schema in the list validates. When the schemas are mutually exclusive, oneOf is just asking the validator to do unnecessary work.
"anyOf": [
{
"properties": {
"general": {
"properties": {
"documentType": { "enum": ["invoice"] }
}
},
"references": {
"required": ["invoiceId", "invoiceDate"]
}
}
},
{
"properties": {
"general": {
"properties": {
"documentType": { "enum": ["creditNote"] }
}
},
"references": {
"required": ["creditNoteId", "creditNoteDate"]
}
}
}
]
With the help of Jason Desrosiers I finaly found a solution also for my nested json.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"apiVersion",
"apiDate"
],
"anyOf": [
{
"properties": {
"general": {
"properties": {
"documentType": { "enum": ["invoice"] },
"references": {
"required": ["invoiceId", "invoiceDate"]
}
}
}
}
},
{
"properties": {
"general": {
"properties": {
"documentType": { "enum": ["creditNote"] },
"references": {
"required": ["creditNoteId", "creditNoteDate"]
}
}
}
}
}
],
"properties": {
"apiVersion": {
"type": "string",
"description": "The version of the json file"
},
"apiDate": {
"type": "string",
"description": "The date when the json version was published"
},
"general": {
"$ref": "#/definitions/general_identifiers",
"references": {
"type": "object",
"properties": {
"invoiceId": {
"type": "string"
},
"invoiceDate": {
"type": "string"
},
"creditNoteId": {
"type": "string"
},
"creditNoteDate": {
"type": "string"
}
}
}
}
},
"definitions" : {
"general_identifiers" : {
"type": "object",
"required": [
"documentType"
],
"properties": {
"documentType": {
"enum": [
"invoice",
"creditNote"
]
}
}
}
}
}