【C# 序列化】System.Text.Json.Nodes ---Json数据交换格式 对应C#类

发布时间 2023-07-10 17:33:49作者: WebEnh

请先阅读 JSON数据交换格式

Json数据交换格式 对应C#类

System.Text.Json.Nodes:.NET 6

依微软的计划,System.Text.Json 应取代Newtonsoft.Json(Json.NET),成为 .NET Core/.NET 5+ 奥林匹克指定 JSON 程式库。System.Text.Json 主打轻巧高效能,但毕竟发展时间尚短,与身经百战的老将 Json.NET 相比,在功能完整性及可扩充性上仍有点“嫩”。其中我觉得最不便的地方是缺少像 Json.NET 一样的 JObjec/JArray 物件模型,无法动态巡览 JSON 属性或修改内容,更甭提整合 dynamic 动态型别的花式应用。

好消息! .NET 6 起,System.Text.Json 补强了这段,加入 JsonNode、JsonObject、JsonArray、JsonValue 等型别,对映到 Json.NET 的 JToken、JObject、JArray、JValue,允许开发者以物件模型方式建构 JSON 文件,或是将 JSON 文件转为物件资料结构,进行增删修改或属性巡览,有了这项武器,处理 JSON 文件就更方便了。

 writeable DOM

. net 6提供了处理内存中可写文档对象模型(DOM)的类型,用于在数据的结构化视图中随机访问JSON元素。

对于新增操作我们可以使用JsonObject类和JsonArray类去创建JSON DOM:

  • JsonObject:表示创建JSON对象;
  • JsonArray:表示创建JSON数组。

 

 

 

 

 

主要的 API 如下:

  • JsonNode: JSON 文档中的一个节点,对应 Newtonsoft.Json 里的 JToken,内部有字典字段
  • JsonObject: JSON 对象继承自JsonNode,对应 Newtonsoft.Json 里的 JObject是字典结构继承了JsonValue、ICollection、IDictionary、IEnumerable。
  • JsonArray: JSON 数组继承自JsonNode,对应 Newtonsoft.Json 里的 JArray,是list结构继承了JsonValue、ICollection、IList、IEnumerable。
  • JsonValue: JSON 中的一个值继承自JsonNode,对应 Newtonsoft.Json 里的 JValue 继承了IEnumerable。

JsonNode用法

案例一

生成、获取JsonNode子节点、以及属性的值

你可以使用 JsonNode.Parse("") 来将一个 JSON 转换成一个 JsonNode 对象,可以看下面的示例:

 

复制代码
using System.Text.Json;
using System.Text.Json.Nodes;

//生成JsonNode节点
JsonNode JObjectNode = JsonNode.Parse(@"{""ShangHai"":""42""}")!;//将string 解析为JsonNode
JsonObject  JObject = JObjectNode.AsObject()!;//JsonNode 转化为Object对象

//解析并且转化成JsonArray
JsonArray JArray = JsonNode.Parse(@"[{""HangZhou"":52},{""MyProperty"":true}]")!.AsArray();

//获取值子节点
JsonNode sun = JArray[1];
Console.WriteLine($"Parent Node:{sun.Parent}");
Console.WriteLine($"Root Node:{sun.Root}");
Console.WriteLine($"JsonNodeOptions:{sun.Options}");
Console.WriteLine(sun.ToJsonString());

//获取节点的值
Console.WriteLine(JObject["ShangHai"]!.GetValue<string>());
//OR
string value = (string)JObject["ShangHai"]!;
Console.WriteLine(value);

Console.WriteLine(JArray[1]!["MyProperty"]!.GetValue<bool>());
复制代码

 

案例二

复制代码
//获取天气
HttpClient hc=new HttpClient(); string joson = await hc.GetStringAsync("http://www.weather.com.cn/data/sk/101010100.html"); var weather=JsonNode.Parse(joson); string city=weather["weatherinfo"]["city"].ToJsonString(); Console.WriteLine(city); Console.Read();
复制代码

 

案例三、

使用对象初始值设定项创建 JsonNode DOM 并进行更改

以下示例介绍如何:

  • 使用对象初始值设定项创建 DOM。
  • 对 DOM 进行更改。

 

复制代码
using System.Text.Json;
using System.Text.Json.Nodes;
//新增操作
JsonObject jo = new JsonObject
{
    //JsonObject继承JsonNode ,JsonNode内部有字典和索引(索引会生成一个node)。字典初始值设定项
    ["Message"] = "个人信息",
    ["Father"] = new JsonObject { ["Name"] = "张三" },
    ["Son"] = new JsonArray(
        //JsonArray 内部有一个list和Add()方法。  JsonArray列表初始化设定项
        new JsonObject
        {
            ["Name"] = "张小小",
            ["Pet"] = new JsonArray("小花狗", "小花猫"),
            ["Age"] = ""
        },
        new JsonObject
        {
            ["Name"] = "张大大",
            ["Pet"] = new JsonArray("小狼狗", "小公鸡"),
            ["Age"] = 2
        })
};
string jsonString = jo.ToJsonString(new JsonSerializerOptions { WriteIndented = true });
var njo = JsonNode.Parse(jsonString);
Console.WriteLine(jsonString);


