65.9K
CodeProject 正在变化。 阅读更多。
Home

JSON 版本 4 到 C# 对象和反向 - 第 1 部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (20投票s)

2015年4月1日

CPOL

18分钟阅读

viewsIcon

45278

downloadIcon

1025

一套用于创建和操作 JSON Schema 和实例的 C# 类。

引言

需要一种方式来定义一个表单,并将此表单从数据库服务器下载到移动、Web 或桌面平台。填写好的表单随后提交给数据库服务器。关于如何定义这些表单,我考虑了两种选择:XML 和 JavaScript 对象表示法 (JSON)。起初强烈倾向于 XML,但 PostgreSQL 的 jsonb 数据类型允许高效存储和查询 JSON 数据,这使得 JSON 占据了优势。

解决了这个问题后,便开始寻找一个完美的 C# JSON 库。最完整的是 NewtonSoft JSON 库。然而,最终决定在内部开发一个库(或一组类)。想法是,如果填写好的表单字段与表单中定义的字段不一致,则创建表单数据实例应失败。使用 NewtonSoft,必须首先创建数据实例,然后检查它是否与 schema 中定义的对应。

上述以及这是一个了解 JSON 的机会的事实,是这项工作的动力。

在这项工作的第一部分中,介绍了有效创建 JSON schema 和实例所需的步骤。在第二部分中,讨论了更高级的 JSON 功能。

背景

根据上一节中阐述的目标,JSON 指定了定义表单的机制。这些机制统称为 JSON Schema 对象。一旦定义,schema 可用于指导 JSON 数据实例对象的创建。明确地说,JSON Schema 用于定义表单,而填写好的表单称为该表单的一个实例。

JSON schema 核心 规范 定义了 4 种原始数据类型(即 String、Integer、Number、Boolean 和 Null)和 2 种复合数据类型(即 Array 和 Object)。JSON Array 对象类型是零个或多个所有或任何 6 种 JSON 类型的有序列表。而 JSON Object 数据类型是零个或多个所有或任何 6 种类型的无序列表。

根据 JSON 实例 规范,将编程语言对象转换为有效 JSON schema 或实例字符串的机制称为生成器。解析器是将有效 JSON 字符串转换为编程语言对象的机制。对于这项工作,生成器将称为序列化器,解析器称为反序列化器。

 

目录

使用代码

在接下来的小节中,将尝试演示如何创建映射到所有 JSON 类型的 C# 对象。还介绍了如何将 C# 对象序列化为 JSON schema 和实例字符串,以及如何将 JSON 字符串反序列化回 C# 对象。本节将总结如何按名称查找 JSON 对象,以及字符在序列化和反序列化过程中如何转义和反转义

这些 JSON C# 类集中的许多机制将通过示例进行演示。所呈现的示例假设要创建一个并填写求职申请表。

顶级 JSON Schema 对象

理想情况下,JSON schema 的所有相关组件都应包含在顶级 schema 对象中。顶级对象描述表单,为其提供标题、标识,但最重要的是告知表单符合哪个版本的 JSON schema 标准。请注意,这项工作基于 JSON schema 规范的第 4 版。

//Example 1_1

JsonSchemaEngine _json_schema_engine   =  new JsonSchemaEngine(); 


JsonSchemaObject _json_schema_person_details = new JsonSchemaObject (JSON_VERSION.V4, 
"PersonInfo","Prospective Employee Detail Form", "FormID-001");

_schema_string = _json_schema_engine.Serialize (_json_schema_person_details);

上面显示了创建顶级 JSON schema 对象的代码。可以看出,schema 对象构造函数 JsonSchemaObject (JSON_VERSION version,string title,string description,string object_id,bool additional_properties = true) 传递了表单的版本、标题、描述和标识。目前,请忽略 additional_properties 参数,因为本工作的第二部分会对其进行处理。


JsonSchemaEngine 对象被实例化并用于序列化顶级对象。_schema_string 的内容如下所示。

//output of Example_1_1

/*
{
  "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#", 
  "type": "object",
  "id": "FormID-001",
  "title": "PersonInfo",
  "description": "Prospective Employee Detail Form"
}

*/

上面 JSON schema 中的 $schema 属性表示该表单符合 schema 规范的第 4 版草案。type 属性表示顶级对象是 JSON Object 类型,因此可以包含其他 JSON 类型。其余属性不言自明。

顶级 C# schema 对象的 versiontypeidtitledescription 可以分别从以下 JsonSchemaObjectVersionObjectTypeObjectIDTitleDescription 属性中读取。

上述代码可以在附加解决方案的 Example_1_1 函数中找到。

JSON Schema 字符串类型

假设表单的前两个字段是申请人的名字和姓氏。这些字段都是 JSON 字符串类型,每个字段的长度必须在 2 到 100 个字符之间。这两个字段都是必填的。创建这些字段的代码如下所示:

