2012-01-13 12 views
17

tengo algunos datos JSON que tiene este aspecto:¿Cómo analizo un objeto JSON en C# cuando no sé la clave por adelantado?

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

¿Cómo puedo analizar esta usando JSON.net? Primero puedo hacer esto:

JObject jFoo = JObject.Parse(data); 

Necesito poder iterar sobre cada objeto en esta lista. Me gustaría ser capaz de hacer algo como esto:

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

o

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

pero por supuesto que no funciona. Todos los ejemplos funcionan bien si conoce la clave mientras escribe su código. Se descompone cuando no conoce la clave por adelantado.

+0

pregunta ..¿Quieres Serialzie el objeto JSON o simplemente Parse out basado en "ref_id" – MethodMan

+0

Quiero una lista de los ref_ids para que pueda usarlos en otra solicitud. –

Respuesta

21

Es factible; esto funciona pero no es elegante. Estoy seguro de que hay una mejor manera.

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

Lienzo:

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

¿Ha considerado usar JavascriptSerializer?

podría intentar hacer algo como esto:

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

prefiero no sacar JSON.net ... pero lo haré si no encuentra nada más. –

+1

¿puedes usar javascriptserializer en una aplicación de consola? Tengo dificultades para agregar una referencia a System.Web.Extensions ... –

+1

Sí, puede hacerlo, aunque deberá convertirlo de la aplicación Client Profile a la aplicación .Net framework común. Ver http://msdn.microsoft.com/en-us/library/cc656912.aspx#net_framework_4_client_profile_features como referencia – Konstantin

-1

solución de Konstantin funcionará, pero si quieres una lista de Id de hacer lo mismo y en lugar de la Console.Writeln() utilizan el siguiente

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

¿para qué sirve JSON.net? –

3

Puede iterar sobre la descendencia con una simple consulta LINQ como esto:

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

Del mismo modo, si desea sólo los ref_id valores, se puede obtener aquellos como este:

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

Descubrí que la respuesta de TrueWill funcionaba, pero quería evitar el foreach y tratar de hacer que un bucle simple funcionara por el bien de la velocidad. Mis resultados fueron ciertamente lo que podría describirse como feo en el mejor de los casos. Aquí están en caso de que sean útiles para cualquier persona. (Me he quedado en WriteLine para poder ver las cosas un poco más fácil).

Tenga en cuenta que esto no funcionará para algunos JSON y no es perfectamente genérico. Algunos de los cheques nulos se podría hacer mejor, etc.

 // 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

¿Es usted mucho * significativamente * más rápido? o estas adivinando? o.Children(). Count() asume que obtener el conteo para cada iteración es más rápido que lo que elija el implementador. Esto a menudo no es cierto o puede cambiar en el futuro. El objetivo de los iteradores y la encapsulación es que no debes saber ni preocuparte. Por ejemplo, si Children es una lista vinculada, Next() es muy rápido y Count puede ser muy lento. También para (int i ....) no detecta si las colecciones han cambiado (desde otro hilo) durante la iteración. –

3

estoy usando Json.NET y yo escribimos una manera rápida donde se puede imprimir todas las claves y los valores correspondientes utilizando un método recursivo.

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

continuación, puede utilizar este método recursivo para obtener todas las propiedades y sus valores

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