【C# 序列化】System.Text.Json.Nodes ---Json数据交换格式 对应C#类
请先阅读 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.Json
JsonNode
一个常见的替代方案是使用 ,这是Newtonsoft Json.NET 的一部分,可以在许多.NET项目中看到。JToken
JObject
JArray
JValue
解析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 } }