2
votes

I have spent all day trying to get this to work, will post a list of references and things I have tried after the question.

So here is my jsonschema:

{
    "data": [{
        "required": "effort",
        "decisive": "maybe",
        "field1": 7
    },
    {
        "required": "effort",
        "decisive": "no",
        "field1": 6
    }],
    "schema": {
        "$schema": "http://json-schema.org/draft-04/schema#",
        "type": "array",
        "items": {
            "type": "object",
            "properties": {
                "field1": {
                    "type": "string",
                    "pattern": "[A-Z]",
                    "title": "field1"
                },
                "required": {
                    "type": "string",
                    "title": "required",
                    "readonly": true
                },
                "decisive": {
                    "type": "string",
                    "title": "Decisive",
                    "enum": ["yes", "no", "maybe", "not now"]
                }

            }
        }
    }
}

Consider the exact piece of jsonschema but with the field1 element as follows:

"field1": {
    "type": "integer",
    "minimum": 5,
    "maximum": 10,
    "title": "field1"
}
  • The first example validates only capital letters in its field1
  • The second wants an integer between 5 and 10.

How can you make it validate either of these, so both are accepted -

  • either only capital letters
  • or an integer between 5 and 10?

Oh - the field1 in the data section above is not that important, it is a desired default value.

I have tried all kinds of ideas - with oneOf - here, here, here

param - here

additionalProperties - here

required - here

The intuitive thing was to use the oneOf on pattern, but oneOf, as is mentioned in many questions, does not do anything inside the properties section, only outside it. So I tried to have the exact same properties inside a oneOf with just the one difference as described above. That did not work either, and contains a lot of repetition which must somehow be avoidable.

Does anyone know how to solve this? Am out of ideas..

1
Out of interest, is this an assignment of some kind, or work? Seen a few very similar questions over the past few days?Relequestual
It's work. I think everyone is trying to use jsonschema for forms even if it wasn't made for that. I have a question with a bounty at the moment to try to save us from alpaca so we can stay more within Python.cardamom

1 Answers

3
votes

You were one the right track with oneOf, except what you actually want is anyOf. Almost every time you think you want oneOf, you really want anyOf. Remember that the values of properties are schemas just like any other. You can use the boolean keywords there just like anywhere else.

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "field1": {
                "title": "field1"
                "anyOf": [
                    {
                        "type": "string",
                        "pattern": "[A-Z]"
                    },
                    {
                        "type": "integer",
                        "minimum": 5,
                        "maximum": 10
                    }
                ]
            },
            "required": {
                "type": "string",
                "title": "required",
                "readonly": true
            },
            "decisive": {
                "type": "string",
                "title": "Decisive",
                "enum": ["yes", "no", "maybe", "not now"]
            }

        }
    }
}

Edit 1

When you hear that oneOf can't be used inside properties, this is the kind of thing they are talking about.

{
  "type": "object",
  "properties": {
    "anyOf": [
      {
        "field1": { ... }
      },
      {
        "field1": { ... }
      }
    ],
    "required": { ... },
    "decisive": { ... }
  }
}

Edit 2

Because it came up in the comments, here's a better explanation of why oneOf is almost never the right choice. To be clear, oneOf will always work in place of anyOf. If anyOf didn't exist, JSON Schema wouldn't loose any expressive power.

However, anyOf is a more precise tool. Using oneOf when anyOf will do is like using a sledge hammer to drive a nail when you have a simple claw hammer in your toolbox.

anyOf is the boolean OR operation. oneOf is the boolean "exclusive OR" (XOR) operation. "XOR" has so little usefulness, that modern languages don't even have support for it. OR is usually represented with the operator ||. XOR has no analog.

anyOf means any of the items can be true. oneOf means one and only one of the items can be true. When you use oneOf, the validator needs to test all of the schemas to ensure that one schema validates as true and the rest validate as false. When you use anyOf, the validator can stop as soon as it finds a schema that validates as true. This is called "short circuiting" and all modern programming languages do this when evaluating OR operations. When the schemas are mutually exclusive (which they almost always are), continuing to validate schemas after one is found is pure waste and therefore should be avoided.

I think oneOf is overused because from a natural language perspective, it sounds right.