如何使用json.net进行json的递归下降?

我试图使用json.net解析一个json文件。 该文件看起来像这样

{X: { Title:"foo", xxxx:xxxx } } {Y: {ZZ: {Title: "bar",...} } } 

我试图通过Title属性递归处理所有对象的结构。 但我对JTokenJPropertyJContainerJValueJObject感到困惑。 阅读源代码并没有让我更加明智,也没有任何样本有帮助。 我想要一些东西

 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你得到了这个:哦不,我不被允许嵌入图片。 伤心。