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

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (23投票s)

2015年4月1日

CPOL

14分钟阅读

viewsIcon

45691

downloadIcon

701

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

引言

假定读者已经阅读并理解了本系列两部分文章的第一部分。如果已阅读,请继续阅读本文。

 

目录

使用代码

第一部分一样,使用代码片段描述 JSON 概念及其实现方式。这里使用的一些示例基于 Michael Droettboom 和 Space Telescope Science Institute 的其他人工作

JSON 引用 

//Example_2_1

 /*   
{
      "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

      "id": "ExampleID-021",

      "title": "refExamples",

      "description": "REF Demo Schema",

      "type": "object",

      "properties":  {

                       "integerOne": {
                       "type": "integer",
                       "minimum": 200,
                       "maximum": 500,
                       "exclusiveMinimum": true,
                       "exclusiveMaximum": true,
                       "multipleOf": 20
                        },

                        "integerTwo": {
                        "type": "integer",
                        "minimum": 200,
                        "maximum": 500,
                        "exclusiveMinimum": true,
                        "exclusiveMaximum": true,
                        "multipleOf": 20
                        },

                        "integerThree": {
                        "type": "integer",
                        "minimum": 200,
                        "maximum": 500,
                        "exclusiveMinimum": true,
                        "exclusiveMaximum": true,
                        "multipleOf": 20
                         }
            },
       "required": ["integerOne", "integerTwo", "integerThree"]
}
*/
    

考虑上面的 JSON schema 文本。请注意,顶层 schema 的三个属性,即 integerOneintegerTwointegerThree,都具有相同的参数。尽管如此,每个属性都必须单独创建,从而违反了DRY 原则。JSON schema 规范试图通过三种机制来缓解这种定义重复。这些机制允许在对象外部定义对象参数,然后在对象内部引用这些定义的参数。  在运行时,这些引用将被引用的参数替换。 

对于这项工作,三种引用技术分别称为内部定义外部

内部引用

//Example_2_2
        
/*
 {
     "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

     "id": "ExampleID-022",

     "title": "refExamples",

     "description": "REF Demo Schema",

     "type": "object",

     "properties":  {

                      "integerOne": {
                       "id": "integer_id_001",
                       "type": "integer",
                       "minimum": 200,
                       "maximum": 500,
                       "exclusiveMinimum": true,
                       "exclusiveMaximum": true,
                       "multipleOf": 20
                       },

                        "integerTwo": {
                        "$ref": "#integer_id_001"
                        },

                       "integerThree": {
                       "$ref": "#integer_id_001"
                        }
                     },
     "required": ["integerOne", "integerTwo", "integerThree"]

}
        
 */
      

上面是实现内部引用的 schema 示例。如您所见,参数在 integerOne 属性中定义一次,然后使用带有 IntegerOne 标识的 $ref 关键字的引用放置在另外两个属性中。  在功能上,上述 schema 文本与 Example_2_1 例程中的 schema 文本相似。要检查这一点,请反序列化上面的 JSON 文本,然后再次序列化它。打印序列化后的文本以确认这一点。

下面是用于生成上述 schema 文本的 C# 代码。

//Example_2_2
    
JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, 
"refExamples", "REF Demo Schema", "ExampleID-022");


JsonSchemaObject _json_schema_integerOne = new JsonSchemaObject ("integerOne", JSON_TYPE.INTEGER,200, 500, 20, string.Empty, true);

_json_schema_integerOne.ExclusiveMinimum = true;
_json_schema_integerOne.ExclusiveMaximum = true;
_json_schema_integerOne.ObjectID = "integer_id_001";


JsonSchemaObject _json_schema_integerTwo   = new JsonSchemaObject("integerTwo",
JSON_POINTER_TYPE.INTERNAL,_json_schema_integerOne.ObjectID,string.Empty,true);

JsonSchemaObject _json_schema_integerThree = new JsonSchemaObject("integerThree",
JSON_POINTER_TYPE.INTERNAL,_json_schema_integerOne.ObjectID,string.Empty,true);


_json_schema_object.AddObjects (new List<JsonSchemaObject> (new JsonSchemaObject [] {
				_json_schema_integerOne,
				_json_schema_integerTwo,
				_json_schema_integerThree})
				);



_schema_string = _json_schema_engine.Serialize (_json_schema_object);
    
    

请注意,integerTwo 和 IntegerThree 是使用引用构造函数实例化的,即 JsonSchemaObject (string object_name,JSON_POINTER_TYPE ref_type,string json_schema_reference_uri,string description,bool is_required = false)。  除了对象名称外,此构造函数还接收引用的类型,在本例中为 JSON_POINTER_TYPE.INTERNAL,以及被引用对象的标识,即 _json_schema_integerOne.ObjectID

如果在反序列化过程中引用的对象找不到,则会抛出异常。

引用类型及其关联的 URI 可以从 JsonSchemaObject SchemaReferenceType 和 SchemaReferenceUri 属性中读取。

定义引用

//Example_2_3

/* { 

    "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#", 

    "id": "ExampleID-023",
 
    "title": "refExamples", 

    "description": "REF Demo Schema", 

    "type": "object",
 
     "properties": { 
                   "integerOne":  { 
                                "$ref": "#/definitions/integerDef" 
                                },

                   "integerTwo": { 
                               "$ref": "#/definitions/integerDef" 
                               }, 

                  "integerThree": { 
                              "$ref": "#/definitions/integerDef" 
                              } 
                  }, 
    "required": ["integerOne", "integerTwo", "integerThree"], 

     definitions: { 

                "integerDef": { 
                              "type": "integer", 
                              "minimum": 200,
                              "maximum": 500, 
                              "exclusiveMinimum": true,
                              "exclusiveMaximum": true, 
                              "multipleOf": 20 
                            } 
                 } 

} 

*/ 