// Example_1_2

...

JsonSchemaObject _json_schema_first_name = new JsonSchemaObject ("firstName", 2, 100, 
string.Empty, "First Name of Applicant", true);

JsonSchemaObject _json_schema_last_name = new JsonSchemaObject ("lastName", 2, 100,string.Empty, "Last Name of Applicant", true);

_json_schema_person_details.AddObject (_json_schema_first_name);
_json_schema_person_details.AddObject (_json_schema_last_name);

_schema_string = _json_schema_engine.Serialize (_json_schema_person_details);

可以使用以下 JsonSchemaObject 构造函数创建 schema 的 JSON 字符串类型:JsonSchemaObject (string object_name,int? minimum_length, int? maximum_length,string pattern,string description,bool is_required = false)

当这些字段的 schema 对象创建后,它们会使用 JsonSchemaObject AddObject (JsonSchemaObject json_schema_object) 实例例程添加到顶级对象,即 _json_schema_person_details,如上所示。

顶级对象的序列化字符串如下所示:

//Example_1_2

/*
{
    "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#", 
    "type": "object",
    "id": "FormID-001",
    "title": "PersonInfo",
    "description": "Prospective Employee Detail Form",
    "properties":  {
                    
                    "firstName": {
                    "description": "First Name of Applicant",
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 100
                    },

                    "lasttName": {
                    "description": "Last Name of Applicant",
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 100
                   }
    },

  "required": ["firstName", "lasttName"]
}
*/

当其他 JSON 类型被添加到 JSON Object 类型时,这些添加的类型称为对象的属性。这就是为什么名字和姓氏字段包含在标记为属性的花括号内的原因。请注意,在上面的字符串末尾,firstNamelastName 对象被标记为 required。这是因为这两个对象的 is_required 参数都设置为 true。这些字段不需要符合任何字符串模式,因此字符串模式属性设置为 string.Empty。本作品后面将给出一个示例,展示如何设置模式属性。

以下 JsonSchemaObject 属性仅与 JSON 字符串类型的 C# 对象相关联:MaximumLengthMinimumLengthPatternJsonSchemaObject 对象的名称可以从 ObjectName 属性中读取。

以下代码片段展示了如何创建表单的当前实例。

//Example_1_2

JsonInstanceObject _json_instance_first_name = new JsonInstanceObject (_json_schema_first_name,"Donkey");

JsonInstanceObject _json_instance_last_name  = new JsonInstanceObject (_json_schema_last_name,
"Hotey");

_instance_object_string_list = new List<JsonInstanceObject> ();
_instance_object_string_list.Add (_json_instance_first_name);
_instance_object_string_list.Add (_json_instance_last_name);


JsonInstanceObject _json_instance_person_details = new JsonInstanceObject (_json_schema_person_details,_instance_object_string_list);

_instance_string  = _json_instance_engine.Serialize (_json_instance_person_details);

创建 JsonSchemaObject 实例涉及调用 JsonInstanceObject (JsonSchemaObject json_schema_object, string json_instance_value) 构造函数,并像上面所示一样,将定义的 schema 和实例值都传递给它。

如果作为名字或姓氏传递的字符串值违反了最小或最大字符长度,则会立即抛出异常,并且不会创建实例。

这些名字和姓氏实例对象一经创建,就会作为列表传递给 _json_schema_person_details schema 对象的实例对象,使用以下构造函数 JsonInstanceObject (JsonSchemaObject json_schema_object, List<JsonInstanceObject> json_instance_object_list)

请注意,_json_schema_person_details schema 对象也传递给了_json_instance_person_details 以及实例对象列表。这确保了生成的表单实例符合表单 schema 中设置的参数。例如,如果实例列表中不包含 firstNamelastName 对象,则会抛出异常。回想一下,这两个属性都是必需的。除其他检查外,还会进行一项检查,以确保 firstNamelastName 对象都是 schema 中定义的 JSON 字符串类型。JSON 实例对象的序列化过程与 JSON schema 的序列化过程类似。序列化后的实例字符串输出如下所示:

//Example_1_2

/*
{
  "firstName": "Donkey", 
  "lastName": "Hotey"
}
*/

如果 JSON 实例是字符串类型,则通过读取 JsonInstanceObject 类的 ObjectStringValue 属性获取实例值。JSON 实例 C# 对象的名称存储在 JsonInstanceObject 类的 ObjectName 属性中。

完整代码请参见 Example_1_2 例程。

JSON Schema Enum 约束和默认值

JSON 定义了一个数组 enum 关键字,有助于限制 JSON 实例对象可以取值的范围。例如,表单可以将申请人的性别限制在五种选择之一。实现此约束的步骤如下所示。

// Example_1_3
...

