简体   繁体   中英

How to validate JSON document with nested documents in arrays conditionally?

I've the following example JSON document:

{
    "level0key1": "foo0",
    "level0key2": "bar0",
    "level0array1": [
      {
        "level1key1": "foo1-0",
        "level1key2": "bar1-0"
      },
      {
        "level1key1": "foo1-1",
        "level1key2": "bar1-1"
      }
      
    ],
    "level0doc1": {
       "dockey1": "foo-doc-1",
       "dockey2": "foo-doc-2"
    }
}

I want to build a JSON Schema to check the following condition: In case "level0key1" = "foo0" each document of "level0array1" must have a field "level1key1".

What I have so far is the following JSON Schema:

{
    "$schema": "https://json-schema.org/draft/2019-09/schema",
    "title": "test",
    "type": "object",
    "required": [],
    "properties": {
        "level0key1": {
            "type": "string"
        },
        "level0key2": {
            "type": "string"
        },
        "level0array1": {
            "type": "array",
            "properties": {
                "level1key1": {
                    "type": "string"
                },
                "level1key2": {
                    "type": "string"
                }

            }

        }
    },
    "allOf": [{
            "if": {
                "properties": {
                    "level0key1": { "const": "foo0" }
                },
                "required": ["level0key1"]
            },
            "then": {
                "required": ["level0key2"]
            }
        }, {
            "if": {
                "properties": {
                    "level0key1": { "const": "foo0" }
                },
                "required": ["level0key1"]
            },
            "then": {
                "required": ["level0array1/[]/level1key1"]
            }
        }

    ]
}

The first check within the "allOf" array is just for testing purpose and works like expected. The second one is failing all the time. I suppose the syntax for addressing the field within the array is wrong. I experimented with the asterisk as wildcard and using dots instead of slashes.

I also tried to put the condition within the 'level0array1' definition. But I do not get this to work too.

For testing my schema I used https://www.jsonschemavalidator.net

Any hints how to fix it?

Thanks a lot!

I found a workaround for my problem. But I believe there must a better solutions. So any suggestions are still welcome.

My workaround is to define two 'types' of array items: ArrayItem and ArrayItemRequireKey . The second one has the same definition like the first one except that the field level1key1 is required. After this I can use if/then/else to use one or the other type in condition to my/any other field (with the same level of the hierarchy).

The new schema looks like this:

{
    "$schema": "https://json-schema.org/draft/2019-09/schema",
    "title": "test",
    "type": "object",
    "required": [],
    "properties": {
        "level0key1": {
            "type": "string"
        },
        "level0key2": {
            "type": "string"
        }
    },
    "allOf": [{
            "if": {
                "properties": {
                    "level0key1": {"const": "foo0"}
                },
                "required": ["level0key1"]
            },
            "then": {
                "required": ["level0key2"]
            }
        }, {
            "if": {
                "properties": {
                    "level0key1": {"const": "foo0"}
                },
                "required": ["level0key1"]
            },
            "then": {
                "properties": {
                    "level0array1": {
                        "type": "array",
                        "items": {
                            "$ref": "#/$defs/ArrayItemRequireKey"
                        }
                    }
                },
                "required": ["level0array1"]
            },
            "else": {
                "properties": {
                    "level0array1": {
                        "type": "array",
                        "items": {
                            "$ref": "#/$defs/ArrayItem"
                        }
                    }
                },
                "required": ["level0array1"]
            }
        }
    ],
    "$defs": {
        "ArrayItem": {
            "type": "object",
            "properties": {
                "level1key1": {
                    "type": "string"
                },
                "level1key2": {
                    "type": "string"
                }
            }
        },
        "ArrayItemRequireKey": {
            "allOf": [{ "$ref": "#/$defs/ArrayItem" }],
            "required": ["level1key1"]
        }
    }
}

Be aware: In my case/with my library this does not work with the json schema version of 2020-12. I have to use 2019-09 to get it running.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM