Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I require one field or another or (one of two others) but not all of them?

I am having trouble coming up with a JSON schema that will validate if the JSON contains either:

  • one field only
  • another field only
  • (one of two other fields) only

but not to match when multiples of those are present.

In my case specifically, I want one of

  • copyAll
  • fileNames
  • matchesFiles and/or doesntMatchFiles

to validate but I don't want to accept when more than that is there.

Here's what I've got so far:

{     "$schema": "http://json-schema.org/draft-04/schema#",     "type": "object",     "required": [ "unrelatedA" ],     "properties": {     "unrelatedA": {         "type": "string"     },     "fileNames": {         "type": "array"     },     "copyAll": {         "type": "boolean"     },     "matchesFiles": {         "type": "array"     },     "doesntMatchFiles": {         "type": "array"         }     },     "oneOf": [          {"required": ["copyAll"], "not":{"required":["matchesFiles"]}, "not":{"required":["doesntMatchFiles"]}, "not":{"required":["fileNames"]}},          {"required": ["fileNames"], "not":{"required":["matchesFiles"]}, "not":{"required":["doesntMatchFiles"]}, "not":{"required":["copyAll"]}},          {"anyOf": [                {"required": ["matchesFiles"], "not":{"required":["copyAll"]}, "not":{"required":["fileNames"]}},                {"required": ["doesntMatchFiles"], "not":{"required":["copyAll"]}, "not":{"required":["fileNames"]}}]}     ] } ; 

This matches more than I want to. I want this to match all of the following:

{"copyAll": true, "unrelatedA":"xxx"} {"fileNames": ["aab", "cab"], "unrelatedA":"xxx"} {"matchesFiles": ["a*"], "unrelatedA":"xxx"} {"doesntMatchFiles": ["a*"], "unrelatedA":"xxx"} {"matchesFiles": ["a*"], "doesntMatchFiles": ["*b"], "unrelatedA":"xxx"} 

but not to match:

{"copyAll": true, "matchesFiles":["a*"], "unrelatedA":"xxx"} {"fileNames": ["a"], "matchesFiles":["a*"], "unrelatedA":"xxx"} {"copyAll": true, "doesntMatchFiles": ["*b"], "matchesFiles":["a*"], "unrelatedA":"xxx"} {"fileNames": ["a"], "matchesFiles":["a*"], "unrelatedA":"xxx"} {"unrelatedA":"xxx"} 

I'm guessing there's something obvious I'm missing - I'd like to know what it is.

like image 819
user3486184 Avatar asked Jun 03 '14 19:06

user3486184


1 Answers

The problem is the "not" semantics. "not required" does not mean "inclusion forbidden". It just means that you don't have to add it in order to validate that schema.

However, you can use "oneOf" to satisfy your specification in a simpler way. Remember that it means that "just one of these schemas can validate". The following schema achieves the property switching you are attempting to solve:

{     "$schema": "http://json-schema.org/draft-04/schema#",     "type": "object",     "required": [         "unrelatedA"     ],     "properties": {         "unrelatedA": {             "type": "string"         },         "fileNames": {             "type": "array"         },         "copyAll": {             "type": "boolean"         },         "matchesFiles": {             "type": "array"         },         "doesntMatchFiles": {             "type": "array"         }     },     "oneOf": [         {             "required": [                 "copyAll"             ]         },         {             "required": [                 "fileNames"             ]         },         {             "anyOf": [                 {                     "required": [                         "matchesFiles"                     ]                 },                 {                     "required": [                         "doesntMatchFiles"                     ]                 }             ]         }     ] } 
like image 80
jruizaranguren Avatar answered Sep 30 '22 07:09

jruizaranguren