JsonSchemaObject _json_schema_gender = new JsonSchemaObject ("gender", null, null, string.Empty, "Gender of Applicant", true);

 List<string> _gender_options = new List<string> ();
_gender_options.Add("male");
_gender_options.Add("female");
_gender_options.Add("transgender");
_gender_options.Add("intersex");
_gender_options.Add("other");
_json_schema_gender.AddEnumList (_gender_options,1);

_json_schema_person_details.AddObject (_json_schema_gender);

_schema_string = _json_schema_engine.Serialize (_json_schema_person_details);

可以看出,创建了一个 JSON 字符串类型的性别对象,并使用 JsonSchemaObject AddEnumList (object object_enum,int default_index = -1) 例程将性别属性的可能值列表附加到该对象上。

序列化后的 _json_schema_person_detail 的输出如下所示。

//Example_1_3

/*
{
...
"properties":  {
 
...
   "gender": {
           "description": "Gender of Applicant",
            "type": "string",

           "enum": ["male", "female", "transgender", "intersex", "other"],
           "default": "female"
          }
  },
  "required": ["firstName", "lastName", "gender"]
}
*/

请注意,性别对象的 default 值设置为 female。这是因为整数值 1 被作为第二个参数传递给 AddEnumList 例程。1 是 _gender_options 列表中字符串 "female" 的索引。如果不需要 default 值,则该参数应省略或设置为 -1。也可以使用 SetDefaultValue (object default_value) 例程独立于 AddEnumList 例程设置默认值。有关如何使用此例程为所有 6 种 JSON 类型设置默认值的用例,请参见 Example_1_14

请注意,传递给 AddEnumList 例程列表中的所有对象都必须是唯一的,否则将抛出异常。

//Example_1_3
...

JsonInstanceObject _json_instance_gender = new JsonInstanceObject (_json_schema_gender,"other");

...

_instance_object_string_list.Add (_json_instance_gender);

_json_instance_person_details = new JsonInstanceObject (_json_schema_person_details,_instance_object_string_list);

 
_instance_string  = _json_instance_engine.Serialize (_json_instance_person_details);

上面的代码展示了如何创建 _json_schema_gender 对象的实例。创建后,此性别实例被添加到 _json_instance_person_details 对象中,然后序列化以产生下面的字符串输出。

Example_1_3

/*
{
  "firstName": "Donkey", 
  "lasttName": "Hotey", 
  "gender": "other"
}
*/

如果 _json_instance_gender 传递的字符串值不是 enum 数组中的值,则会抛出异常。另一方面,如果传入空字符串或 null 字符串作为其值,则其值将变为默认值,即 "female"。上述代码包含在 Example_1_3 例程中。

所有 6 种 JSON 类型都可以分配 enum 数组和 default 值。对于 JSON Number、Integer 和 Boolean 类型,分别将 C# double?int?bool? 列表传递给 AddEnumList 例程。
另一方面,对于 JSON Object 和 Array 类型,传递一个 JsonInstanceObject 列表。演示如何完成上述操作的代码在附加解决方案文件中的 Example_1_8Example_1_9 中给出。

Enum 列表包含在 JsonSchemaObject 类的 EnumInstanceObject 属性的对象列表中。default 值可以从同一类的 DefaultInstanceObject 属性中读取。

JSON Schema Integer 和 Number 类型

在这项工作中,JSON Integer 类型映射到 C# int?,Number 类型映射到 double?。除此之外,JSON Integer 和 Number 类型具有相同的对象属性集,并且以类似的方式进行操作。考虑到这一点,假设表单中需要一个 JSON Integer 类型的年龄字段。还假设此字段的值必须在 18 到 55 之间。构造函数 JsonSchemaObject (string object_name,JSON_TYPE json_type, double? minimum_value,double? maximum_value, double? multiple_of_value, string description,bool is_required = false) 用于创建此字段,如下所示:

//Example_1_4

JsonSchemaObject _json_schema_age = new JsonSchemaObject ("age", JSON_TYPE.INTEGER, 18,55, null, "The Age of the Applicant ", true);

...

_json_schema_person_details.AddObject (_json_schema_age);

_schema_string = _json_schema_engine.Serialize (_json_schema_person_details);

此构造函数只接受 JSON_TYPE.NUMBERJSON_TYPE.INTEGER 作为其第二个参数,否则将抛出异常。multiple_of_value 参数设置为 null,因为它不是必需的。但如果表单希望将 _json_schema_age 对象的实例值限制为 5 的倍数,则该参数应设置为 5。在这种情况下,分配的值不是此参数值的倍数,则会抛出异常。
现在,顶级对象的序列化字符串应该有一个名为 age 的属性,如下所示

//Example_1_4

/*
{
...
"properties":  {
...
        "age": {
              "description": "The Age of the Applicant ",
              "type": "integer",
              "minimum": 18,
              "maximum": 55
               }
        },
"required": ["firstName", "lastName", "gender", "age"]
}
*/

