如何用Newtonsoft.Json提取含指定键的JSON子树及所有父节点?
实现JToken中按关键字提取含目标键及父节点的子JSON
完全可以实现这个需求,核心思路是先定位所有包含目标键的节点,再回溯保留它们的父节点路径,最后根据这些路径构建出过滤后的JSON结构。
具体实现步骤
- 遍历JToken收集目标键的完整路径:递归遍历整个JToken结构,记录每个目标键从根节点到自身的层级路径。
- 根据路径构建结果JSON:按照收集到的路径,逐个将路径上的节点复制到结果对象中,只保留能关联到目标键的分支。
C#代码示例
1. 收集所有目标键的路径
private static List<List<string>> FindAllPaths(JToken root, string targetKey) { var paths = new List<List<string>>(); Traverse(root, new List<string>(), targetKey, paths); return paths; } private static void Traverse(JToken token, List<string> currentPath, string targetKey, List<List<string>> paths) { if (token is JObject obj) { foreach (var prop in obj.Properties()) { var newPath = new List<string>(currentPath) { prop.Name }; if (prop.Name == targetKey) { paths.Add(newPath); } Traverse(prop.Value, newPath, targetKey, paths); } } // 如需处理数组,可添加JArray的遍历逻辑 else if (token is JArray array) { for (int i = 0; i < array.Count; i++) { var newPath = new List<string>(currentPath) { $"[{i}]" }; Traverse(array[i], newPath, targetKey, paths); } } }
2. 根据路径构建结果对象
private static JToken BuildResultFromPaths(JToken root, List<List<string>> paths) { var result = new JObject(); foreach (var path in paths) { JToken currentOriginal = root; JToken currentResult = result; for (int i = 0; i < path.Count; i++) { var key = path[i]; if (currentOriginal is JObject originalObj) { var prop = originalObj.Property(key); if (prop == null) continue; if (currentResult is JObject resultObj) { if (!resultObj.ContainsKey(key)) { // 最后一层是目标键,直接复制属性;否则创建空容器继续深入 if (i == path.Count - 1) { resultObj.Add(prop.Name, prop.Value.DeepClone()); } else { var newContainer = new JObject(); resultObj.Add(prop.Name, newContainer); currentResult = newContainer; } } else { // 父节点已存在,直接进入下一层 currentResult = resultObj[key]; } } currentOriginal = prop.Value; } // 如需处理数组,可添加对应逻辑 } } return result; }
3. 使用示例
// 解析原JSON为JToken var originalJson = @" { ""Name"": ""Torr"", ""Attr1"": { ""A"": 1, ""Attr1_1"": { ""A"": 1 }, ""Attr1_2"" :{ ""B"": 1 } }, ""A"": 2 }"; var root = JToken.Parse(originalJson); // 搜索目标键"A" var targetKey = "A"; var paths = FindAllPaths(root, targetKey); var filteredResult = BuildResultFromPaths(root, paths); // 输出格式化后的结果 Console.WriteLine(filteredResult.ToString(Newtonsoft.Json.Formatting.Indented));
代码说明
- 递归遍历能覆盖所有嵌套层级,确保不会遗漏任何目标键的位置
- 使用
DeepClone()避免修改原JToken对象,保证数据独立性 - 可以扩展JArray的处理逻辑,适配包含数组的JSON结构
内容的提问来源于stack exchange,提问作者Harxish
相关产品推荐
相关产品推荐

