如何使用 JsonSchema.Net 验证 JSON 架构是否符合 JSON 架构标准)

问题描述 投票:0回答:3

我一直在努力尝试根据元模式验证 json 模式(检查 json 是否确实遵循 JSON 模式标准)。 我尝试遵循文档linklink。我基于官方 JSON Schema 规范

我的用例是这样的:我正在开发一个端点,它可以接收带有模式的 json。该模式稍后将用于验证某些实体,但我也想验证模式本身。

我尝试了所有这些,但它们都返回相同的结果..有效..所以在我看来他们没有验证任何内容..

private void ValidateSchema(string schemaString)
{
    var element = JsonNode.Parse(schemaString);
    var metaSchema = Json.Schema.MetaSchemas.Metadata202012; // tried also with Json.Schema.MetaSchemas.Draft202012;
    var options = new ValidationOptions
    {
        OutputFormat = OutputFormat.Detailed,
        ValidateMetaSchema = false // tried also with true
    };
    var results = metaSchema.Validate(element, options);
}

这些是我尝试过的输入。我预计有些会返回无效。

@"{""f"":""a""}"
@"{}"
@"{""required"": [""prop1"", ""prop2"", ""prop3"", ""prop4"", ""prop5"", ""prop6""]}"
@"{
""$schema"": ""http://json-schema.org/draft-07/schema#"",
""type"": ""object"",
""required"": [""prop1"", ""prop2"", ""prop3"", ""prop4"", ""prop5"", ""prop6""]
}"
c# jsonschema json-everything
3个回答
4
投票

就代码而言,您做得正确,并且不需要

ValidateMetaSchema
选项。该选项根据其元模式验证模式,同时您根据模式验证其他 JSON 数据。

例如,如果我反序列化了你的最后一个示例

{
  "$schema": ""http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [
    "prop1",
    "prop2",
    "prop3",
    "prop4",
    "prop5", 
    "prop6"
  ]
}

进入

JsonSchema
,我使用它来验证其他一些 JSON 数据,然后该选项将根据草案 7 元架构添加架构的二次验证。如果架构由于某种原因无效(例如,在草案 7 中,
"$defs": 42
将被忽略,但在草案 2020-12 中它无效),则
$schema
关键字将引发错误,该错误将包含在输出中。

在您的情况下,您将直接根据其元模式(只是其本身)验证草案 7 元模式。但我们已经知道草案 7 元模式对其自身有效,因此这只是一个不必要的额外检查。继续并关闭该选项。


在评论中,您询问是否有办法在存在未知关键字时引发错误。没有这样的选项。

但是,您可以做的是检查

schema.Keywords
属性是否有任何
UnrecognizedKeyword
类型。如果有的话,那么架构中有额外的数据。

但请注意模式可以嵌套,因此您需要检查每个级别。

{
  "allOf": [
    { "unrecognized": "keyword" }
  ]
}

在这里,您需要找到

AllOfKeyword
并检查其子模式中的
UnrecognizedKeyword


除此之外,我将稍微扩展@Clemens 的答案,以解释为什么你的示例返回有效。

{
  "f": "a"
}

当针对元模式进行验证时,此 JSON 将产生与第二个示例相同的验证结果

{}
因为(如 @Clemens 提到的)JSON 模式会忽略未知关键字。由于
f
不是可识别的关键字,因此验证会忽略它。 (不过,为
f
输出收集了注释。)

因为其中没有验证关键字,所以它将验证所有 JSON 实例。 技术上这是一个有效的模式,尽管它没有做太多事情。

{
  "required": [
    "prop1",
    "prop2",
    "prop3",
    "prop4",
    "prop5",
    "prop6"
  ]
}

在这里,您需要存在某些属性 if JSON 实例是一个对象。但如果实例 不是 对象,则

required
不起作用。您可能希望使用
"type": "object"
来更多地限制值。

{
  "$schema": ""http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": [
    "prop1",
    "prop2",
    "prop3",
    "prop4",
    "prop5", 
    "prop6"
  ]
}

在这里,所有的部分都已就位,并且您可能期望的可以发挥作用。 JSON 仍然是有效的草案 7 架构(它对于草案 2020-12 也有效)。

为了使架构无效,您必须为其不支持的已定义关键字添加有效值,例如为

maximum
提供一个字符串值。在这种情况下,架构将无法验证。

也就是说,如果您尝试将无效模式 JSON 反序列化为

JsonSchema
模型,序列化程序将抛出异常,因为反序列化期间会发生 some 验证。

我认为根据元模式验证模式 JSON 的方法比让序列化程序抛出异常更好,但您需要确保根据

$schema
关键字中表示的元模式进行验证。 (因此,不要根据草案 7 元模式验证 2020-12 草案模式。)


3
投票

元模式验证未涵盖您的示例。元模式使用开放模型,并且也没有语义检查。您需要一个 JSON 模式 linter,例如 JSONBuddy (https://www.json-buddy.com) 附带的那种,也可以在 json-schema-linter.com 上获取以进行快速测试。


2
投票

我在这里发布了我在 @gregsdennis 的回答后使用的代码,这样任何人都可以使用它:

private static void ValidateSchema(string schema)
{
    JsonSchema jsonSchema;
    try
    {
        jsonSchema = JsonSerializer.Deserialize<JsonSchema>(schema)!;
    }
    catch (Exception e)
    {
        throw new ArgumentException($"Submitted schema is invalid. Could not deserialize. Error: {e.Message}");
    }

    if (jsonSchema.Keywords == null)
    {
        throw new ArgumentException($"Submitted schema is invalid. No Keywords found.");
    }
    var unrecognizedKeywords = jsonSchema.Keywords!.Where(k => k is UnrecognizedKeyword).ToArray();
    if (unrecognizedKeywords.Any())
    {
        var data = string.Join(", ", unrecognizedKeywords.Select(SerializeForLogging));
        throw new ArgumentException($"Submitted schema is invalid. Unrecognized Keywords: {data}");
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.