JSON Integer 或 Number 类型特有的 JsonSchemaObject 属性如下:MaximumValueMinimumValueMultipleOfValue。还有两个与 JSON Integer 或 Number 类型相关的属性,即 ExclusiveMinimumExclusiveMaximum。将 ExclusiveMinimum 属性设置为 true 意味着传递给 _json_schema_age 对象实例的值必须排除 18,即有效值从 19 开始。类似地,如果 ExclusiveMaximum 属性设置为 true,则 _json_schema_age 实例的最高有效值为 54。ExclusiveMinimumExclusiveMaximum 属性的默认值为 false

紧随其后的代码片段展示了如何创建年龄 schema 对象的实例。

//Example_1_4
...

JsonInstanceObject _json_instance_age = new JsonInstanceObject (_json_schema_age,28);

...

_instance_object_string_list.Add (_json_instance_age);

_json_instance_person_details = new JsonInstanceObject (_json_schema_person_details,_instance_object_string_list);

_instance_string  = _json_instance_engine.Serialize (_json_instance_person_details);

如果传递给 JsonInstanceObject (JsonSchemaObject json_schema_object, int? json_instance_value) 构造函数的值小于 18 或大于 55,则会抛出异常。如果 _json_schema_age 对象是 Number 类型,则会调用 JsonInstanceObject (JsonSchemaObject json_schema_object,double? json_instance_value) 构造函数。

如果 JsonInstanceObject 类型是 Number,则其关联值可以从实例类 ObjectDoubleValue 属性中获取。如果是 Integer 类型,则其值可以从类的 ObjectIntegerValue 属性中读取。

序列化表单实例应产生以下输出:

 

//Example_1_4

/*
{
    "firstName": "Donkey", 
    "lastName": "Hotey", 
    "gender": "other", 
    "age": 28
}
*/

完整的代码清单请参见附加解决方案中的 Example_1_4 例程。

JSON Schema Boolean 类型

为了描述 JSON 布尔类型如何在本工作中实现,假设表单中有一个强制字段,申请人必须说明是否需要进一步培训。此字段的有效值应为 true 或 false。以下代码展示了如何实现上述目标。

//Example_1_5
...

JsonSchemaObject _json_schema_requires_training = 
	new JsonSchemaObject ("training?", JSON_TYPE.BOOLEAN, "Does the applicant require training?", true);

List<bool?> _training_options = new List<bool?> ();

_training_options.Add(true);
_training_options.Add(false);

_json_schema_requires_training.AddEnumList (_training_options);


....

_json_schema_person_details.AddObject (_json_scon_schema_requires_training) 

_schema_string = _json_schema_engine.Serialize (_json_schema_person_details);

在本工作中,JSON 布尔类型映射到 C# bool?

序列化表单现在应该有一个名为 "training?" 的必填属性,如下所示。

// Example_1_5

/*
{
    ...
   "properties":  {

    ...

        "training?": {
             "description": "Does the applicant require training?",
            "type": "boolean",
            "enum": [true, false]
               },   

  "required": ["firstName", "lastName", "gender", "age", "training?"]
}


*/

请注意,此属性未设置 default 值。你能猜到原因吗?

// Example_1_5
  
JsonInstanceObject _json_instance_requires_training = 
new JsonInstanceObject (_json_schema_requires_training,false);

...

_innstance_object_list.Add (_json_instance_requires_training);

JsonInstanceObject _json_instance_person_details = new JsonInstanceObject (_json_schema_person_details,_instance_object_list);
			
_instance_string  = _json_instance_engine.Serialize (_json_instance_person_details);

使用以下构造函数 JsonInstanceObject (JsonSchemaObject json_schema_object, bool? json_instance_value) 创建 _json_schema_requires_training 对象的实例(见上面的代码片段)。与 JSON 布尔类型实例相关联的值可以从 JsonInstanceObjectObjectBooleanValue 属性中检索。

现在,表单的序列化实例应包含 training 属性,如下所示。

//Example_1_5

/*

{
   "firstName": "Donkey", 
   "lastName": "Hotey", 
   "gender": "other", 
   "age": 28, 
   "training?": false
}

*/

完整的代码请参见 Example_1_5 例程。

JSON Schema Object 类型

考虑表单中申请人的地址字段,该字段由四个子字段组成,即门牌号、街道、城市和省份。此字段可以充分表示为具有四个属性的 JSON schema 对象类型,即 1 个 JSON Integer 类型和 3 个 JSON String 类型。创建地址对象的代码行如下所示:

//Example_1_6
...

JsonSchemaObject _json_schema_address = new JsonSchemaObject ("address", JSON_TYPE.OBJECT,"The address of the applicant", true);