在本例中,定义的 schema 参数放置在称为 definitions 的特殊对象中。参数的引用放置在每个相关对象中,如上面 IntegerOneintegerTwointegerThree 属性的示例所示。

用于完成上述操作的代码如下所示。

//Example_2_3
  
JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, 
"refExamples","REF Demo Schema", "ExampleID-023");

JsonSchemaObject _json_schema_integerDef = new JsonSchemaObject ("integerDef",
 JSON_TYPE.INTEGER,200, 500, 20, string.Empty, true);

_json_schema_integerDef.ExclusiveMinimum = true;
_json_schema_integerDef.ExclusiveMaximum = true;


_json_schema_object.AddDefinition (_json_schema_integerDef);



JsonSchemaObject _json_schema_integerOne = new JsonSchemaObject ("integerOne",
JSON_POINTER_TYPE.DEFINITIONS,_json_schema_integerDef.ObjectName, string.Empty, true);


JsonSchemaObject _json_schema_integerTwo = new JsonSchemaObject ("integerTwo",
JSON_POINTER_TYPE.DEFINITIONS, _json_schema_integerDef.ObjectName, string.Empty, true);



JsonSchemaObject _json_schema_integerThree = new JsonSchemaObject ("integerThree",
JSON_POINTER_TYPE.DEFINITIONS, _json_schema_integerDef.ObjectName, string.Empty, true);


		
_json_schema_object.AddObjects (new List<jsonschemaobject> (new JsonSchemaObject [] {
				_json_schema_integerOne,
				_json_schema_integerTwo,
				_json_schema_integerThree})
				);
	
			
				
_schema_string = _json_schema_engine.Serialize (_json_schema_object);  
    

同样,使用的是 JsonSchemaObject (string object_name,JSON_POINTER_TYPE ref_type,string json_schema_reference_uri,string description,bool is_required = false) 构造函数,但这次它传递了 JSON_POINTER_TYPE.DEFINITIONS 作为参数。此外,不是像内部引用那样传递对象 ID,而是使用对象名称,即 integerDef

另一个定义 URI 的示例是 "$ref": "#/definitions/jsonObject/integerDef" 。此 URI 表示 integerDef 位于一个名为 jsonObject 的 JSON 对象类型内部,而 jsonObject 又位于 definitions 对象内部。

如果在作用域内或包含 $ref 属性的对象父作用域内的所有定义对象中都找不到引用的对象,则在反序列化过程中会抛出异常。

引用类型及其关联的 URI 可以从 JsonSchemaObject SchemaReferenceType 和 SchemaReferenceUri 属性中读取。

外部引用

在到目前为止讨论的内部定义引用机制中,被引用的 schema 位于被引用对象所在的同一对象内部。JSON 允许引用位于对象外部的 schema,因此称为外部引用

//Example_2_4

/*
{
        "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

        "id": "http://x.y.z/rootschema.json#",

        "title": "refExamples",

        "description": "External Schema",

        "type": "object",

         "properties":  {
                         "integerExternal": {
                         "id": "integer_id_024",
                         "type": "integer",
                         "minimum": 200,
                         "maximum": 500,
                         "exclusiveMinimum": true,
                         "exclusiveMaximum": true,
                         "multipleOf": 20
                        }
}

*/

典型的外部 schema 的结构类似于上面的 JSON 文本。请注意,顶层对象的标识是一个链接,即 "http://x.y.z/rootschema.json#"。  从外部引用 integerExternal 是使用此链接和 integerExternal 的标识完成的,如下所示。

//Example_2_4

/*
{
     "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

     "id": "ExampleID-024",

     "title": "refExamples",

     "description": "REF Demo Schema",

     "type": "object",

     "properties":  {

                     "integerOne": {
                         "$ref": "http://x.y.z/rootschema.json#integer_id_024"
                      },

                      "integerTwo": {
                          "$ref": "http://x.y.z/rootschema.json#integer_id_024"
                       },

                       "integerThree": {
                           "$ref": "http://x.y.z/rootschema.json#integer_id_024"
                        }


     },

     "required": ["integerOne", "integerTwo", "integerThree"]

}
*/

用于完成上述操作的代码包含在 Example_2_4 例程中。请参阅下面的摘录。

/Example_2_4
    
string _object_id = "integer_id_024";
string _ref_schema_id = "http://x.y.z/rootschema.json#";


JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, 
"refExamples","REF Demo Schema", "ExampleID-024");

JsonSchemaObject _json_schema_integerOne = new JsonSchemaObject ("integerOne",
JSON_POINTER_TYPE.EXTERNAL, _ref_schema_id + _object_id, string.Empty, true);

JsonSchemaObject _json_schema_integerTwo = new JsonSchemaObject ("integerTwo",
JSON_POINTER_TYPE.EXTERNAL, _ref_schema_id + _object_id, string.Empty, true);

JsonSchemaObject _json_schema_integerThree = new JsonSchemaObject ("integerThree",
JSON_POINTER_TYPE.EXTERNAL, _ref_schema_id + _object_id, string.Empty, true);


_json_schema_object.AddObjects (
new List<JsonSchemaObject> (new JsonSchemaObject [] {
_json_schema_integerOne,
_json_schema_integerTwo,
_json_schema_integerThree})
				);


_schema_string = _json_schema_engine.Serialize (_json_schema_object);



 
...
 
 _json_schema_engine.AddSchemaRef (_json_schema_external_object);

JsonSchemaObject _json_schema_object_deserialized = _json_schema_engine.Deserialize (
_schema_string);
  
...

