Json Schema: Require a property only when a specif

2019-02-26 16:01发布

I need to build a json schema (draft 4) that requires a property based on the presence of a property in another nested object. I already searched and tried a lot of things (anyOf, oneOf, not, dependencies) with no luck.

Maybe this is not possible to in json schema?

This is my simplified schema:

{
  "$schema": "http://json-schema.org/draft-04/schema#",  
  "type": "object",
  "required": ["dog"],
  "properties": {
    "dog": {
      "type": "object",
      "required": ["bananas"],
      "properties": {
        "bananas": { "$ref": "bananas.json" },
        "thing": {
          "type": "object",
          "properties": {
            "total": { "type": "string" }
          }
        }
      }
    }
  }
}

And this is bananas.json

{
  "$schema": "http://json-schema.org/draft-04/schema#",  
  "type": "object",
  "required": ["banana"],
  "definitions": {
    "non-empty-string": {
        "type": "string",
        "minLength": 1
    }
  },
  "properties": {
    "banana": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": ["unit"],
        "properties": {
          "unit": { "type": "string" },
          "thing": {
            "type": "object",
            "anyOf": [
              { "required": [ "tax_transfers" ] },
              { "required": [ "tax_retentions" ] }
            ],
            "properties": {
              "tax_transfers": {
                "type": "object",
                "required": ["tax_transfer"],
                "properties": {
                  "tax_transfer": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "properties": {
                        "rate": { "type": "string" }
                      }
                    }
                  }
                }
              },
              "tax_retentions": {
                "type": "object",
                "required": ["tax_retention"],
                "properties": {
                  "tax_retention": {
                    "type": "array",
                    "minItems": 1,
                    "items": {
                      "type": "object",
                      "properties": {
                        "rate": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

I need that when one or more objects in the array have a 'thing' property (at bananas -> banana -> thing). Then the property 'thing' at (dog -> thing) should be required.

Any help would be really appreciated.

标签: jsonschema
1条回答
聊天终结者
2楼-- · 2019-02-26 16:49

You need two things to express your constraint. The first is "contains" and the other is "implication". I've organized each in the definitions section.

Contains

The items keyword allows us to require that all items in an array are valid against a schema. If it is not true that all of the items in the array are not valid against the schema, then we know that at least one item is valid.

{
  "not": {
    "items": { "not": { ... schema ... } }
  }
}

If you are able to upgrade to JSON Schema draft-06, a contains keyword was added to make this much easier.

{
  "contains": { ... schema ... }
}

Implication

Implication allows you to do something like a conditional. The condition schema implies the constraint schema if either the condition is true, or the constraint is true (or both are true). It's effectively the same as saying, if the condition is true then the constraint must also be true.

{
  "anyOf": [
    { "not": { ... condition schema ... } },
    { ... constraint schema ... }
  ]
}

JSON Schema draft-07 adds the if-then-else keywords in attempt to address this case better. I personally dislike the way this was done enough that I'll stick with the implication pattern for this kind of thing, but here it is in case you want to try it.

{
  "if": { ... schema ... },
  "then": { ... schema ... },
  "else": { ... schema ... }
}

All together

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "required": ["dog"],
  "properties": {
    "dog": {
      "type": "object",
      "required": ["bananas"],
      "properties": {
        "bananas": { "$ref": "bananas.json" },
        "thing": { "type": "object" }
      }
    }
  },
  "allOf": [
    { "$ref": "#/definitions/banana-things-implies-dog-things" }
  ],
  "definitions": {
    "banana-has-things": {
      "properties": {
        "dog": {
          "properties": {
            "bananas": {
              "properties": {
                "banana": {
                  "not": {
                    "items": { "not": { "required": ["things"] } }
                  }
                }
              }
            }
          }
        }
      }
    },
    "banana-things-implies-dog-things": {
      "anyOf": [
        { "not": { "$ref": "#/definitions/banana-has-things" }},
        {
          "properties": {
            "dog": { "required": ["things"] }
          }
        }
      ]
    }
  }
}
查看更多
登录 后发表回答