JsonSchemaObject _json_schema_house_number = new JsonSchemaObject ("houseNumber", 
JSON_TYPE.INTEGER, string.Empty, true);

JsonSchemaObject _json_schema_street = new JsonSchemaObject ("street", JSON_TYPE.STRING, 
string.Empty, true);

JsonSchemaObject _json_schema_city   = new JsonSchemaObject ("city", JSON_TYPE.STRING,
 string.Empty, true);

JsonSchemaObject _json_schema_state = new JsonSchemaObject ("state", JSON_TYPE.STRING, string.Empty, true);


_json_schema_address.AddObject (_json_schema_house_number);
_json_schema_address.AddObject (_json_schema_street);
_json_schema_address.AddObject (_json_schema_city);
_json_schema_address.AddObject (_json_schema_state);

...

_json_schema_person_details.AddObject (_json_schema_address);
			
_schema_string = _json_schema_engine.Serialize (_json_schema_person_details);

请注意,address 对象的四个属性使用简写构造函数进行实例化,即 JsonSchemaObject (string object_name,JSON_TYPE json_type,string description,bool is_required = false)。此构造函数允许创建具有所有其他相关 schema 参数设置为默认值的 JSON schema 对象。地址对象本身也使用此简写构造函数。创建 JSON Object 类型的完整构造函数以及相关的 JsonSchemaObject 属性将在第 2 部分中讨论。

顶级对象的序列化输出应具有一个 address 属性,如下所示:

//Example_1_6

/*
{
    ...
   "properties":  {

    ...

        "address": {
                   "description": "The address of the applicant",
                   "type": "object",
                   "properties":  {
                                         "houseNumber": {
                                         "type": "integer"
                                          },

                                         "street": {
                                         "type": "string"
                                          },

                                          "city": {
                                          "type": "string"
                                          },

                                         "state": {
                                         "type": "string"
                                          }
                                        },

        "required": ["houseNumber", "street", "city", "state"]
             }
          },

   "required": ["firstName", "lastName", "gender", "age", "training?", "address"]
}


*/

读者会注意到,这是一个 JSON 对象类型(即 address 对象)作为另一个 JSON 对象类型(即顶级对象)的属性的示例。

使用 JsonInstanceObject (JsonSchemaObject json_schema_object, List<JsonInstanceObject> json_instance_object_list) 构造函数,_json_schema_address 对象的实例创建如下:

//Example_1_6
...

JsonInstanceObject _json_instance_house_number = 
new JsonInstanceObject (_json_schema_house_number,345);

JsonInstanceObject _json_instance_street = 
new JsonInstanceObject (_json_schema_street ,"North-West");

JsonInstanceObject _json_instance_city = new JsonInstanceObject (_json_schema_city ,"New York");
JsonInstanceObject _json_instance_state = new JsonInstanceObject (_json_schema_state ,
"New York");


_instance_object_list = new List<jsoninstanceobject> ();

_instance_object_list.Add (_json_instance_house_number);
_instance_object_list.Add (_json_instance_street);
_instance_object_list.Add (_json_instance_city);
_instance_object_list.Add (_json_instance_state);


JsonInstanceObject _json_instance_address = 
new JsonInstanceObject (_json_schema_address ,_instance_object_list);


_instance_object_list.Clear ();

...

_instance_object_list.Add (_json_instance_address);

JsonInstanceObject _json_instance_person_details = new 
JsonInstanceObject (_json_schema_person_details,_instance_object_list);
			
_instance_string  = _json_instance_engine.Serialize (_json_instance_person_details);


组成 JSON Object 类型实例的对象包含在 JsonInstanceObject 类的 ObjectList 属性中。

表单实例的序列化输出现在应如下所示:

//Example_1_6

/*

{
    "firstName": "Donkey", 
    "lastName": "Hotey", 
    "gender": "other", 
    "age": 28, 
    "training?": false, 
    "address":  {
               "houseNumber": 345, 
               "street": "North-West", 
               "city": "New York", 
               "state": "New York"
    }
}
  

*/

JSON Schema 数组类型

假设表单要求申请人填写联系电话号码。每个号码都必须有一个相关的电话号码类型指定,例如家庭、工作等。此外,申请人的电话号码数字必须以 0 开头,并且必须是 11 位数字。申请人还可以至少填写一个号码,最多三个。

根据上述要求,联系电话号码是一个 2 元组对象,即电话号码类型和电话号码数字。这可以作为具有两个 JSON 字符串类型属性的 JSON Object 类型来容纳。
允许申请人输入 1 到 3 个电话号码对象可以使用 JSON 数组类型实现。
下面的代码展示了如何实现这一点。

 //Example_1_7
...
   
JsonSchemaObject _json_schema_number_type = new JsonSchemaObject ("numberType", 
JSON_TYPE.STRING, string.Empty, true);

