請先閱讀 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 } }