如果被引用的对象位于外部 schema 中,则应用程序有责任在调用反序列化例程之前检索此外部 schema。否则,在反序列化过程中会抛出异常,因为找不到 schema。  在调用 Deserialize 例程之前,使用任何一个 AddSchemaRef 例程来添加外部 schema(或 schemata)。  请参阅 Example_2_4 例程了解如何实现这一点。 AddSchemaRef 例程来添加外部 schema(或 schemata),然后再调用 Deserialize 例程。请参阅 Example_2_4 例程了解如何实现。

引用类型及其关联的 URI 可以从 JsonSchemaObject SchemaReferenceType 和 SchemaReferenceUri 属性中读取。

JSON 数组类型属性

在本作品的第一部分中,引入了 JSON 数组类型的概念。本节回顾了之前讨论的一些数组参数,并介绍了新的参数。

 

唯一、最小和最大项

//Example_2_5

/*
{
      "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

      "id": "ExampleID-025",

      "title": "arrayExamples",

      "description": "Array Demo Schema",

      "type": "object",

      "properties":  {

                  "arrayObject": {
                                "type": "array",
                                 "items": 
                                       {
                                       "type": "integer"
                                       },
                                 "minItems": 1,
                                 "maxItems": 4,
                                 "uniqueItems": true
                 }
     },

    "required": ["arrayObject"]
}

*/

上面显示的 schema 文本现在应该读者很熟悉了。它是一个描述 JSON 数组类型的 schema,该数组类型由 JSON 整数类型的项组成。此数组 schema 的实例应包含不多于 4 个整数项,不少于 1 个。数组中的所有项都必须是唯一的。

如下面的代码摘录所示,使用构造函数 JsonSchemaObject (string object_name,int? minimum_items,int? maximum_items,bool is_unique_items,bool additional_items,string description,bool is_required = false) 创建了数组的 schema。

//Example_2_5

JsonSchemaObject _json_schema_integer = new JsonSchemaObject ("integerObject", 
JSON_TYPE.INTEGER,null, null, null, string.Empty, false);

JsonSchemaObject  _json_schema_array   = new JsonSchemaObject ("arrayObject",1,4,true,true,
string.Empty,true);

_json_schema_array.AddObject (_json_schema_integer);

JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, 
"arrayExamples","Array Demo Schema", "ExampleID-025");

_json_schema_object.AddObject (_json_schema_array);

_schema_string = _json_schema_engine.Serialize (_json_schema_object);

对于 Example_2_5,使用下面的代码创建了上述 schema 的实例。

//Example_2_4

_instance_object_string_list = new List<JsonInstanceObject> ();

int _array_size = 4;

for (int i=0; i < _array_size; i++) 
{
	_instance_object_list.Add(new JsonInstanceObject(_json_schema_integer,(i+1)));

}

/* Line 1:
 
_instance_object_list.Add(new JsonInstanceObject(_json_schema_integer,(1)));

//*/

JsonInstanceObject _json_instance_array = new JsonInstanceObject (_json_schema_array, 
_instance_object_list);

_instance_object_list.Clear ();

_instance_object_list.Add (_json_instance_array);

JsonInstanceObject _json_instance_object = new JsonInstanceObject (_json_schema_object, 
_instance_object_list);

_instance_string = _json_instance_engine.Serialize (_json_instance_object);

要违反数组设置的最大和最小项数,请将 _array_size 变量的值更改为小于 1 或大于 4 的值。异常是怎么说的?
要违反 JSON 数组的 uniqueItems 约束,请注释掉第 1 行并运行 Example_2_5。读取抛出的异常。

JSON 数组参数 uniqueItemsminItemsmaxItems 可以从 JsonSchemaObject 类的 UniqueItemsMinimumItemsMaximumItems 属性中读取。

下面是数组 schema 的序列化实例。

Example_2_5

/*
{
"arrayObject": [1, 2, 3, 4]
}
*/

 

数组元组

与直觉相反,JSON 允许数组类型由非相同 JSON 类型项组成。例如,一个数组可以在同一个有序列表中包含字符串、整数和数字。这种数组称为元组。下面是描述元组的 schema 示例。

//Example_2_6

/*
{
    "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

    "id": "ExampleID-026",

    "title": "arrayExamples",

    "description": "Array Tuple Demo Schema",

    "type": "object",

    "properties":  {
  
                    "arrayObject": {
                    "type": "array",
                    "items": [
                                 {
                                  "type": "integer"
                                 }, 
                                 
                                 {
                                 "type": "string"
                                 }, 

                                 {
                                  "type": "string",
                                   "enum": ["Street", "Avenue", "Boulevard"]

                                 },
 
                                 {
                                  "type": "string",
                                   "enum": ["NW", "NE", "SW", "SE"]

                                 }
                          ],
                      "uniqueItems": true
                   }

   },

   "required": ["arrayObject"]
}

 */

数组项由 1 个整数和 3 个字符串组成。此示例是一个描述地址的元组。

创建此元组所用的 C# 代码如下所示。

//Example_2_6

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


JsonSchemaObject _json_schema_street_name        = new JsonSchemaObject ("streetName", JSON_TYPE.STRING, string.Empty, true);
			
			
JsonSchemaObject _json_schema_street_type   = new JsonSchemaObject ("streetType", 
JSON_TYPE.STRING, string.Empty, true);

_json_schema_street_type .AddEnumList (new List<string>(new string[] {"Street","Avenue","Boulevard"}));


JsonSchemaObject _json_schema_direction   = new JsonSchemaObject ("direction", JSON_TYPE.STRING, string.Empty, true);

_json_schema_direction .AddEnumList (new List<string>(new string[] {"NW","NE","SW","SE"}));