JsonSchemaObject _json_schema_number     = new JsonSchemaObject ("number", null,null,"0\\d{10}", string.Empty, true);

JsonSchemaObject _json_schema_number_object = new JsonSchemaObject (string.Empty, 
JSON_TYPE.OBJECT,string.Empty, true);

_json_schema_number_object.AddObject (_json_schema_number_type);
_json_schema_number_object.AddObject (_json_schema_number);


JsonSchemaObject _json_schema_number_array = new JsonSchemaObject ("phoneNumber",1,3,true,false,"Phone Numbers of Applicant",true);

_json_schema_number_array.AddObject (_json_schema_number_object);

...

_json_schema_person_details.AddObject (_json_schema_number_array);	
		
			
_schema_string = _json_schema_engine.Serialize (_json_schema_person_details);


请注意,_json_schema_number 对象的 pattern 参数设置为正则表达式字符串 "0\\d{10}"。这与电话号码数字的要求一致。
JSON Array 类型对象使用以下构造函数创建:JsonSchemaObject (string object_name,int? minimum_items,int? maximum_items,bool is_unique_items,bool additional_items,string description,bool is_required = false)

根据要求,构造函数的 minimum_itemsmaximum_items 参数分别设置为 1 和 3。如果申请人在表单实例化期间输入少于 1 个或多于 3 个号码,则会立即抛出异常。is_unique_items 参数设置为 true,以确保所有输入的号码对象都是唯一的。如果两个号码实例具有相同的电话号码类型和电话号码数字,则会抛出异常。additional_items 参数将在第 2 部分中介绍。与 JSON 数组类型的 JsonSchemaObject 相关的属性也将在第 2 部分中讨论。

phoneNumber 对象的序列化输出如下所示:

//Example_1_7

/*
{
    ...
   "properties":  {

    ...

       "phoneNumber": {
                      "description": "Phone Numbers of Applicant",
                      "type": "array",
                      "items": 
                              {
                                "type": "object",
                                 "properties":  {
                                              "numberType": {
                                              "type": "string"
                                               },

                                               "number": {
                                               "type": "string",
                                               "pattern": "^0\d{10}$"
                                               }
                                            },
                                 "required": ["numberType", "number"]
                              },
                      "minItems": 1,
                      "maxItems": 3,
                      "uniqueItems": true,
                      "additionalItems": false
                     }
                  },
"required": ["firstName", "lastName", "gender", "age", "training?", "address", "phoneNumber"]
}


*/

上面显示的输出是 JSON Object 类型(即 _json_schema_number_object)包含在 JSON Array 类型(即 _json_schema_number_array)中,并且 JSON Array 类型(即 _json_schema_number_array)包含在 JSON Object 类型(即 _json_schema_person_details)中的一个示例。这演示了三层 JSON 对象的嵌套。

_json_schema_number_array 的一个实例是使用 JsonInstanceObject (JsonSchemaObject json_schema_object, List<JsonInstanceObject> json_instance_object_list) 构造函数创建的,如下所示。

//Example_1_7
...

//create first phone number instance object

JsonInstanceObject _json_instance_type = 
new JsonInstanceObject(_json_schema_number_type,"Home");


JsonInstanceObject _json_instance_number = new JsonInstanceObject(_json_schema_number,
"07843487433");

_instance_object_list = new List<jsoninstanceobject> ();
_instance_object_list.Add (_json_instance_type);
_instance_object_list.Add (_json_instance_number );


JsonInstanceObject _json_instance_number_object_1 = 
new JsonInstanceObject(_json_schema_number_object,_instance_object_string_list);


//create second phone number instance object

_instance_object_list.Clear ();

_json_instance_type = new JsonInstanceObject(_json_schema_number_type,"Work");
_json_instance_number = new JsonInstanceObject(_json_schema_number,"06890487422");

_instance_object_list = new List<jsoninstanceobject> ();
_instance_object_list.Add (_json_instance_type);
_instance_object_list.Add (_json_instance_number );

			

JsonInstanceObject _json_instance_number_object_2 = new JsonInstanceObject(_json_schema_number_object,_instance_object_list);



//create phone number instance Array


_instance_object_string_list.Clear ();
_instance_object_string_list.Add (_json_instance_number_object_1);
_instance_object_string_list.Add (_json_instance_number_object_2);


JsonInstanceObject _json_instance_number_array = 
new JsonInstanceObject(_json_schema_number_array,_instance_object_list);

_instance_object_list.Clear ();

...

_instance_object_string_list.Add (_json_instance_number_array);

_json_instance_person_details = new JsonInstanceObject (_json_schema_person_details,_instance_object_string_list);

_instance_string  = _json_instance_engine.Serialize (_json_instance_person_details);

构成 JSON 数组类型实例的对象可以在 JsonInstanceObject 类的 ObjectList 属性中找到。

表单实例的序列化输出如下所示:

