You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:46:24