如何使用json.net进行json的递归下降?
我试图使用json.net解析一个json文件。 该文件看起来像这样
{X: { Title:"foo", xxxx:xxxx } } {Y: {ZZ: {Title: "bar",...} } }
我试图通过Title属性递归处理所有对象的结构。 但我对JToken
, JProperty
, JContainer
, JValue
, JObject
感到困惑。 阅读源代码并没有让我更加明智,也没有任何样本有帮助。 我想要一些东西
WalkNode(node, Action action) { foreach(var child in node.Children) { Action(child); WalkNode(child); } } Parse() { WalkNode(root, n=> { if(n["Title"] != null) { ... } }); }
下面的代码应该非常接近您的要求。 我假设有一个外部数组,并且数组可以出现在层次结构中的任何位置。 (如果不是这样,您可以稍微简化WalkNode方法代码,但它应该以任何一种方式工作。)
using System; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace JsonRecursiveDescent { class Program { static void Main(string[] args) { string json = @"[ { ""X"": { ""Title"":""foo"", ""xxxx"":""xxxx"" } }, { ""Y"": { ""ZZ"": { ""Title"":""bar"", ""xxxx"":""xxxx"" } } } ]"; JToken node = JToken.Parse(json); WalkNode(node, n => { JToken token = n["Title"]; if (token != null && token.Type == JTokenType.String) { string title = token.Value(); Console.WriteLine(title); } }); } static void WalkNode(JToken node, Action action) { if (node.Type == JTokenType.Object) { action((JObject)node); foreach (JProperty child in node.Children()) { WalkNode(child.Value, action); } } else if (node.Type == JTokenType.Array) { foreach (JToken child in node.Children()) { WalkNode(child, action); } } } } }
我以为我会对@BrianRogers WalkNode方法进行一些小调整,使其更加通用:
private static void WalkNode(JToken node, Action objectAction = null, Action propertyAction = null) { if (node.Type == JTokenType.Object) { if (objectAction != null) objectAction((JObject) node); foreach (JProperty child in node.Children ()) { if (propertyAction != null) propertyAction(child); WalkNode(child.Value, objectAction, propertyAction); } } else if (node.Type == JTokenType.Array) { foreach (JToken child in node.Children()) { WalkNode(child, objectAction, propertyAction); } } }
然后OP可以做类似的事情:
WalkNode(json, null, prop => { if (prop.Name == "Title" && prop.Value.Type == JTokenType.String) { string title = prop.Value(); Console.WriteLine(title); } });
还需要做一些事情。 想提出我的解决方案。 它的优点是:
- 不是递归的
- 没有回调
- 不假设任何内部结构(数组)
-
将树遍历与需要执行的操作分离
IEnumerable
AllTokens(JObject obj) { var toSearch = new Stack (obj.Children()); while (toSearch.Count > 0) { var inspected = toSearch.Pop(); yield return inspected; foreach (var child in inspected) { toSearch.Push(child); } } } 然后你可以使用linq过滤和执行操作:
var tokens = AllTokens(jsonObj); var titles = tokens.Where(t => t.Type == JTokenType.Property && ((JProperty)t).Name == "Title");
试试这个方法我尝试了一些不成功后写的:
private void Traverse(JToken token, TreeNode tn) { if (token is JProperty) if (token.First is JValue) tn.Nodes.Add(((JProperty)token).Name + ": " + ((JProperty)token).Value); else tn = tn.Nodes.Add(((JProperty)token).Name); foreach (JToken token2 in token.Children()) Traverse(token2, tn); }
您首先必须传递完整的JSON文件,如下所示:
TreeNode rooty= tvu.Nodes.Add("Rooty") // not the Indian bread,just Rooty, Ok? JToken token = JToken.Parse(File.ReadAllText(<"Path to json file">)); Traverse(token, rooty);
完成,Bom你得到了这个:哦不,我不被允许嵌入图片。 伤心。