//Example_1_7

/*
{
    "firstName": "Donkey", 
    "lastName": "Hotey", 
    "gender": "other", 
    "age": 28, 
    "training?": false, 
    "address":  {
               "houseNumber": 345, 
               "street": "North-West", 
               "city": "New York", 
               "state": "New York"
               },

   "phoneNumber": [
                   {
                    "numberType": "Home", 
                    "number": "07843487433"
                   },
 
                   {
                    "numberType": "Work", 
                    "number": "06890487422"
                   }
              ]
}
*/

上述所有相关代码都可以在 Example_1_7 例程中找到。

JSON Schema Null 类型

为了说明 JSON Null 类型如何在本工作中实现,允许在表单中包含一个名为 spouse 的字段。还考虑到该字段在当前版本的表单中不使用,但将来可能需要。确保该字段存在于表单中的众多方法之一是将其指定为 JSON Null 类型。

//Example_1_10
...
    
JsonSchemaObject _json_schema_spouse = new JsonSchemaObject ("spouse", JSON_TYPE.NULL, 
"To be used in the future", true);

_json_schema_person_details.AddObject (_json_schema_spouse);

_schema_string = _json_schema_engine.Serialize (_json_schema_person_details);  
    

序列化上述代码将把 spouse 属性作为顶级 JSON 对象的一个属性,如下所示:

//Example_1_10

/*       
 {

     ...

     "properties":  {

              ...

              "spouse": {
                    "description": "To be used in the future",
                    "type": "null"
                 }

     },

    "required": ["firstName", "lastName", "gender", "age", "training?", "address",
    "phoneNumber", "spouse"]
}
    
 */ 

使用 JsonInstanceObject (JsonSchemaObject json_schema_object) 构造函数创建 _json_schema_spouse 对象的实例,如下所示:

//Example_1_10
...  

JsonInstanceObject _json_instance_spouse = new JsonInstanceObject(_json_schema_spouse);

_instance_object_list.Add (_json_instance_spouse);

_instance_string  = _json_instance_engine.Serialize (_json_instance_person_details);   
    

序列化后,表单实例的最终版本将如下所示:

 // Example_1_10       
 /*

{
    "firstName": "Donkey", 
    "lastName": "Hotey", 
    "gender": "other", 
    "age": 28, 
    "training?": false, 
    "address":  {
               "houseNumber": 345, 
               "street": "North-West", 
               "city": "New York", 
               "state": "New York"
               },

   "phoneNumber": [
                   {
                    "numberType": "Home", 
                    "number": "07843487433"
                   },
 
                   {
                    "numberType": "Work", 
                    "number": "06890487422"
                   }
              ],
              
    "spouse": null

}
*/  
    

完整的代码请参见 Example_1_10 例程。

反序列化 JSON Schema 和实例

转换或反序列化有效的 JSON schema 字符串类似于序列化过程。
在实例化 JsonSchemaEngine 后,一个有效的 JSON schema 字符串被传递给 Deserialize (string json_schema) 例程,该例程返回 JsonSchemaObject C# 顶级对象。

请注意,通过调用 JsonSchemaEngine(int schema_size_byte_limit = -1) 构造函数,可以限制可反序列化的 JSON schema 字符串的大小(以字节为单位)。如果传递给 Deserialize 例程的 json_schema 参数的大小大于 JsonSchemaEngine 实例化时为 schema_size_byte_limit 指定的值,则会抛出异常。

//Example_1_11 
....

//Deserializing a JSON Schema

JsonSchemaEngine _json_schema_engine   =  new JsonSchemaEngine(); 

/*JsonSchemaEngine _json_schema_engine   =  new JsonSchemaEngine(500);*/


JsonSchemaObject _json_schema_person_details_2  =  
_json_schema_engine.Deserialize (_schema_string);




//Deserializing a JSON schema instance

JsonInstanceEngine 	_json_instance_engine = new JsonInstanceEngine();

/*JsonInstanceEngine 	_json_instance_engine = new JsonInstanceEngine(500);*/

JsonInstanceObject  _json_instance_person_details_2 = 
_json_instance_engine.Deserialize (_json_schema_person_details, _instance_string);   
    

反序列化 JSON schema 的实例需要该实例创建时使用的 schema 存在,并将其传递给 JsonInstanceEngine 类的 JsonInstanceObject Deserialize (JsonSchemaObject json_schema_object,string json_instance) 例程,如上所示。

如上所示,还可以通过将 JsonInstanceEngine (int instance_size_byte_limit = -1) 构造函数中的 instance_size_byte_limit 参数设置为指定的最大大小,来限制可反序列化的 JSON 实例字符串的大小。

请参阅 Example_1_11 例程。

按名称查找 JSON Schema 和实例对象