JsonSchemaObject  _json_schema_array   = ew JsonSchemaObject ("arrayObject",null,null,true,true,string.Empty,true);

_json_schema_array.AddObject (_json_schema_house_number);
_json_schema_array.AddObject (_json_schema_street_name);
_json_schema_array.AddObject (_json_schema_street_type);
_json_schema_array.AddObject (_json_schema_direction);


JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, "arrayExamples","Array Tuple Demo Schema", "ExampleID-026");

_json_schema_object.AddObject (_json_schema_array);
_schema_string = _json_schema_engine.Serialize (_json_schema_object);

使用下面的代码创建描述元组的 schema 的实例。

//Example_2_6

_instance_object_list = new List<JsonInstanceObject> ();


_instance_object_list.Add (new JsonInstanceObject (_json_schema_house_number, 1600));

_instance_object_list.Add (new JsonInstanceObject (_json_schema_street_name, "Pennsylvania"));

_instance_object_list.Add (new JsonInstanceObject (_json_schema_street_type, "Avenue"));

_instance_object_list.Add (new JsonInstanceObject (_json_schema_direction, "NW"));


JsonInstanceObject _json_instance_array = new JsonInstanceObject (_json_schema_array, 
_instance_object_list);

_instance_object_list.Clear ();

_instance_object_list.Add (_json_instance_array);


JsonInstanceObject _json_instance_object = new JsonInstanceObject (_json_schema_object,
_instance_object_list);

_instance_string = _json_instance_engine.Serialize (_json_instance_object);

元组 schema 的序列化输出如下所示;

//Example_2_6
/*

{
"arrayObject": [1600, "Pennsylvania", "Avenue", "NW"]
}

*/
 

附加项

请记住,用于创建元组数组的构造函数是 JsonSchemaObject (string object_name,int? minimum_items,int? maximum_items,bool is_unique_items,bool additional_items,string description,bool is_required = false)。要理解 additional_items 参数在构造函数中所起的作用,请考虑地址元组未提供 State 字段的配置。但是,将 additional_items 参数设置为 true 允许在实例化 schema 时向元组添加额外的字段,而无需显式定义这些额外字段。在 Example_2_7 中,State 字段已添加,如下所示。

//Example_2_7
...

_instance_object_list.Add (new JsonInstanceObject (_json_schema_house_number, 1600));

_instance_object_list.Add (new JsonInstanceObject (_json_schema_street_name, "Pennsylvania"));

_instance_object_list.Add (new JsonInstanceObject (_json_schema_street_type, "Avenue"));

_instance_object_list.Add (new JsonInstanceObject (_json_schema_direction, "NW"));

_instance_object_list.Add (new JsonInstanceObject (_json_schema_state, "Washington"));


...
 

序列化输出表示如下。 

//Example_2_7

/*
{
"arrayObject": [1600, "Pennsylvania", "Avenue", "NW", "Washington"]
}
*/ 

Example_2_7 中将元组 additional_items 参数设置为 false ,以查看是否抛出了异常。 

通过将 additional_items 参数的值设置为 true,可以向元组添加任何 6 种 JSON 类型。但是,有时 additionalItems 属性必须符合特定 schema。例如,可以将可以添加到元组的类型限制为仅 JSON 字符串类型。下面的 schema 正是这样做的。

/*    
{
      "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

      "id": "ExampleID-028",

      "title": "arrayExamples",

      "description": "Array Additional Items Demo Schema",

      "type": "object",

       "properties":  {
               "arrayObject": {
                        "type": "array",
                         "items": [
                                 {
                                   "type": "integer"
                                   },

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

                                       "enum": ["Street", "Avenue", "Boulevard"]
                                    }, 

                                    {
                                       "type": "string",

                                       "enum": ["NW", "NE", "SW", "SE"]
                                    },
                            ],

                            "uniqueItems": true,

                             "additionalItems": 
                              {
                               "type": "string"
                              }
               }
     },

      "required": ["arrayObject"]
     }

  */

 请注意,数组的 additionalItems 属性现在有一个 schema 作为值,而不是之前分配的布尔值。

要将附加项属性的值设置为 schema,请使用第二个数组构造函数,即 JsonSchemaObject (string object_name,int? minimum_items,int? maximum_items,bool is_unique_items,JsonSchemaObject additional_items,string description,bool is_required = false),  以实例化 JSON 数组对象,如 Example_2_8 中所做的那样。请参阅下面的代码。

//Example_2_8
...

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


JsonSchemaObject  _json_schema_array  = new JsonSchemaObject ("arrayObject",null,null,true,
_json_schema_state,string.Empty,true);

...

请注意,additionalItems 属性的默认值为 true。当 additionalItems 属性未在 JSON 数组 schema 中出现时,假定其设置为 true

如果 additionalItems 属性为布尔类型,则可以从 JsonSchemaObject 类的 AdditionalItemsBool 属性中读取其值。如果它是 schema 类型,则应从 JsonSchemaObject 类的 AdditionalItemsObject 属性中读取。

JSON 对象类型属性

本节介绍 JSON 对象类型的所有属性。

附加属性

additionalProperties 属性对于 JSON 对象类型 schema 来说,就像 additionalItems 对于 JSON 数组类型 schema 一样。  并且,就像 JSON 数组的 addItems 一样,additionalProperties 属性可以接受布尔值或 schema 值。additionalProperties 的默认值为 true,并且在 JSON 对象 schema 中未将其作为属性出现时,假定其设置为 true。在下面显示的 schema 中,additionalProperties 假定为 true。

//Example_2_9
   
