2013-04-24 65 views
7

我想解析使用json.net的json文件。該文件看起來像這樣如何使用json.net做json的遞歸下降?

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

我想這種結構處理的所有對象遞歸下降了Title屬性。但我很困惑JToken,JProperty,JContainer,JValue,JObject。閱讀源代碼並沒有讓我更聰明,也沒有任何示例有幫助。我想要的東西沿線

WalkNode(node, Action<Node> action) 
{ 
    foreach(var child in node.Children) 
    { 
     Action(child); 
     WalkNode(child); 
    } 
} 

Parse() 
{ 
    WalkNode(root, n=> 
    { 
     if(n["Title"] != null) 
     { 
      ... 
     } 
    }); 
} 
+1

有些問題:上面的例子是無效的JSON。屬性X和Y的包含對象是否應該位於數組中,還是您打算讓X和Y位於同一個包含對象中?另外,JSON層次結構中的任何位置都需要遍歷數組,還是僅嵌套對象和屬性? – 2013-04-25 05:49:53

回答

13

下面的代碼應該是非常接近你正在尋找。我假定有一個外部數組,並且該數組可以出現在層次結構中的任何位置。 (如果這是不正確的,可以簡化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<string>(); 
        Console.WriteLine(title); 
       } 
      }); 
     } 

     static void WalkNode(JToken node, Action<JObject> action) 
     { 
      if (node.Type == JTokenType.Object) 
      { 
       action((JObject)node); 

       foreach (JProperty child in node.Children<JProperty>()) 
       { 
        WalkNode(child.Value, action); 
       } 
      } 
      else if (node.Type == JTokenType.Array) 
      { 
       foreach (JToken child in node.Children()) 
       { 
        WalkNode(child, action); 
       } 
      } 
     } 

    } 
} 
+0

但是,如果我不知道「標題」存在,我想要所有的屬性? – rodolfoprado 2013-09-04 18:12:44

+2

這是一個不同的問題。如果你想發佈一個新問題來描述你想要做的事情,我會很樂意回答。一定要爲它標記'json.net'。 – 2013-09-04 19:59:27

4

我想我會包括我小的調整,@BrianRogers WalkNode方法,它也隨之輕微更靈活:

private static void WalkNode(JToken node, 
           Action<JObject> objectAction = null, 
           Action<JProperty> propertyAction = null) 
{ 
    if (node.Type == JTokenType.Object) 
    { 
     if (objectAction != null) objectAction((JObject) node); 

     foreach (JProperty child in node.Children<JProperty>()) 
     { 
      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<string>(); 
     Console.WriteLine(title); 
    } 
}); 
1

試試這個方法我有些不成功的嘗試後寫它:

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你有這樣一句: 哦,不,我不能嵌入圖片。傷心。

1

還需要做些什麼。 想提出我的解決方案。它具有的優點是:

  • 不是遞歸
  • 沒有callbacks
  • 不得新任任何的內部結構(陣列)
  • from需要被執行

    IEnumerable<JToken> AllTokens(JObject obj) { 
        var toSearch = new Stack<JToken>(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");