2013-04-24 32 views
7

Tôi đang cố gắng phân tích cú pháp tệp json bằng json.net. Tệp trông giống như thế nàyLàm thế nào để làm đệ quy gốc của json sử dụng json.net?

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

Tôi đang cố gắng xử lý lại cấu trúc này xử lý tất cả các đối tượng có thuộc tính Tiêu đề. Nhưng tôi bối rối về JToken, JProperty, JContainer, JValue, JObject. Đọc mã nguồn đã không để lại cho tôi nhiều khôn ngoan hơn và không có mẫu nào giúp ích. Tôi muốn một cái gì đó dọc theo các dòng của

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

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

Một số câu hỏi: Ví dụ trên không phải là JSON hợp lệ. Có phải các đối tượng chứa các thuộc tính X và Y được cho là nằm trong một mảng hay bạn có ý định cho X và Y nằm trong cùng một đối tượng chứa không? Ngoài ra, sẽ có mảng ở bất kỳ đâu trong cấu trúc phân cấp JSON mà bạn cần duyệt hay chỉ là các đối tượng và thuộc tính lồng nhau? –

Trả lời

13

Mã dưới đây phải khá gần với những gì bạn đang tìm kiếm. Tôi đã giả thiết rằng có một mảng bên ngoài và các mảng đó có thể xuất hiện ở bất kỳ đâu trong cấu trúc phân cấp. (Nếu đây là không đúng sự thật, bạn có thể đơn giản hóa các phương pháp mã WalkNode một chút, nhưng nó phải làm việc một trong hai cách.)

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

Nhưng nếu tôi không biết rằng "Tiêu đề" tồn tại và tôi muốn tất cả các thuộc tính? – rodolfoprado

+2

Đó là một câu hỏi khác. Nếu bạn muốn đăng câu hỏi mới mô tả những gì bạn đang cố gắng làm, tôi sẽ sẵn lòng trả lời câu hỏi đó. Hãy chắc chắn gắn thẻ nó 'json.net'. –

4

tôi nghĩ rằng tôi muốn bao gồm tinh chỉnh nhỏ của tôi để phương pháp @BrianRogers WalkNode, làm cho nó một chút linh hoạt hơn:

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); 
     } 
    } 
} 

sau đó OP có thể làm một cái gì đó như:

WalkNode(json, null, prop => 
{ 
    if (prop.Name == "Title" && prop.Value.Type == JTokenType.String) 
    { 
     string title = prop.Value<string>(); 
     Console.WriteLine(title); 
    } 
}); 
1

thử phương pháp này tôi đã viết nó sau khi một số cố gắng không thành công:

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); 
    } 

Trước tiên, bạn phải vượt qua nó các tệp JSON hoàn chỉnh như thế này:

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); 

Xong, Bom bạn có một này: Ồ không, tôi không được phép để nhúng hình ảnh. buồn.

1

Cũng cần thiết để thực hiện điều gì đó. Muốn đề xuất giải pháp của tôi. Nó có lợi thế là:

  • không phải là đệ quy
  • không callbacks
  • không thừa nhận bất kỳ cấu trúc nội bộ (mảng)
  • tách riêng cây traversal từ các hành động cần thiết để được thực thi

    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); 
         } 
        } 
    } 
    

    Sau đó, bạn có thể sử dụng LINQ để lọc và thực hiện hành động:

    var tokens = AllTokens(jsonObj); 
    var titles = tokens.Where(t => t.Type == JTokenType.Property && ((JProperty)t).Name == "Title");