可以通过调用 JsonSchemaObject 静态例程 FindSchemaObjectByName (string json_schema_name, JsonSchemaObject json_schema_object) 并传入要读取的对象的名称以及容器对象来检索和读取 JSON C# schema 对象的组件对象。在下面的示例中,尝试使用此例程从 _json_schema_person_details 对象中检索 gender schema 对象。如果返回了 gender 对象,则可以读取其相关属性,如下所示。

//Example_1_12

JsonSchemaObject _json_schema_object = 
JsonSchemaObject.FindSchemaObjectByName ("gender",_json_schema_person_details);

if (_json_schema_object != null)
{
			
	Console.WriteLine ("Object Name: {0}", _json_schema_object.ObjectName);

	Console.WriteLine ("JSON Type: {0}",  _json_schema_object.ObjectType);

	Console.WriteLine ("Minimum Length: {0}",_json_schema_object.MinimumLength);

	Console.WriteLine ("Maximum Length: {0}",_json_schema_object.MaximumLength);

	Console.WriteLine ("Required?: {0}", _json_schema_object.IsRequired);

	Console.WriteLine ("Default Value: {0}", 
    _json_schema_object.DefaultInstanceObject.ObjectStringValue);

	Console.WriteLine ("---------------------enum items---------------------------");
				foreach (JsonInstanceObject enum_item in 
                            _json_schema_object.EnumInstanceObject.ObjectList)

					Console.WriteLine ("\t\t {0}",enum_item.ObjectStringValue);
				
}

控制台输出的表示形式如下所示:

//Example_1_12 
   
/*

Object Name: gender
JSON Type: STRING
Minimum Length: 
Maximum Length: 
Required?: True
Default Value: female
---------------------enum items---------------------------
		 male
		 female
		 transgender
		 intersex
		 other


*/

 

JsonSchemaObject 类的 FindSchemaObjectByName 例程有一个用于 JsonInstanceObject 类的类似例程,即 FindInstanceObjectByName (string object_name, JsonInstanceObject json_instance_object)。下面展示的 Example_1_12 例程的摘录演示了其用法。

  // Example_1_12

JsonInstanceObject _json_instance_object = 
JsonInstanceObject.FindInstanceObjectByName ("gender",_json_instance_person_details);

  if (_json_instance_object != null) 
  {
				
	Console.WriteLine ("Object Name: {0}", _json_instance_object.ObjectName);
	Console.WriteLine ("JSON Type: {0}",   _json_instance_object.ObjectType);
	Console.WriteLine ("Object Value: {0}",   _json_instance_object.ObjectStringValue);
			
}

    
//Example_1_12
 /*
  
 Object Name: gender
 JSON Type: STRING
 Object Value: other
 
 */

 

JSON 引擎字符转义

在序列化过程中,JsonSchemaEngine 将尝试转义文本主体中出现的某些特殊 JSON 字符,例如双引号 ' " '。请参阅下面的场景,了解何时会发生这种情况。这些转义的字符串在 schema 反序列化过程中会被反转义

//Example_1_13

JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, 
"xterEscapeExamples", "Character escape Demo", "ExampleID-0113");

JsonSchemaObject _json_schema_string  = new JsonSchemaObject ("Quote\"name\"",JSON_TYPE.STRING,
"Testing Xter Escape");

_json_schema_object.AddObject (_json_schema_string);
_schema_string = _json_schema_engine.Serialize (_json_schema_object);   
    
//Example_1_13
/*       
{
  "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

  "id": "ExampleID-0113",

  "title": "xterEscapeExamples",

  "description": "Character escape Demo",

  "type": "object",

  "properties":  {

       "Quote \"name\"": {

           "description": "Testing Xter Escape",
           "type": "string"
       }
  }
}
*/  
    

JsonInstanceEngine 也是如此,如下所示:

 //Example_1_13
       
 JsonInstanceObject  _json_instance_string =  new JsonInstanceObject (_json_schema_string, "C is "quirky", "flawed", and an enormous success.---- Dennis M. Ritchie" );

JsonInstanceObject _json_instance_object = new JsonInstanceObject (_json_schema_object,
new List<JsonInstanceObject> (new JsonInstanceObject []    {_json_instance_string}));


_instance_string = _json_instance_engine.Serialize (_json_instance_object);    

Example_1_13
/*        
{
"Quote": "C is \"quirky\", \"flawed\", and an enormous success.---- Dennis M. Ritchie"
}
*/      

关注点

恐怕没什么有趣的事情要报告了 ;)

历史

2015年1月4日:第一版。

2015年4月2日:修改了 JSON 字符串类型 schema 构造函数。

2016年5月3日:修改了此 JSON 库的 DoEscape 函数,使其与 www.json.org 转义规范对齐。

2016年11月3日:修正了 JSON 反转义函数。将附加代码替换为 Net Core 版本。

 

© . All rights reserved.