Newtonsoft.Json.Schema 未根据 JSON 模式正确验证 JSON 输入

Newtonsoft.Json.Schema is not validating JSON input correctly against a JSON schema

在下面的示例中,架构验证为以下负载 JSON 返回 true,即使:

为什么这些错误没有被捕获?

我们正在使用 Newtonsoft.Json.Schema 进行验证。

JSON 架构:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {
        "article_metadata": {
            "description": "article metadata for descrepancy checks",
            "type": "object",
            "properties": {
                "authors": {
                    "description": "authors details",
                    "type": "object",
                    "properties": {
                        "list": {
                            "type": "array",
                            "items": {
                                "sequence_id": {
                                    "type": "string"
                                },
                                "guid": {
                                    "description": "32 digit unique id to identify author",
                                    "type": "string"
                                },
                                "name": {
                                    "type": "object",
                                    "properties": {
                                        "prefix": {
                                            "type": "string"
                                        },
                                        "given_name": {
                                            "type": "array",
                                            "minItems": 1,
                                            "items": {
                                                "type": "string"
                                            }
                                        },
                                        "family_name": {
                                            "type": "string"
                                        },
                                        "required": [
                                            "family_name",
                                            "given_name"
                                        ]
                                    }
                                },
                                "required": [
                                    "sequence_id",
                                    "name"
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
}

有效载荷JSON:

{
    "article_metadata": {
        "authors": {
            "list": [{
                    "sequence_id": "Au1",
                    "guid": "00208406-c337-4f58-9245-9455d8852a00",
                    "affiliation_id": "Aff1",
                    "name": {
                        "prefix": "Ms.",
                        "family_name": "Hole"
                    }
                }, {
                    "sequence_id": "Au2",
                    "guid": "32b8a598-2fb5-42f1-ad0e-94ce2fc00a8f",
                    "affiliation_id": "Aff2",
                    "name": {
                        "prefix": "Mr.",
                        "given_name": "Anurag"
                    }
                }
            ]
        }
    }
}

您的问题可以通过演示重现 fiddle #1 here.

让我们尝试将其分解为 Minimal, Reproducible Example。如果我们从整体模式中仅提取 "name" 个对象的模式,它看起来像:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {
        "prefix": {
            "type": "string"
        },
        "given_name": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "string"
            }
        },
        "family_name": {
            "type": "string"
        },
        "required": [
            "family_name",
            "given_name"
        ]
    }
}

并且缺少所有必需属性的相应无效 JSON 对象如下所示:

{
  "prefix": "Mr."
}

如果我尝试根据此架构验证 JSON,则无法解析架构本身,并引发以下错误:

Newtonsoft.Json.Schema.JSchemaReaderException: Unexpected token encountered when reading value for 'required'. Expected StartObject, Boolean, got StartArray. Path 'properties.required', line 18, position 53.

演示 fiddle #2 here.

这里的问题是您已将所需属性列表 添加为 属性 本身 。您需要从属性列表中提取所需的属性,如下所示:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {
        "prefix": {
            "type": "string"
        },
        "given_name": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "string"
            }
        },
        "family_name": {
            "type": "string"
        }
    },
    "required": [
        "family_name",
        "given_name"
    ]
}

现在您的架构将成功加载并正确验证 "name" 对象,生成以下错误:

Required properties are missing from object: family_name, given_name. Path '', line 1, position 2.

演示 fiddle #3 here.

但是,您的原始 JSON 架构不会引发 JSchemaReaderException 错误,它只是无法正确验证。这是为什么?您用于 "list" 数组项的语法似乎是错误的——错误的程度足以使 Json.NET 模式解析器变得混乱。为此,您可以立即列出您希望在数组项中找到的 属性 值,如下所示:

{
    "type": "array",
    "items": {
        "sequence_id": {
            "type": "string"
        },
        "guid": {
            "description": "32 digit unique id to identify author",
            "type": "string"
        },
        "name": {
           // Contents omitted for brevity
        },
        "required": [
            "sequence_id",
            "name"
        ]
    }
}

但是,如https://json-schema.org/understanding-json-schema/reference/array.html所示,数组项的定义方式与定义属性值或根对象的方式相同,特别是通过指示"type"项目(此处 "object"),然后给出特定于类型的约束。因此,您的模式的这一部分应该如下所示:

{
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "sequence_id": {
                "type": "string"
            },
            "guid": {
                "description": "32 digit unique id to identify author",
                "type": "string"
            },
            "name": {
                 // Contents omitted for brevity
            }
        },
        "required": [
            "sequence_id",
            "name"
        ]
    }
}

当我对您的架构进行此更正时,您的 JSON 现在可以正确验证,生成以下错误:

Required properties are missing from object: given_name. Path 'article_metadata.authors.list[0].name', line 8, position 29.
Invalid type. Expected Array but got String. Path 'article_metadata.authors.list[1].name.given_name', line 18, position 46.
Required properties are missing from object: family_name. Path 'article_metadata.authors.list[1].name', line 16, position 29.

您的最终架构应如下所示:

{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "properties": {
        "article_metadata": {
            "description": "article metadata for descrepancy checks",
            "type": "object",
            "properties": {
                "authors": {
                    "description": "authors details",
                    "type": "object",
                    "properties": {
                        "list": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "sequence_id": {
                                        "type": "string"
                                    },
                                    "guid": {
                                        "description": "32 digit unique id to identify author",
                                        "type": "string"
                                    },
                                    "name": {
                                        "type": "object",
                                        "properties": {
                                            "prefix": {
                                                "type": "string"
                                            },
                                            "given_name": {
                                                "type": "array",
                                                "items": {
                                                    "type": "string"
                                                },
                                                "minItems": 1
                                            },
                                            "family_name": {
                                                "type": "string"
                                            }
                                        },
                                        "required": [
                                            "family_name",
                                            "given_name"
                                        ]
                                    }
                                },
                                "required": [
                                    "sequence_id",
                                    "name"
                                ]
                            }
                        }
                    }
                }
            }
        }
    }
}

演示 fiddle #4 here.