2012-01-13 108 views
17

我有一個看起來像這樣的一些JSON數據:如何在C#中解析JSON對象,但事先不知道密鑰?

{ 
    "910719": { 
    "id": 910719, 
    "type": "asdf", 
    "ref_id": 7568 
    }, 
    "910721": { 
    "id": 910721, 
    "type": "asdf", 
    "ref_id": 7568 
    }, 
    "910723": { 
    "id": 910723, 
    "type": "asdf", 
    "ref_id": 7568 
    } 
} 

如何可以解析這種使用JSON.net?我可以首先這樣做:

JObject jFoo = JObject.Parse(data); 

我需要能夠遍歷此列表中的每個對象。我希望能夠做這樣的事情:

foreach (string ref_id in (string)jFoo["ref_id"]) {...} 

foreach (JToken t in jFoo.Descendants()) 
{ 
    Console.WriteLine((string)t["ref_id"]); 
} 

當然,這並不工作,但。如果您在編寫代碼時知道密鑰,所有示例都可以很好地工作。當你不知道密鑰時,它會崩潰。

+0

問題..你想Serialize的JSON對象或只是直分析出來的基礎上「ref_id」 – MethodMan 2012-01-13 18:40:49

+0

我想要一個ref_ids列表,所以我可以在另一個請求中使用它們。 – 2012-01-13 18:56:23

回答

21

這是可行的;這有效,但它不是優雅的。我確定有更好的方法。

var o = JObject.Parse(yourJsonString); 

foreach (JToken child in o.Children()) 
{ 
    foreach (JToken grandChild in child) 
    { 
     foreach (JToken grandGrandChild in grandChild) 
     { 
      var property = grandGrandChild as JProperty; 

      if (property != null) 
      { 
       Console.WriteLine(property.Name + ":" + property.Value); 
      } 
     } 
    } 
} 

打印:

id:910719 
type:asdf 
ref_id:7568 
id:910721 
type:asdf 
ref_id:7568 
id:910723 
type:asdf 
ref_id:7568
1

你有沒有考慮過使用JavascriptSerializer?

你可以嘗試做這樣的事情:

JavaScriptSerializer serializer = new JavaScriptSerializer(); 
var foo = serializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(data); 
foreach(var item in foo) 
{ 
    Console.Writeln(item.Value["ref_id"]); 
} 

http://msdn.microsoft.com/en-us/library/system.web.script.serialization.javascriptserializer.aspx

+0

我寧願不拔出JSON.net ...但我會如果沒有其他事情發生。 – 2012-01-13 18:59:09

+1

你可以在控制檯應用程序中使用javascriptserializer嗎?我無法添加對System.Web.Extensions的引用... – 2012-01-13 19:27:34

+1

是的,您可以,但您需要將其從客戶端配置文件應用程序轉換爲常見的.Net框架應用程序。請參閱 http://msdn.microsoft.com/en-us/library/cc656912.aspx#net_framework_4_client_profile_features 僅供參考 – Konstantin 2012-01-14 19:52:14

-1

康斯坦丁的解決方案將工作,但如果你想標識的列表做同樣的事情,而不是Console.Writeln()使用以下

List<string> list = new List<string>(); 
JavaScriptSerializer serializer = new JavaScriptSerializer(); 
var foo = serializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(data); 
foreach(var item in foo) 
{ 
    list.Add(item.Value["ref_id"]); 
} 
+0

那麼JSON.net的優點是什麼? – 2012-01-13 19:01:53

3

您可以在後代重複一個簡單的LINQ查詢是這樣的:

JObject jFoo = JObject.Parse(json); 

foreach (JObject obj in jFoo.Properties().Select(p => p.Value)) 
{ 
    Console.WriteLine("id: " + obj["id"]); 
    Console.WriteLine("ref_id: " + obj["ref_id"]); 
} 

同樣,如果你只想要ref_id值,就可以得到那些像這樣:

foreach (string refId in jFoo.Properties().Select(p => p.Value["ref_id"])) 
{ 
    Console.WriteLine(refId); 
} 
-2

我發現TrueWill的答案工作,但我想避免的foreach和嘗試得到一個簡單的for循環速度的緣故工作。我的結果當然可以稱得上是醜陋的。在這裏他們是在他們對任何人都有用的情況下。 (我留在了的WriteLine的能夠看到事情變得更簡單的緣故。)