//查询操作

Console.WriteLine(njo["Son"][1]["Name"]!);////运行后输出 “张大大”

//修改操作
njo["Message"] = "zhagnxiaoxiao";

//当然,我们不仅能改还可以给节点增加属性和新的节点:

//增加新节点
njo["SearchDate"] = new JsonObject { ["UTC"] = "2021/12/1 00:00:00", ["UTC8"] = "2021/12/ 08:00:00" };
Console.WriteLine(njo.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));
Console.Read();
//删除操作 对于删除,.NET6并没有提供删除节点的方法,但我们可以使用一个变通的方法来实现,就是通过将节点设为null,序列化时忽略,代码如下:
njo["SearchDate"] = null;

Console.WriteLine(njo.ToJsonString(new JsonSerializerOptions { WriteIndented = true }));
//写入流
using MemoryStream ms=new MemoryStream();
Utf8JsonWriter writer = new Utf8JsonWriter(ms);
jo.WriteTo(writer);
writer.Flush();
var jsonString2 = ms.ToArray();
 
复制代码

 

JsonObject用法

 

复制代码
 
using System.Text.Json;
using System.Text.Json.Nodes;



//生成JsonNode节点
JsonNode JObjectNode = System.Text.Json.Nodes.JsonNode.Parse(@"{""ShangHai"":42,""HangZhou"":23}")!;//将string 解析为JsonNode

#region 新建一个JsonObject 对象 多种方法
JsonObject JObject = JObjectNode.AsObject()!;//JsonNode 转化为Object对象

//  方式1
JsonObject JObject1 = new();
JObject["JiangSu"] = 54;
JObject["ShangHai"] = 32;
JObject["HangZhou"] = 44;

//or  方式2  依赖于Add方法
JsonObject JObject2 = new (){ ["ShangHai"] = 42, ["HangZhou"] = 23 };//依赖与Add方法


//or  方式3 依赖于Add方法
JsonObject JObject3 = new();
JObject.Add(KeyValuePair.Create<string, JsonNode>("name3", "value3"!)!);
JObject.Add("name4", "value4");

//or  方式4  索引
JsonObject JObject4 = new JsonObject(
    new[]
    {
        KeyValuePair.Create<string, JsonNode?>("name1", "value1"),
        KeyValuePair.Create<string, JsonNode?>("name2", 2),
    }
);
 
//or 方式5  索引
var dictionary = new Dictionary<string, JsonNode>
{
    ["name1"] = "value1"!,
    ["name2"] = 2
};

JsonObject JObject5 = new JsonObject(dictionary!);

#endregion


//添加Json属性

JObject.Add("BeJing", 23);
//or 
JObject["YunNan"] = new JsonArray
{
   new JsonObject{["Name"] = "Spot"},
    new JsonObject{["Exp"] = 255},
       new JsonObject{["Exp1"] = 257},
};
//or
JObject["KunMing"] = new JsonArray("Shield", "Sword", "Bottle");
//or



Console.Clear();
Console.WriteLine("添加3个属性");
Console.WriteLine(JObject.ToJsonString(new JsonSerializerOptions() {  WriteIndented=true}));
Console.Read();


Console.WriteLine(JObject.ContainsKey("BeJing"));//是否包含属性
Console.WriteLine(JObject.Count);//对象中属性的个数

Console.WriteLine(JObject["ShangHai"]!.GetValue<int>());

//删除属性
JObject.Remove("ShangHai");
//or
var array = JObject["YunNan"]!.AsArray();


//https://blog.darkthread.net/blog/system-text-json-writable-dom/
//array.Remove(array.Single(o => o?.GetValue<string>() == "Bottle"));
//or
var itme = array.Single(o => o.AsObject().ContainsKey("Exp"));
array.Remove(itme);
Console.WriteLine("移除后的数组");
Console.WriteLine(array.ToJsonString(new JsonSerializerOptions() { WriteIndented = true }));
Console.WriteLine("移除后的对象");
Console.WriteLine(JObject.ToJsonString(new JsonSerializerOptions() { WriteIndented = true }));

Console.Read();
//读取
string HangZhou = (string)JObject["HangZhou"]!;
string YunNan = (string)JObject["YunNan"]![1]!;
JObject["HangZhou"]!.GetValue<string>();

//JsonObject.GetEnumerator
var enumerator=JObject.GetEnumerator();
while (enumerator.MoveNext())
{
    var current=enumerator.Current;
    Console.WriteLine(current.Key);
}

//JsonObject.TryGetPropertyValue
JsonNode  jnode = new JsonArray() ;
if(JObject.TryGetPropertyValue("YunNan", out jnode))
{
    Console.WriteLine(true);
};



