首页 > 其他分享 >Json Schema简介和Json Schema的.net实现库 LateApexEarlySpeed.Json.Schema

Json Schema简介和Json Schema的.net实现库 LateApexEarlySpeed.Json.Schema

时间:2023-12-26 12:33:06浏览次数:38  
标签:LateApexEarlySpeed json validationResult instance Json Schema schema

什么是Json Schema ?

Json Schema是一种声明式语言,它可以用来标识Json的结构,数据类型和数据的具体限制,它提供了描述期望Json结构的标准化方法。
利用Json Schema, 你可以定义Json结构的各种规则,以便确定Json数据在各个子系统中交互传输时保持兼容和一致的格式。

一般来说,系统可以自己实现逻辑来判断当前json是否满足接口要求,比如是否某个字段存在,是否属性值是有效的。但当验证需求变得复杂后,比如有大量嵌套json结构,属性之间的复杂关联限制等等,则容易编写出考虑不全的验证代码。另外,当系统需要动态的json数据要求,比如先由用户自己决定他需要的json结构,然后系统根据用户表达的定制化json结构需求,帮助用户验证后续的json数据。这种系统代码编译时无法确定的json结构,就需要另一种解决方案。

Json Schema就是针对这种问题的比较自然的解决方案。它可以让你或你的用户描述希望的json结构和值的内容限制,有效属性,是否是required, 还有有效值的定义,等等。。利用Json Schema, 人们可以更好的理解Json结构,而且程序也可以根据你的Json Schema验证Json数据。

比如下面的一个简单例子,用.net下的Json Schema实现库LateApexEarlySpeed.Json.Schema进行Json数据的验证:

Json Schema (文件:schema.json):

{
  "type": "object",
  "properties": {
    "propBoolean": {
      "type": "boolean"
    },
    "propArray": {
      "type": "array",
      "uniqueItems": true
    }
  }
}

Json 数据 (文件:instance.json):

{
  "propBoolean": true,
  "propArray": [ 1, 2, 3, 4, 4 ]
}

C# 代码:

            string jsonSchema = File.ReadAllText("schema.json");
            string instance = File.ReadAllText("instance.json");

            var jsonValidator = new JsonValidator(jsonSchema);
            ValidationResult validationResult = jsonValidator.Validate(instance);

            if (validationResult.IsValid)
            {
                Console.WriteLine("good");
            }
            else
            {
                Console.WriteLine($"Failed keyword: {validationResult.Keyword}");
                Console.WriteLine($"ResultCode: {validationResult.ResultCode}");
                Console.WriteLine($"Error message: {validationResult.ErrorMessage}");
                Console.WriteLine($"Failed instance location: {validationResult.InstanceLocation}");
                Console.WriteLine($"Failed relative keyword location: {validationResult.RelativeKeywordLocation}");
            }

输出:

Failed keyword: uniqueItems
ResultCode: DuplicatedArrayItems
Error message: There are duplicated array items
Failed instance location: /propArray
Failed relative keyword location: /properties/propArray/uniqueItems

LateApexEarlySpeed.Json.Schema中文介绍

项目原始文档:https://github.com/lateapexearlyspeed/Lateapexearlyspeed.JsonSchema.Doc

中文文档:
LateApexEarlySpeed.Json.Schema是2023年12月发布的一个新的.net下的Json Schema实现库,基于截止到2023年12月为止最新版的Json schema - draft 2020.12。
Json Schema验证功能经过了official json schema test-suite for draft 2020.12的测试。(部分排除的用例见下面的已知限制章节)
LateApexEarlySpeed.Json.Schema的主要特点是:

  • 基于微软.net下默认的System.Text.Json而非经典的Newtonsoft.Json
  • 使用简单
  • 和已有的知名且杰出的.net下的一些JsonSchema实现库相比,具有很好的性能 (在common case下,利用BenchmarkDotnet进行的性能测试)。用户请根据自己的使用场景进行性能验证

该实现库之后可能会transfer成开源项目。

基础用法

安装Nuget package

Install-Package LateApexEarlySpeed.Json.Schema
string jsonSchema = File.ReadAllText("schema.json");
string instance = File.ReadAllText("instance.json");

var jsonValidator = new JsonValidator(jsonSchema);
ValidationResult validationResult = jsonValidator.Validate(instance);

