¿Cómo enumero a través de un JObject?

111

Estoy tratando de determinar cómo acceder a los datos que están en mi JObject y no puedo por mi vida determinar cómo usarlos.

JObject Object = (JObject)Response.Data["my_key"];

Puedo imprimirlo en la consola haciendo Console.WriteLine (Object) y veo los datos, se ve así:

{
 "my_data" : "more of my string data"
...
}

Pero NO tengo idea de cómo simplemente iterar / enumerar a través de él, ¿alguien tiene alguna idea? Estoy tan perdido en este momento.

Geesu
fuente

Respuestas:

167

Si miras la documentaciónJObject , verás que se implementa IEnumerable<KeyValuePair<string, JToken>>. Por lo tanto, puede iterar sobre él simplemente usando un foreach:

foreach (var x in obj)
{
    string name = x.Key;
    JToken value = x.Value;
    
}
svick
fuente
3
Esto es correcto, pero por razones que no entiendo, no puede usarlo con Linq a menos que lo envíe explícitamente al tipo enumerable. Es decir, usted en ((IEnumerable<KeyValuePair<string, JToken>>)obj).Select(...)lugar de simple-viejo obj.Select(...); o al menos eso es lo que encontré en una parte de mi código.
Adrian Ratnapala
2
@AdrianRatnapala ¿Su objeto se declara dinámico? Los métodos de extensión (como Enumerable.Select) no funcionan con eso.
svick
1
No, en mi caso objtenía tipo JObject; pero JObjectparece tener problemas similares a dynamic. El compilador no puede inferir los argumentos de tipo .Select. Puedo darlos explícitamente, obj.Select<KeyValuePair<string, JToken>, (result type)>(...)también funciona para mí
Adrian Ratnapala
3
@AdrianRatnapala Hmm, tienes razón. Es porque JObjectimplementa ambos IEnumerable<KeyValuePair<string, JToken>>y IEnumerable<JToken>(indirectamente a través JContainer).
svick
3
Ahora, ¿cómo lo uso para JSON anidado? Por ejemplo, si el "valor" contiene otro conjunto de pares clave: valor, ¿cómo puedo usar el JToken valuepara recorrer el siguiente conjunto de pares?
AlbatrossCafe
53

Los JObjects se pueden enumerar a través de objetos JProperty lanzándolos a un JToken :

foreach (JProperty x in (JToken)obj) { // if 'obj' is a JObject
    string name = x.Name;
    JToken value = x.Value;
}

Si tiene un JObject anidado dentro de otro JObject, no necesita lanzarlo porque el descriptor de acceso devolverá un JToken:

foreach (JProperty x in obj["otherObject"]) { // Where 'obj' and 'obj["otherObject"]' are both JObjects
    string name = x.Name;
    JToken value = x.Value;
}
Daniel
fuente
3
También se puede utilizar convenientemente LINQ, así: obj.Properties().Select(p => p.Name + ": " + p.Value).
itslittlejohn
Esta era exactamente la información que estaba buscando. Muchas gracias!
jhoepken
15

La respuesta no funcionó para mí. No sé cómo consiguió tantos votos. Aunque ayudó a señalarme en una dirección.

Esta es la respuesta que funcionó para mí:

foreach (var x in jobj)
{
    var key = ((JProperty) (x)).Name;
    var jvalue = ((JProperty)(x)).Value ;
}
jaxxbo
fuente
1
Con eso (después de esta línea: JObject priceComplianceJson = JObject.Parse (File.ReadAllText (fullPath));) obtengo, "No se puede convertir el tipo 'System.Collections.Generic.KeyValuePair <string, Newtonsoft.Json.Linq.JToken>' a 'Newtonsoft.Json.Linq.JProperty' "Sin embargo, la eliminación de la fundición funciona: var key = x.Key; var jvalue = x.Value; - al menos compila ... Revisaré la funcionalidad mañana.
B. Clay Shannon
3

Para personas como yo, adictos a linq , y según la respuesta de svick , aquí hay un enfoque de linq:

using System.Linq;
//...
//make it linq iterable. 
var obj_linq = Response.Cast<KeyValuePair<string, JToken>>();

Ahora puedes hacer expresiones linq como:

JToken x = obj_linq
          .Where( d => d.Key == "my_key")
          .Select(v => v)
          .FirstOrDefault()
          .Value;
string y = ((JValue)x).Value;

O solo:

var y = obj_linq
       .Where(d => d.Key == "my_key")
       .Select(v => ((JValue)v.Value).Value)
       .FirstOrDefault();

O este para iterar sobre todos los datos:

obj_linq.ToList().ForEach( x => { do stuff } ); 
dani herrera
fuente