JObject.Clear();//清空字典
复制代码

 

 JsonArray用法

复制代码
 
using System.Text.Json;
using System.Text.Json.Nodes;

JsonNode obJsonNode= JsonValue.Create("Beijing") ;
JsonNode obJsonNode2 = JsonValue.Create("Toamkomg");

JsonArray jsonArray =new JsonArray {"shanghai","jiangsu" };
jsonArray.Add("yunan");
jsonArray.Add("jiangsu");
jsonArray.Add(obJsonNode);
jsonArray.Insert(0,obJsonNode2);
Console.WriteLine(jsonArray.Contains(obJsonNode));
Console.WriteLine(jsonArray.IndexOf(obJsonNode));
Console.WriteLine(jsonArray.Count);
Console.WriteLine(jsonArray.ToJsonString(new JsonSerializerOptions {PropertyNameCaseInsensitive=true}));
jsonArray.Remove(obJsonNode);
Console.WriteLine(jsonArray.ToJsonString(new JsonSerializerOptions { PropertyNameCaseInsensitive = true }));
jsonArray.RemoveAt(0);
Console.WriteLine(jsonArray.ToJsonString(new JsonSerializerOptions { PropertyNameCaseInsensitive = true }));
复制代码

 JsonValue.Create用法

 

 

 

System.Text.Json

该命名空间自 2019 年 9 月以来一直存在,但是,只有最近发布的 .NET 6(2021 年 11 月)包含了一种使用 创建和操作 JSON 的方法。System.Text.JsonJsonNode

一个常见的替代方案是使用 ,这是Newtonsoft Json.NET 的一部分,可以在许多.NET项目中看到。JTokenJObjectJArrayJValue

解析Json数据

复制代码
string data = @" [ {""name"": ""John Doe"",""occupation"": ""gardener""},
    {""name"": ""Peter Novak"", ""occupation"": ""driver""}  ]";
//文档解析配置
JsonDocumentOptions jdo=new(){ AllowTrailingCommas=true, CommentHandling= JsonCommentHandling.Skip };

JsonDocument? jscon= JsonDocument.Parse(data);
JsonElement je = jscon.RootElement;
if (je.ValueKind == JsonValueKind.Array)
{
    JsonElement.ArrayEnumerator enumerateArray = je.EnumerateArray();
    JsonElement.ArrayEnumerator users = enumerateArray.GetEnumerator();
    while (users.MoveNext())
    {
        var use = users.Current;
        Console.WriteLine(use.GetProperty("name"));

    }
   
}
复制代码

 使用Utf8JsonWriter编写原始JSON

. net 6引入了使用System.Text.Json.Utf8JsonWriter编写原始JSON的可能性。

复制代码
using System.Text.Json;
using System.Text.Json.Nodes;

namespace JsonNodePOCOExample;

public class TemperatureRanges : Dictionary<string, HighLowTemps>
{
}

public class HighLowTemps
{
    public int High { get; set; }
    public int Low { get; set; }
}

public class Program
{
    public static DateTime[]? DatesAvailable { get; set; }

    public static void Main()
    {
        string jsonString =
@"{
  ""Date"": ""2019-08-01T00:00:00"",
  ""Temperature"": 25,
  ""Summary"": ""Hot"",
  ""DatesAvailable"": [
    ""2019-08-01T00:00:00"",
    ""2019-08-02T00:00:00""
  ],
  ""TemperatureRanges"": {
      ""Cold"": {
          ""High"": 20,
          ""Low"": -10
      },
      ""Hot"": {
          ""High"": 60,
          ""Low"": 20
      }
  }
}
";
        // Parse all of the JSON.
        JsonNode forecastNode = JsonNode.Parse(jsonString)!;

        // Get a single value
        int hotHigh = forecastNode["TemperatureRanges"]!["Hot"]!["High"]!.GetValue<int>();
        Console.WriteLine($"Hot.High={hotHigh}");
        // output:
        //Hot.High=60

        // Get a subsection and deserialize it into a custom type.
        JsonObject temperatureRangesObject = forecastNode!["TemperatureRanges"]!.AsObject();
        using var stream = new MemoryStream();
        using var writer = new Utf8JsonWriter(stream);
        temperatureRangesObject.WriteTo(writer);
        writer.Flush();
        TemperatureRanges? temperatureRanges = 
            JsonSerializer.Deserialize<TemperatureRanges>(stream.ToArray());
        Console.WriteLine($"Cold.Low={temperatureRanges!["Cold"].Low}, Hot.High={temperatureRanges["Hot"].High}");
        // output:
        //Cold.Low=-10, Hot.High=60

        // Get a subsection and deserialize it into an array.
        JsonArray datesAvailable = forecastNode!["DatesAvailable"]!.AsArray()!;
        Console.WriteLine($"DatesAvailable[0]={datesAvailable[0]}");
        // output:
        //DatesAvailable[0]=8/1/2019 12:00:00 AM
    }
}
复制代码