if (validationResult.IsValid)
{
    Console.WriteLine("good");
}
else
{
    Console.WriteLine($"Failed keyword: {validationResult.Keyword}");
    Console.WriteLine($"ResultCode: {validationResult.ResultCode}");
    Console.WriteLine($"Error message: {validationResult.ErrorMessage}");
    Console.WriteLine($"Failed instance location: {validationResult.InstanceLocation}");
    Console.WriteLine($"Failed relative keyword location: {validationResult.RelativeKeywordLocation}");
    Console.WriteLine($"Failed schema resource base uri: {validationResult.SchemaResourceBaseUri}");
}

输出信息

当json数据验证失败后,可以查看错误数据的具体信息:

  • IsValid: As summary indicator for passed validation or failed validation.

  • ResultCode: The specific error type when validation failed.

  • ErrorMessage: the specific wording for human readable message

  • Keyword: current keyword when validation failed

  • InstanceLocation: The location of the JSON value within the instance being validated. The value is a JSON Pointer.

  • RelativeKeywordLocation: The relative location of the validating keyword that follows the validation path. The value is a JSON Pointer, and it includes any by-reference applicators such as "$ref" or "$dynamicRef". Eg:

    /properties/width/$ref/minimum
    
  • SubSchemaRefFullUri: The absolute, dereferenced location of the validating keyword when validation failed. The value is a full URI using the canonical URI of the relevant schema resource with a JSON Pointer fragment, and it doesn't include by-reference applicators such as "$ref" or "$dynamicRef" as non-terminal path components. Eg:

    https://example.com/schemas/common#/$defs/count/minimum
    
  • SchemaResourceBaseUri: The absolute base URI of referenced json schema resource when validation failed. Eg:

    https://example.com/schemas/common
    

性能建议

尽可能的重用已实例化的JsonValidator实例(JsonValidator可以简单理解为代表一个json schema验证文档)来验证json数据,以便获得更高性能

外部json schema依赖的支持

除了自动支持当前schema文档内的引用关系,还支持外部json schema依赖:

  • 本地schema依赖文本
var jsonValidator = new JsonValidator(jsonSchema);
string externalJsonSchema = File.ReadAllText("schema2.json");
jsonValidator.AddExternalDocument(externalJsonSchema);
ValidationResult validationResult = jsonValidator.Validate(instance);
  • 远程schema url (实现库将访问网络来获得远程的schema)
var jsonValidator = new JsonValidator(jsonSchema);
await jsonValidator.AddHttpDocumentAsync(new Uri("http://this-is-json-schema-document"));
ValidationResult validationResult = jsonValidator.Validate(instance);

自定义keyword的支持

除了json schema specification中的标准keywords之外,还支持用户创建自定义keyword来实现额外的验证需求:

{
  "type": "object",
  "properties": {
    "prop1": {
      "customKeyword": "Expected value"
    }
  }
}
ValidationKeywordRegistry.AddKeyword<CustomKeyword>();
[Keyword("customKeyword")] // It is your custom keyword name
[JsonConverter(typeof(CustomKeywordJsonConverter))] // Use 'CustomKeywordJsonConverter' to deserialize to 'CustomKeyword' instance out from json schema text
internal class CustomKeyword : KeywordBase
{
    private readonly string _customValue; // Simple example value

    public CustomKeyword(string customValue)
    {
        _customValue = customValue;
    }

    // Do your custom validation work here
    protected override ValidationResult ValidateCore(JsonInstanceElement instance, JsonSchemaOptions options)
    {
        if (instance.ValueKind != JsonValueKind.String)
        {
            return ValidationResult.ValidResult;
        }

        return instance.GetString() == _customValue
            ? ValidationResult.ValidResult
            : ValidationResult.CreateFailedResult(ResultCode.UnexpectedValue, "It is not my expected value.", options.ValidationPathStack, Name, instance.Location);
    }
}
internal class CustomKeywordJsonConverter : JsonConverter<CustomKeyword>
{
    // Library will input json value of your custom keyword: "customKeyword" to this method.
    public override CustomKeyword? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // Briefly: 
        return new CustomKeyword(reader.GetString()!);
    }

    public override void Write(Utf8JsonWriter writer, CustomKeyword value, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }
}

Format支持

目前实现库支持如下format:

  • uri
  • uri-reference
  • date
  • time
  • date-time
  • email
  • uuid
  • hostname
  • ipv4
  • ipv6
  • json-pointer
  • regex

Format 验证需要显式enable, 当验证数据时,请传入配置好的 JsonSchemaOptions:

jsonValidator.Validate(instance, new JsonSchemaOptions{ValidateFormat = true});

如果需要自定义format验证,可以实现一个FormatValidator子类并注册:

[Format("custom_format")] // this is your custom format name in json schema
public class TestCustomFormatValidator : FormatValidator
{
    public override bool Validate(string content)
    {
        // custom format validation logic here...
    }
}

// register it globally
FormatRegistry.AddFormatType<TestCustomFormatValidator>();

Other extension usage doc is to be continued .

限制

  • 目前类库关注于验证,暂不支持annotation
  • 因为暂不支持annotation, 所以不支持如下keywords: unevaluatedProperties, unevaluatedItems
  • 目前不支持 content-encoded string

问题报告

欢迎把使用过程中遇到的问题和希望增加的功能发到github repo issue中

More doc is to be written

标签:LateApexEarlySpeed,json,validationResult,instance,Json,Schema,schema
From: https://www.cnblogs.com/dotnet-diagnostic/p/17927879.html

相关文章

  • MySql之json_extract函数处理json字段
    转自:链接:https://juejin.cn/post/7103482347894358046 MySql之json_extract函数处理json字段在db中存储json格式的数据,相信大家都或多或少的使用过,那么在查询这个json结构中的数据时,有什么好的方法么?取出String之后再代码中进行解析?接下来本文将介绍一下Mysql5.7+之后提供的......
  • java alibaba fastjson自定义序列化反序列化(教你解决问题思路)
    大家版本不一样方式可能不一样,我不管你的fastjson版本是哪个,按照我这个思路去弄就行写一个JSONObject类,导入fastjson的JSONObject,然后CTRL+鼠标左键点进去看JSONObject源码,然后点击IDEA的左上角selectopenedfile来定位到当前打开的文件。然后看当前目录这边可以看到上面有个Seria......
  • java读取yaml文件并转化成json格式数据
    一、在maven项目中导入依赖<!--yaml文件转化成json格式--><dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>1.29</version></de......
  • 推荐给程序员的chrome扩展插件:gitzip for github下载单个GitHub仓库中的文件;json-hand
    推荐清单gitzipforgithub下载单个GitHub仓库中的文件双击文件,勾选文件前面的复选框,可以一次性选择多个文件json-handle格式化json......
  • JSONPATH-阿里和jayway的实现测试
    业务业务的需要,所以想找一个从对象中获取属性的工具。搜了搜发现由阿里和jayway的实现,又花费了一些时间了解和练习,总结了一些要点:阿里的可能快一些,但考虑到完备性,也许选择jayway更好一些。本文档参考了以下URL:JaywayJsonPath介绍_com.jayway.jsonpath-CSDN博客FASTJSON2JSO......
  • RapidJSON
    RapidJSON 是一个C++的JSON解析器及生成器。它的灵感来自RapidXml。RapidJSON小而全。它同时支持SAX和DOM风格的API。SAX解析器只有约500行代码 【chatgpt】 RapidJSON、cJSON和JsonCpp都是JSON解析器/生成器的C++库,它们的目标都是提供快速、轻量级......
  • C# .NET的BinaryFormatter、protobuf-net、Newtonsoft.Json以及自己写的序列化方法序
    https://www.cnblogs.com/s0611163/p/11872484.html测试结果整理后: 结论:1、这几个工具中,protobuf-net序列化和反序列化效率是最快的2、BinaryFormatter和Newtonsoft.Json反序列化慢的比较多3、Newtonsoft.Json序列化后的文件体积比较大4、Newtonsoft.Json在序列化反序列......
  • Jmeter:http请求及json断言
    一前言环境:window10jmeter5.3对jmeter的http请求和json断言这2个组件中的一些字段进行简单说明二http请求如上,可以选择切换语言,有时切换成中文或者英文,这样需要填写字段的意思更加一目了然三json断言断言请求返回的json数据数时,jmeter中默认有2种方式可选,如下这里......
  • Python JSON格式字符串与对象之间的转换多种方法
    ​ 1、json.dumps()和json.loads()方法使用 json.dumps() 方法将Python对象转换为JSON格式字符串。使用 json.loads() 方法将JSON格式字符串解析为Python对象。使用示例:PythonJSON格式字符串与对象之间的转换多种方法-CJavaPy2、json.dump()和json.load(......
  • 放弃FastJson!一篇就够,Jackson的功能原来如此之牛(万字干货)
    放弃FastJson!一篇就够,Jackson的功能原来如此之牛(万字干货)转载自:https://zhuanlan.zhihu.com/p/352485162在上篇《经过多方调研,最终还是决定禁用FastJson!》中,讲了FastJson的基本使用以及存在的不确定性问题,所以最终决定在项目中放弃使用,进而选择市面上比较主流,SpringBoot默......