使用JSON.NET反序列化含层级结构的动态JSON字符串
如何使用JSON.NET反序列化包含层级结构的动态JSON字符串?
嘿,这个问题我刚好处理过类似的场景,用JSON.NET(也就是大家常说的Newtonsoft.Json)来搞定这种递归层级的JSON其实挺顺手的,给你两种实用方案,按需选择就行:
方案一:强类型反序列化(推荐,适合结构固定的场景)
你的JSON是典型的递归层级结构——每个节点的子节点和父节点结构完全一致,这种场景下定义一个递归实体类是最优解,不仅有类型安全,后续操作也方便。
首先注意到你给的JSON里有个小拼写错误:部分节点写的是paretnID(少了个e),正确的应该是parentID,我们可以用JsonProperty特性来统一映射,避免反序列化失败。
先定义实体类:
using Newtonsoft.Json; using System.Collections.Generic; public class UserNode { public int id { get; set; } public string name { get; set; } public bool hasChildren { get; set; } // 处理JSON里的拼写错误,把`paretnID`和`parentID`都映射到这个属性 [JsonProperty("parentID")] public int ParentId { get; set; } // 递归的子节点列表,初始化空列表避免空引用 public List<UserNode> children { get; set; } = new List<UserNode>(); }
然后反序列化代码就很简单了:
// 你的JSON字符串 string jsonString = @"{""id"": 1, ""name"": ""user1"", ""hasChildren"": true, ""parentID"": 0, ""children"": [ { ""id"": 2, ""name"": ""user2"", ""paretnID"": 1, ""hasChildren"": true, ""children"": [ { ""id"": 3, ""name"": ""user3"", ""parentID"": 2, ""hasChildren"": false, ""children"": [ ] }, { ""id"": 4, ""name"": ""user4"", ""parentID"": 2, ""hasChildren"": false, ""children"": [ ] } ] }, { ""id"": 5, ""name"": ""user5"", ""paretnID"": 1, ""hasChildren"": true, ""children"": [ { ""id"": 6, ""name"": ""user6"", ""parentID"": 5, ""hasChildren"": false, ""children"": [ ] } ] } ]}"; // 反序列化到根节点 UserNode rootUser = JsonConvert.DeserializeObject<UserNode>(jsonString); // 遍历打印所有节点名称的示例方法 void PrintNodes(UserNode node) { Console.WriteLine(node.name); foreach (var child in node.children) { PrintNodes(child); } } PrintNodes(rootUser);
方案二:动态/匿名类型反序列化(适合完全不确定结构的场景)
如果你的JSON结构完全不固定,不想定义实体类,可以用dynamic类型或者JObject来动态解析:
用dynamic快速访问
dynamic root = JsonConvert.DeserializeObject<dynamic>(jsonString); // 直接访问属性,注意要和JSON里的键拼写完全一致(比如部分节点是paretnID) Console.WriteLine($"根节点ID: {root.id}, 名称: {root.name}"); // 遍历子节点 foreach (var childNode in root.children) { Console.WriteLine($"子节点: {childNode.name}, 父ID: {childNode.paretnID}"); // 继续遍历孙节点 foreach (var grandChild in childNode.children) { Console.WriteLine($"孙节点: {grandChild.name}"); } }
用JObject做灵活查询
如果需要更复杂的动态操作,比如查询特定节点,用JObject结合LINQ会更强大:
using Newtonsoft.Json.Linq; using System.Linq; JObject rootObj = JObject.Parse(jsonString); // 查询所有hasChildren为false的节点名称 var leafNodes = rootObj.Descendants() .OfType<JObject>() .Where(o => (bool)o["hasChildren"] == false) .Select(o => o["name"].ToString()); foreach (var nodeName in leafNodes) { Console.WriteLine($"叶子节点: {nodeName}"); }
注意事项
- 用动态类型的时候一定要注意JSON里的属性拼写,比如你示例里的
paretnID,访问时必须和JSON里的键完全一致,否则会报错; - 强类型方案虽然需要定义类,但后续维护和类型检查更靠谱,优先推荐。
内容的提问来源于stack exchange,提问作者Sandeep Thomas
相关产品推荐
相关产品推荐