請注意,這不會對一些JSON工作,不是完全通用。一些空的檢查可以做的更好,我使用等

 // NOW, DOING IT ALL AS A FOR LOOP... 
     // a, b, c, d - for iterator counters. 
     // j1, j2, j3, j4 - the JTokens to iterator over - each is a child of the previous 
     // p, q, r, s - The properties from j1/2/3/4. 

     JObject o = JObject.Parse(json); 
     JToken j1 = o.First; 
     for (int a = 0; a < o.Children().Count(); a++) { // Outermost loop gives us result, error, id. 
      if (j1 == null) 
       continue; 
      if (a > 0) { 
       j1 = j1.Next; 
       if (j1 == null) 
        continue; 
      } 
      var p = j1 as JProperty; 
      Console.WriteLine("FOR 0 = " + a.ToString() + " --- " + p.Name); 
      // DO STUFF HERE. 

      // FIRST INNER LOOP 
      // Set up a JToken or continue 
      JToken j2 = j1.Children().First() as JToken; 
      if (j1.Children().Count() > 0) { 
       j2 = j1.Children().First() as JToken; 
      } else { 
       continue; 
      } 
      Console.WriteLine("*** STARTING FIRST INNER..."); 
      for (int b = 0; b < j1.Children().Count(); b++) { // returns nothing as second loop above. 
       if (j2 == null) { 
        Console.WriteLine("*** j2 null 1..."); 
        continue; 
       } 
       if (b > 0) { 
        j2 = j2.Next; 
        if (j2 == null) { 
         Console.WriteLine("*** j2 null 2..."); 
         continue; 
        } 
       } 
       var q = j2 as JProperty; 
       // These null checks need to be != or ==, depending on what's needed. 
       if (q != null) { 
        Console.WriteLine("FOR 1 = " + a.ToString() + "," 
         + b.ToString() + " --- " + q.Name); 
        // DO STUFF HERE. 
        // ... 
       } // q !null check 

       // SECOND INNER LOOP 
       // Set up a JToken or continue 
       JToken j3; 
       if (j2.Children().Count() > 0) { 
        j3 = j2.Children().First() as JToken; 
       } else { 
        continue; 
       } 
       Console.WriteLine("****** STARTING SECOND INNER..."); 
       for (int c = 0; c < j2.Children().Count(); c++) { 
        if (j3 == null) 
         continue; 
        if (c > 0) { 
         j3 = j3.Next; 
         if (j3 == null) 
          continue; 
        } 
        var r = j3 as JProperty; 
        if (r == null) { 
         continue; 
        } // r null check 

        Console.WriteLine("FOR 2 = " 
         + a.ToString() + "," 
         + b.ToString() + "," 
         + c.ToString() + " --- " + r.Name); 
        // DO STUFF HERE. 

        // THIRD INNER LOOP 
        // Set up a JToken or continue 
        JToken j4; 
        if (j3.Children().Count() > 0) { 
         j4 = j3.Children().First() as JToken; 
        } else { 
         continue; 
        } 

        Console.WriteLine("********* STARTING THIRD INNER..."); 
        for (int d = 0; d < j3.Children().Count(); d++) { 
         if (j4 == null) 
          continue; 
         if (c > 0) { 
          j4 = j4.Next; 
          if (j4 == null) 
           continue; 
         } 
         var s = j4 as JProperty; 
         if (s == null) { 
          continue; 
         } // s null check 

         Console.WriteLine("FOR 3 = " 
          + a.ToString() + "," 
          + b.ToString() + "," 
          + c.ToString() + "," 
          + d.ToString() + " --- " + s.Name); 
         // DO STUFF HERE. 
         // ... 

        } // for d - j3 
       } // for c - j2 
      } // for b - j1 
     } // for a - original JObject 
+0

你的方式*顯着*更快?或者你在猜測? O.Children()。Count()假定獲取每次迭代的次數比實施者選擇的更快。這通常不是真實的,或者將來可能會改變。迭代器和封裝的重點在於你不應該知道或關心。例如,如果兒童是鏈接列表,則Next()非常快,Count可能非常緩慢。也爲(int我....)不會檢測集合是否已更改(從另一個線程),而迭代。 – 2017-04-10 16:32:39

3

Json.NET和我寫了一個快速的方法,你可以使用遞歸方法打印出所有的密鑰和相應的值。

 var o = JObject.Parse(YourJsonString); 
     getAllProperties(o); //call our recursive method 

然後你可以使用這個遞歸方法得到所有的屬性和它們的值

void getAllProperties(JToken children) 
    { 
     foreach (JToken child in children.Children()) 
     { 
      var property = child as JProperty; 
      if (property != null) 
      { 
       Console.WriteLine(property.Name + " " + property.Value);//print all of the values 
      } 
      getAllProperties(child); 
     } 
    } 
相關問題