{
    "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

    "id": "ExampleID-029",

    "title": "objectExamples",

    "description": "OBJECT Additional Properties Demo",

    "type": "object",

    "properties":  {

               "jsonObject": {
                     "type": "object",

                      "properties":  {
                         "houseNumber": {
                                "type": "integer"
                           },

                           "streetName": {
                                  "type": "string"
                             },

                              "streetType": {
                                      "type": "string",

                                       "enum": ["Street", "Avenue", "Boulevard"]
                               },

                               "direction": {
                                        "type": "string",

                                     "enum": ["NW", "NE", "SW", "SE"]
                                 }
                        },
                        "required": ["houseNumber", "streetName", "streetType","direction"]
                 }
  },

  "required": ["jsonObject"]
}


请注意,上面显示的 schema 中,jsonObject 属性与数组元组 arrayObject (在前一节中讨论过,请参见 Example_2_8 例程)的属性相似。

JsonSchemaObject (string object_name,int? minimum_properties,int? maximum_properties,JsonSchemaObject additional_properties,string description,bool is_required = false) 构造函数用于实例化 jsonObject,如下面的代码所示。

//Example_2_9

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


JsonSchemaObject _json_schema_street_name        = new JsonSchemaObject ("streetName", JSON_TYPE.STRING, string.Empty, true);
			
			
JsonSchemaObject _json_schema_street_type   = new JsonSchemaObject ("streetType", 
JSON_TYPE.STRING, string.Empty, true);

_json_schema_street_type .AddEnumList (new List<string>(new string[] {"Street","Avenue","Boulevard"}));


JsonSchemaObject _json_schema_direction   = new JsonSchemaObject ("direction", JSON_TYPE.STRING, string.Empty, true);

_json_schema_direction .AddEnumList (new List<string>(new string[] {"NW","NE","SW","SE"}));



_JsonSchemaObject  _json_schema_sub_object =  new JsonSchemaObject ("jsonObject",null,null,true,string.Empty,true);

_json_schema_sub_object.AddObject (_json_schema_house_number);
_json_schema_sub_object.AddObject (_json_schema_street_name);
_json_schema_sub_object.AddObject (_json_schema_street_type);
_json_schema_sub_object.AddObject (_json_schema_direction);


JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, 
"objectExamples","OBJECT Additional Properties Demo", "ExampleID-029");

_json_schema_object.AddObject (_json_schema_sub_object);

_schema_string = _json_schema_engine.Serialize (_json_schema_object);

由于 additionalProperties 参数默认为 true,因此可以将 state 属性添加到上面 schema 的实例中,如下面的序列化实例文本所示。
 

//Example_2_9

/*

{
    "jsonObject":  {
    "houseNumber": 1600, 
    "streetName": "Pennsylvania", 
    "streetType": "Avenue", 
    "direction": "NW", 
    "state": "Washington"
    }
}
*/
 

additionalProperties 参数设置为 false,然后运行 Example_2_9 例程,查看抛出的异常。

如前所述,additionalProperties 属性的值也可以是一个 schema,用于限制在实例化 schema 时可以添加的 JSON 类型。要做到这一点,请使用 JsonSchemaObject (string object_name,int? minimum_properties,int? maximum_properties,JsonSchemaObject additional_properties,string description,bool is_required = false) 构造函数。  如果使用此构造函数,则 schema 的序列化输出应类似于下面的文本。

//Example_2_10

/*   
{
           "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",
           "id": "ExampleID-0210",
           "title": "objectExamples",
           "description": "OBJECT Additional Properties Demo",
           "type": "object",
            "properties":  {
                            "jsonObject": {
                                    "type": "object",
                                 "properties":  {
                                      "houseNumber": {
                                         "type": "integer"
                                       },

                                        "streetName": {
                                         "type": "string"
                                         },

                                          "streetType": {
                                              "type": "string",

                                               "enum": ["Street", "Avenue","Boulevard"]
                                            },

                                            "direction": {
                                               "type": "string",

                                                 "enum": ["NW", "NE", "SW","SE"]
                                            }
                                   },
                               "required": ["houseNumber", "streetName", "streetType",
                                           "direction"],
                                          
                               "additionalProperties": 
                                {
                                     "type": "string"
                                }
                              }
          },

         "required": ["jsonObject"]
}
			
*/

如果需要实例化的 JSON 对象是顶层对象,则使用以下任一构造函数代替

  1. JsonSchemaObject (JSON_VERSION version,string title,string description,string object_id,bool additional_properties = true)
  2. JsonSchemaObject (JSON_VERSION version,string title,string description,string object_id,JsonSchemaObject additional_properties).

additionalProperties 参数可以根据其值类型从 JsonSchemaObject 类的 AdditionalPropertiesBool 或 AdditionalPropertiesObject 属性中读取。 

模式属性

除了通过将 additionalProperties 值设置为特定的 schema 定义来限制它之外,JSON schema 规范还提出了另一种称为模式属性 (Pattern Properties) 的机制,它提供了另一层控制附加属性可以采用的结构。  模式属性最好通过示例来解释,使用下面的代码片段。

/Example_2_13


/*  
    {
        "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

        "id": "ExampleID-0213",

        "title": "objectExamples",

        "description": "OBJECT Pattern Properties Demo",

        "type": "object",

        "patternProperties": {

                      "^S_[a-zA-Z0-9]*$": {
                               "type": "string",
                               "minLength": 1,
                               "maxLength": 255
                        },
 
                        "^N_[a-zA-Z0-9]*$": {
                               "type": "number",
                               "minimum": 1,
                               "maximum": 80,
                               "multipleOf": 5,

                          }
       }
}

*/
 

