1

Given this example JSON:

{
  "type": "number",
  "values": [ 34, 42, 99 ]
}

Is it possible to define JSON Schema that makes sure that the contents of the values array are of the type specified in another property (in this example type)?

Above type is saying that the array values can only contain integers (using the specifier "number").

Or specify that values contains strings:

{
  "type": "string",
  "values": [ "hello", "world" ]
}
Diego Barros
  • 2,071
  • 2
  • 33
  • 45
  • Yes, but you will have to write an `if/then` block for each type you want to support. Sorry I don't have time to write a proper answer with examples. Let me know if this information doesn't help much! =] – Relequestual Feb 15 '19 at 09:36
  • Did you need further help on this? If not, have you considered accepting one of the existing answers? – Relequestual May 21 '20 at 14:13

2 Answers2

0

Yes you can use the "items" keyword. If it has a single value then that value is the schema for every element of the array.

{
    "type": "array",
    "items": { "type: "string" }
}

Assuming you're using a draft4 schema like most people do, section 8.2.3.1 of the specification states:

8.2.3.1. If "items" is a schema

If items is a schema, then the child instance must be valid against this schema, regardless of its index, and regardless of the value of "additionalItems".

Community
  • 1
  • 1
Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79
  • 1
    iirc, the OP is asking if they can dynamically validate a field based on the value of another field. – Relequestual Feb 15 '19 at 09:34
  • What is your evidence for saying most people are using draft-4? I think that's false based on the questions we get on the JSON Schema slack on a daily basis. – Relequestual Feb 15 '19 at 09:36
  • @Relequestual you are correct when you say I was wanting to dynamically validate the contents of a collection from another field. I know that may not be possible, or a bit unorthodox, but I thought I'd still ask and be sure. Thanks. – Diego Barros Feb 16 '19 at 03:58
  • @erwin-bolwidt Thank you for the response. Is it possible to somehow have the "items" say that the contents of the array can be either numbers or string, for example? – Diego Barros Feb 16 '19 at 04:01
  • @Relequestual I'm sorry - I didn't think that this was a controversial statement. I've read this somewhere and I found it confirmed; for example the schemas on json.schemastore.org - 179 are draft-04, 6 are draft-06 and 11 are draft-07. And the popular validators for the JVM support draft4 only - one of the reasons for writing a new validator that supports draft 7. – Erwin Bolwidt Feb 24 '19 at 00:08
  • @ErwinBolwidt No problem. There are two Java libraries that are documented to support draft-7 that we know about on the site. Please feel free to add yours if it is ready. Libraries that only support draft-4 may seem more popular because they will be older. Some are likely abandonded. Sorry if I was a little abrupt. We are trying to encourage people to think latest draft first whenever possible. – Relequestual Feb 25 '19 at 09:35
0

Yes, but you will have to write an if/then block for each type you want to support.

The Understanding JSON Schema has a section on if/then/else: http://json-schema.org/understanding-json-schema/reference/conditionals.html

Here is an extract that explains how if/then/else works.

For example, let’s say you wanted to write a schema to handle addresses in the United States and Canada. These countries have different postal code formats, and we want to select which format to validate against based on the country. If the address is in the United States, the postal_code field is a “zipcode”: five numeric digits followed by an optional four digit suffix. If the address is in Canada, the postal_code field is a six digit alphanumeric string where letters and numbers alternate.

{
  "type": "object",
  "properties": {
    "street_address": {
      "type": "string"
    },
    "country": {
      "enum": ["United States of America", "Canada"]
    }
  },
  "if": {
    "properties": { "country": { "const": "United States of America" } }
  },
  "then": {
    "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
  },
  "else": {
    "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
  }
}

For each type you want to support, you would need to write if/then object, and wrap all of them in an allOf.

Relequestual
  • 11,631
  • 6
  • 47
  • 83