上面 patternProperties 属性的子属性强制执行一个规则,该规则规定任何以 "S_" 开头的附加属性名称必须是 JSON 类型字符串,并且字符长度不得小于 1 且不得大于 255。相应地,任何名称以 "N_" 开头的附加属性必须是 JSON 类型数字,值必须在 1 到 80 之间,并且必须是 5 的倍数。

上述 schema 是使用下面的代码片段生成的(请参见 Example_2_13 例程)。 

 //Example_2_13
  
JsonSchemaObject _json_schema_string_specs   = new JsonSchemaObject (string.Empty,1,255,
string.Empty,string.Empty, false);


JsonSchemaObject _json_schema_number_specs = new JsonSchemaObject (string.Empty, 
JSON_TYPE.NUMBER,1,80,5.0, string.Empty,false);


JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, "objectExamples", "OBJECT Pattern Properties Demo", "ExampleID-0213");

_json_schema_object.AddPatternProperty (_json_schema_string_specs, "S_[a-zA-Z0-9]*");
_json_schema_object.AddPatternProperty (_json_schema_number_specs, "N_[a-zA-Z0-9]*");


_schema_string = _json_schema_engine.Serialize (_json_schema_object);

使用 AddPatternProperty (JsonSchemaObject json_schema_object, string property_pattern) 例程将模式属性 (patternProperties) 添加到 JSON 对象类型,如上所示。

使用下面的代码片段创建 schema 的实例

//Example_2_13
    
JsonInstanceObject _json_instance_string =  new JsonInstanceObject (new JsonSchemaObject("S_24",JSON_TYPE.STRING,string.Empty), "Donkey Hotey");
  
JsonInstanceObject _json_instance_number =  new JsonInstanceObject (new JsonSchemaObject("N_25",JSON_TYPE.NUMBER,string.Empty),60);


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

 
_instance_string = _json_instance_engine.Serialize (_json_instance_object);

_json_instance_number 和 _json_instance_string 对象的 patternProperties 定义所施加的限制是一致的。将传递给 _json_instance_number 的值更改为 100。有什么理由会抛出异常吗? 

下面是 schema 实例的序列化文本表示。

//Example_2_13

/*    
{
   "N_25": 60, 
   "S_24": "Donkey Hotey"
}
*/

有关模式属性 (Pattern Properties) 的更多示例,请参阅 Example_2_14Example_2_15 Example_2_16 例程。

必需、最小和最大属性

required 属性在第一部分中已讨论过。正式来说,它是一个属性名称的有序列表,在实例化对象类型的 schema 时必须存在。在此类中,如果在实例化 JSON 对象 schema 时,缺少标记为必需的属性,则会抛出异常。

minProperties maxProperties 控制 JSON 对象类型允许拥有的属性数量的下限和上限。在下面显示的 schema 中,jsonObject 属性允许拥有 1 到 6 个属性,不多不少。

 

//Example_2_11

/*  
   
{
    "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

    "id": "ExampleID-0211",

    "title": "objectExamples",

    "description": "OBJECT Max and Min Properties Demo",

    "type": "object",

    "properties":  {

                   "jsonObject": {
                                "type": "object",
                                "properties":  {

                                            "objectString": {
                                            "type": "string"
                                             }
                                 },

                                "required": ["objectString"],
                                "minProperties": 1,
                                "maxProperties": 6
                   }
   },

   "required": ["jsonObject"]
}

*/
 

请参阅下面的 Example_2_11 代码片段,了解如何设置 minProperties maxProperties 值。

//Eaxmple_2_11
    
JsonSchemaObject _json_schema_string  = new JsonSchemaObject ("objectString", JSON_TYPE.STRING,
string.Empty, true);


JsonSchemaObject _json_schema_sub_object    = new JsonSchemaObject ("jsonObject",1,6,true,
string.Empty,true);


_json_schema_sub_object.AddObject (_json_schema_string);

JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, "objectExamples", "OBJECT Max and Min Properties Demo", "ExampleID-0211");

_json_schema_object.AddObject (_json_schema_sub_object);

_schema_string = _json_schema_engine.Serialize (_json_schema_object);

 

下面的 jsonObject schema 实例化代码片段除了在 schema 中显式定义的 objectString 属性外,还添加了四个额外项。  这被允许,因为 additionalProperties 参数设置为 true。

//Example_2_11
    
 int _extra_properties_count = 4;

for (int i=0; i < _extra_properties_count; i++)
{
				 
	_instance_object_list.Add (new JsonInstanceObject (
    new JsonSchemaObject ("extraString-" + (i+1).ToString (), JSON_TYPE.STRING,string.Empty,
    true), "extra-string_value" + (i+1).ToString ()));
									                   

}


JsonInstanceObject _json_instance_sub_object = new JsonInstanceObject (_json_schema_sub_object, _instance_object_list);

_instance_object_list.Clear ();

_instance_object_list.Add (_json_instance_sub_object);

JsonInstanceObject _json_instance_object = new JsonInstanceObject (_json_schema_object,
_instance_object_list);

_instance_string = _json_instance_engine.Serialize (_json_instance_object); 

如下面的序列化实例文本所示,这使得 schema 实例的属性总数为 5。将 Example_2_13 例程中的 _extra_properties_count 值更改为大于或等于 6 的数字,并查看当属性数量超过 maxProperties 值时是否抛出异常。

//Example_2_11

/*    
    
{
    "jsonObject":  {
               "objectString": "main-string_value", 
               "extraString-1": "extra-string_value1", 
               "extraString-2": "extra-string_value2", 
               "extraString-3": "extra-string_value3", 
               "extraString-4": "extra-string_value4"
     }
}

 */

minProperties 和 maxProperties 值可以从 JsonSchemaObject 类的 MinimumProperties 和 MaximumProperties 属性中读取。

依赖项 

//Example_2_12

/*
{
    "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",
    "id": "ExampleID-0212",
    "title": "objectExamples",
     "description": "OBJECT Dependencies Properties
     "type": "object",
     "properties":  {
                     "billingObject": {
                          "type": "object",

                           "properties":  {

                                  "holderName": {
                                     "type": "string"
                                    },

                                    "creditCard": {
                                       "type": "number"
                                     },

                                     "billingAddress": {
                                         "type": "string"
                                     }
                           }
                        }
   },

   "required": ["billingObject"]
}


 */

从上面的 schema 可以看出,billingObject 有 3 个属性,即 holderNamecreditCard 和 billingAddress。虽然 billingObject 是必需的,但它的 3 个属性不是。

设想一个场景,其中一个 JSON 对象属性不能独立于另一个存在。例如,如果存在 creditCard 属性,则 billingAddress 属性也必须存在,反之亦然。换句话说,creditCard 和 billingAddress 属性相互依赖。  JSON schema validation 规范可以使用 dependencies 关键字强制执行此规则。

JSON schema validation 规范定义了两种 dependencies 类型:SchemaProperty。这两种 dependencies 类型在功能上是相似的。下面的代码显示了如何使用这些类来实现 dependencies 。

//Example_2_12

JsonSchemaObject _json_schema_name  = new JsonSchemaObject ("holderName", JSON_TYPE.STRING, 
string.Empty, false);

JsonSchemaObject _json_schema_credit_card= new JsonSchemaObject ("creditCard", JSON_TYPE.NUMBER, string.Empty, false);

JsonSchemaObject _json_schema_billing_address  = new JsonSchemaObject ("billingAddress", 
JSON_TYPE.STRING, string.Empty, false);

JsonSchemaObject _json_schema_billing_object    = new JsonSchemaObject ("billingObject", null,
 null,true,string.Empty, true);

_json_schema_billing_object .AddObject(_json_schema_name);
_json_schema_billing_object .AddObject(_json_schema_credit_card);
_json_schema_billing_object .AddObject(_json_schema_billing_address);


List<jsonschemaobject> _schema_dependency_list = new List<jsonschemaobject> ();

_schema_dependency_list.Add (_json_schema_name);
_schema_dependency_list.Add (_json_schema_billing_address);

JsonSchemaObject _json_schema_credit_card_dependency = new JsonSchemaObject(_json_schema_credit_card,_schema_dependency_list);

_schema_dependency_list.Clear ();

_schema_dependency_list.Add (_json_schema_credit_card);
		

JsonSchemaObject _json_schema_billing_address_dependency = 
new JsonSchemaObject(_json_schema_billing_address,_schema_dependency_list );

_json_schema_billing_object.AddDependencies (JSON_DEPENDENCY_TYPE.PROPERTY,
			            new List<JsonSchemaObject> (new JsonSchemaObject[] {
                        _json_schema_credit_card_dependency,
				        _json_schema_billing_address_dependency}));

/* Line 1

_json_schema_billing_object.AddDependencies (JSON_DEPENDENCY_TYPE.SCHEMA,
			               new List<JsonSchemaObject> (new JsonSchemaObject[] {
                           _json_schema_credit_card_dependency,
				           _json_schema_billing_address_dependency}));

 // */


JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, 
"objectExamples","OBJECT Dependencies Properties Demo", "ExampleID-0212");

_json_schema_object.AddObject (_json_schema_billing_object);


_schema_string = _json_schema_engine.Serialize (_json_schema_object);


依赖对象是使用 JsonSchemaObject (JsonSchemaObject dependent_object,List<JsonSchemaObject> dependency_object_list) 构造函数创建的。在上面的代码行中,此构造函数的第一参数是被依赖对象,第二个参数是该被依赖对象所依赖的对象列表。上面的 _json_schema_credit_card_dependency schema 对象是一个 dependencies 对象,它表示 creditCard 属性依赖于 holderName 和 billingAddress 属性。_json_schema_billing_address_dependency schema 对象表示 billingAddress 属性依赖于 creditCard 属性。

使用 AddDependencies (JSON_DEPENDENCY_TYPE dependency_type,List<JsonSchemaObject> json_dependency_object_list) 例程将依赖项添加到 JSON 对象类型。传递给此例程的第一个参数是所需的依赖项类型。第二个参数是要添加到 JSON 对象中的依赖项列表。

序列化后,输出字符串应类似于下面的内容;

//Example_2_12


/*
{
    "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",
    "id": "ExampleID-0212",
    "title": "objectExamples",
     "description": "OBJECT Dependencies Properties
     "type": "object",
     "properties":  {
                     "billingObject": {
                           "type": "object",

                             "properties":  {
                                      "holderName": {
                                        "type": "string"
                                          },

                                        "creditCard": {
                                         "type": "number"
                                          },

                                          "billingAddress": {
                                           "type": "string"
                                          }

                           },
 
                          "dependencies": {

                              creditCard: [holderName, billingAddress],
                              billingAddress: [creditCard]
                           }
                        }
   },

   "required": ["billingObject"]
}


 */

上面显示的 JSON schema 字符串是属性 dependencies 类型的一个示例。

要获得下面显示的 Schema dependencies 类型的表示,请注释掉 Example_2_12 代码中的“第 1 行”。

//Example_2_12

/*    
{
         "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",

         "id": "ExampleID-0212",

         "title": "objectExamples",

         "description": "OBJECT Dependencies Properties Demo",

          "type": "object",

           "properties":  {

                        "billingObject": {
                              "type": "object",
                                "properties":  {
                                      "holderName": {
                                           "type": "string"
                                       },

                                        "creditCard": {
                                         "type": "number"
                                          },

                                          "billingAddress": {
                                           "type": "string"
                                          }
                            },

                            "dependencies": {
                                   creditCard: {
                                        "properties":  {
                                            "holderName": {
                                               "type": "string"
                                              },

                                              "billingAddress": {
                                                     "type": "string"
                                               }

                                            },

                                            "required": ["holderName", "billingAddress"]

                                    },

                                    billingAddress: {
                                      "properties": {
                                           "creditCard": {
                                            "type": "number"
                                             }
                                        },

                                       "required": ["creditCard"]
                                     }
                                }
                         }
           },

    "required": ["billingObject"]
}
		

*/
 

下面是上述 schema 的实例。

  // Example_2_12  
{
       "billingObject":  {
                "holderName": "Donkey Hotey", 
                "creditCard": 234555554444, 
                "billingAddress": "No. 2 North West Street"
        }
}
 

作为测试,在创建实例时排除 creditCard 属性,方法是注释掉 Example_2_12 例程中的“第 2 行”,以查看抛出了什么异常。

JSON Schema 约束属性

 //Example_2_17

/*   
 {
    "$schema": "https://json-schema.fullstack.org.cn/draft-04/schema#",
    "id": "ExampleID-0217",
    "title": "objectExamples",
    "description": "OBJECT Constraint Demo",
    "type": "object",
    "properties":  {

         "anonObject": {

              "oneOf": [
                  {
                    "type": "string"
                  },
 
                  {
                   "type": "integer"
                  },

                 {
                  "type": "boolean"
                 }
            ]
       }
   },

   "required": ["anonObject"]
}

*/

上述 schema 的解释表明,在实例化 schema 时,anonObject 属性可以是字符串、整数或布尔类型。oneOf 关键字为 JSON 属性提供了灵活性,但也有一些限制。灵活性在于属性可以是 JSON 类型 A 或类型 B,并且仍然有效。约束在于这种灵活性受 oneOf 关键字中定义的类型限制。

除了 oneOf 约束之外,JSON 规范还定义了三种约束类型,即 notallOf 和 anyOf。请参阅下面这些约束的列表项解释;

  1. oneOf : schema 的实例必须匹配关键字定义的 schema(schemata)中的一个且仅一个。
  2. not: schema 的实例可以采用除关键字定义的类型之外的任何类型。
  3. anyOf : schema 的实例可以匹配关键字定义的任何一个 schema(schemata)。
  4. allOf : schema 的实例必须匹配此关键字定义的所有 schema(schemata)。

用于创建和序列化上面 anonObject schema 文本的代码片段如下所示。

//Example_2_17
    
JsonSchemaObject _json_schema_object_string  = new JsonSchemaObject ("stringObject",
JSON_TYPE.STRING,string.Empty);

JsonSchemaObject _json_schema_object_integer = new JsonSchemaObject ("integerObject",
JSON_TYPE.INTEGER ,null, null, null, string.Empty, true);

JsonSchemaObject _json_schema_object_bool    = new JsonSchemaObject ("boolObject",
JSON_TYPE.BOOLEAN,string.Empty);


JsonSchemaObject _json_schema_constraint =  new JsonSchemaObject ("anonObject", 
JSON_CONSTRAINT_TYPE.ONEOF, string.Empty,true);

_json_schema_constraint.AddObject (_json_schema_object_string);
_json_schema_constraint.AddObject (_json_schema_object_integer);
_json_schema_constraint.AddObject (_json_schema_object_bool);


JsonSchemaObject _json_schema_object = new JsonSchemaObject (JsonUtilities.JSON_VERSION.V4, 
"constraintExamples", "OBJECT Constraint Demo", "ExampleID-0217");

_json_schema_object.AddObject (_json_schema_constraint);

_schema_string = _json_schema_engine.Serialize (_json_schema_object); 

请注意,anonObject 对象使用此构造函数实例化:JsonSchemaObject(string object_name,JSON_CONSTRAINT_TYPE object_constraint,string description,bool is_required = false)。  注意传递给构造函数的第二个参数是约束类型,即 JSON_CONSTRAINT_TYPE.ONEOF。  约束的 schema(schemata)是使用 AddObject (JsonSchemaObject json_schema_object) 例程添加的,如上所示。

anonObject 属性是使用下面的代码实例化的。

 //Example_2_17
  
JsonInstanceObject _json_instance_anon_object = null;

_json_instance_anon_object =  new JsonInstanceObject (new JsonSchemaObject("anonObject",
JSON_TYPE.BOOLEAN,string.Empty),true);


/* Line 1

_json_instance_anon_object = new JsonInstanceObject (new JsonSchemaObject ("anonObject",
 JSON_TYPE.NUMBER, string.Empty), 60);

 //*/

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


_instance_string = _json_instance_engine.Serialize (_json_instance_object);    

在上面的代码中,anonObject 的值被设置为布尔类型,这当然是 oneOf 属性中设置的三种有效 schema 之一。注释掉 Example_2_17 代码中的第 1 行标记部分并再次运行该示例。有什么理由会抛出那个异常吗?

下面是 anonObject schema 实例的序列化输出。

//Example_2_17

  /*  
{
  "anonObject": true
}

*/
 

有关 JSON schema 约束的更复杂示例,请参阅 Example_2_18 例程。 

关注点

第一部分一样!;)

历史

2015/01/04: 第一个版本。

2015/02/04: 修改了 JSON String 类型 schema 构造函数。

2016/03/05: 修改了此 JSON 库的 DoEscape 函数,使其符合www.json.org 的转义规范。

2016/03/11: 修正了 JSON 反转义函数。用 Net Core 版本替换了附加的代码。

© . All rights reserved.