2012-01-05 24 views
17

Estoy tratando de deserializar algunos datos JSON en objetos para una aplicación. Hasta ahora, ha estado bien porque las propiedades en los datos JSON eran estáticas (clave con un valor). Ahora tengo un resultado donde la clave es una pieza de datos dinámica.Deserialización de JSON utilizando JSon.NET con datos dinámicos

He aquí un ejemplo de JSON url:

http://en.wikipedia.org/w/api.php?action=query&format=json&pageids=6695&prop=info

El JSON resultante de esto es:

{ "query" : { "pages" : { "6695" : { "counter" : "", 
      "lastrevid" : 468683764, 
      "length" : 8899, 
      "ns" : 0, 
      "pageid" : 6695, 
      "title" : "Citadel", 
      "touched" : "2012-01-03T19:16:16Z" 
     } } } } 

bien, eso es genial, excepto que no puedo deserializar las "páginas" de datos en una objeto. Si tuviera que definir una clase para las páginas que tendría que tener este aspecto:

public class 6695 
{ 
    public string counter { get; set; } 
    public int lastrevid { get; set; } 
    public int length { get; set; } 
    public int ns { get; set; } 
    public int pageid { get; set; } 
    public string title { get; set; } 
    public string touched { get; set; } 
} 

Para deserialze el contenido (utilizando JsonConvert.Deserialize (jsondata)) y todos sabemos que no podemos tener una clase llamada 6695. No solo eso, el nombre de la clase debería ser diferente (por ejemplo, pageid = 7145 debería ser la clase 7145).

Parece que puedo sacar algunos valores si uso algo como JObject.Parse (contenido) y luego accedo a elementos como JArrays pero es bastante feo y sigo atascado tratando de sacar los datos de la matriz de páginas .

Buscando a alguien que lo ayude con esto. No creo que sea poco común, simplemente no son datos JSON con los que me he cruzado antes y no estoy seguro de cómo manejarlos.

Gracias!

¡PD se olvidó de mencionar que esto está en Windows Phone 7 por lo que "dinámico" no está disponible!

+0

¿No sería el 6695, simplemente ser nombre de propiedad, en lugar de un nombre de clase? Sigue siendo un problema, pero quizás pueda buscar y reemplazar la propiedad numérica en algún nombre fijo. No estoy seguro de cómo Json.NET maneja esto, pero quizás puedas intentar deserializarlo como un diccionario de un tipo de objeto específico. –

+0

Probablemente llegue un poco tarde a esta fiesta, pero newtonsoft lib tiene JObject para esto ... var obj = JObject.Parse (jsonString); básicamente trata los datos como un diccionario anidado complejo similar a cómo se comporta JavaScript en el navegador. Usted recupera una instancia de un "JObject" que le permite acceder a todo utilizando sintaxis de matriz, por ejemplo: var page = obj ["pages"] ["6695"] – War

Respuesta

18

Así es como se hace usando https://github.com/facebook-csharp-sdk/simple-json (https://nuget.org/packages/SimpleJson).

var text = "{\"query\":{\"pages\":{\"6695\":{\"pageid\":6695,\"ns\":0,\"title\":\"Citadel\",\"touched\":\"2012-01-03T19:16:16Z\",\"lastrevid\":468683764,\"counter\":\"\",\"length\":8899}}}}"; 

(Usando dinámico)

dynamic json = SimpleJson.DeserializeObject(text); 
string title = json.query.pages["6695"].title; 

foreach (KeyValuePair<string, dynamic> page in json.query.pages) 
{ 
    var id = page.Key; 
    var pageId = page.Value.pageid; 
    var ns = page.Value.ns; 
} 

(usando clases inflexible)

class result 
{ 
    public query query { get; set; } 
} 
class query 
{ 
    public IDictionary<string, page> pages { get; set; } 
} 
class page 
{ 
    public long pageid { get; set; } 
    public string title { get; set; } 
} 

var result = SimpleJson.DeserializeObject<result>(text); 

[Actualizar]

en el teléfono ventanas donde no se admite dinámico y se no quiero usar clases fuertemente tipadas

var json = (IDictionary<string, object>)SimpleJson.DeserializeObject(text); 
var query = (IDictionary<string, object>)json["query"]; 
var pages = (IDictionary<string, object>)query["pages"]; 
var pageKeys = pages.Keys; 
var page = (IDictionary<string, object>)pages["6695"]; 
var title = (string)page["title"]; 
+0

¡Genial! Esto funciona (Json.NET es lo mismo y puede usar clases muy tipadas, lo mismo que SimpleJson lo hace). Gracias. – Bil

+0

Acabo de toparme con este problema tratando de analizar los detalles del archivo Gist de GitHub. Muchas gracias por la respuesta aquí. ¡No pensé en usar IDictionary! –

28

El método más simple. En este caso particular, probablemente sería ir al dynamic.

dynamic data = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json); 
var lastRevId = data.query.pages["6695"].lastrevid; 

puede hacer referencia a cualquier elemento por su nombre [] para que pueda hacer algo como data["query"]["pages"]["6695"]["lastrevid"]. Esto se conseguirá con todos esos pequeños objetos donde el nombre no es válido en C#.

+2

Parece que esto es para wp7 que no admite dynamic :(I Dejaré esto aquí para cualquier otra persona que no esté restringida por C# 3 – Buildstarted

+0

Usted ** no necesita usar el método genérico **, simplemente puede ir como 'datos dinámicos = JsonConvert.DeserializeObject (json);' –

0

¿Qué tal una simple búsqueda y reemplazo en la cadena JSON? Si bien podría no ser la solución más elegante, posiblemente sería la más pragmática.

+0

Sí, alguien se le ocurrió eso en Twitter. Probablemente, funcione y no sea demasiado viscoso. – Bil

0

Tal vez usted podría utilizar un atributo reservado para contener el tipo de objeto, y luego utilizar el tipo de base como se muestra en este artículo: Dynamic types with JSON.NET

1

Usando Json.net sólo se puede hacer:

Dictionary<string,object> result = JsonConvert.DeserializeObject<Dictionary<string,object>>(json); 
foreach(var item in result) 
    Console.WriteLine(item.Key + " " + item.Value); 
1

Espero que el siguiente ejemplo ayude. Siempre diseño un modelo que coincida con el json. Es mucho mejor trabajar con el objeto cuando es el diseño de su propio modelo.

Es muy fácil generar el modelo C# del json. Yo uso este sitio web para generar el modelo: http://json2csharp.com

Un ejemplo completo es:

C# Código:

var targetsObject = Newtonsoft.Json.JsonConvert.DeserializeObject<YourModel>(jsonString); 

JSON:

{ 
     "investors": [ 
     { 
      "name": "06", 
      "programs": [ 
      { 
       "name": "Conventional", 
       "value": "3.5" 
      }, 
      { 
       "name": "FHA - Standard", 
       "value": "5.0" 
      }, 
      { 
       "name": "FHA - Streamline", 
       "value": "" 
      }, 
      { 
       "name": "VA", 
       "value": "5.5" 
      }, 
      { 
       "name": "VA IRRRL", 
       "value": "6.0" 
      }, 
      { 
       "name": "Non-Prime", 
       "value": "" 
      } 
      ] 
     }, 
     { 
      "name": "07", 
      "programs": [ 
      { 
       "name": "Conventional", 
       "value": "3.5" 
      }, 
      { 
       "name": "FHA - Standard", 
       "value": "5.0" 
      }, 
      { 
       "name": "FHA - Streamline", 
       "value": "7.0" 
      }, 
      { 
       "name": "VA", 
       "value": "5.5" 
      }, 
      { 
       "name": "VA IRRRL", 
       "value": "" 
      }, 
      { 
       "name": "Non-Prime", 
       "value": "" 
      } 
      ] 
     }, 
     { 
      "name": "08", 
      "programs": [ 
      { 
       "name": "Conventional", 
       "value": "3.5" 
      }, 
      { 
       "name": "FHA - Standard", 
       "value": "5.0" 
      }, 
      { 
       "name": "FHA - Streamline", 
       "value": "7.0" 
      }, 
      { 
       "name": "VA", 
       "value": "5.5" 
      }, 
      { 
       "name": "VA IRRRL", 
       "value": "" 
      }, 
      { 
       "name": "Non-Prime", 
       "value": "" 
      } 
      ] 
     }, 
     { 
      "name": "09", 
      "programs": [ 
      { 
       "name": "Conventional", 
       "value": "3.5" 
      }, 
      { 
       "name": "FHA - Standard", 
       "value": "5.0" 
      }, 
      { 
       "name": "FHA - Streamline", 
       "value": "" 
      }, 
      { 
       "name": "VA", 
       "value": "5.5" 
      }, 
      { 
       "name": "VA IRRRL", 
       "value": "" 
      }, 
      { 
       "name": "Non-Prime", 
       "value": "" 
      } 
      ] 
     }, 
     { 
      "name": "10", 
      "programs": [ 
      { 
       "name": "Conventional", 
       "value": "" 
      }, 
      { 
       "name": "FHA - Standard", 
       "value": "" 
      }, 
      { 
       "name": "FHA - Streamline", 
       "value": "" 
      }, 
      { 
       "name": "VA", 
       "value": "" 
      }, 
      { 
       "name": "VA IRRRL", 
       "value": "" 
      }, 
      { 
       "name": "Non-Prime", 
       "value": "2.0" 
      } 
      ] 
     }, 
     { 
      "name": "11", 
      "programs": [ 
      { 
       "name": "Conventional", 
       "value": "3.5" 
      }, 
      { 
       "name": "FHA - Standard", 
       "value": "5.0" 
      }, 
      { 
       "name": "FHA - Streamline", 
       "value": "" 
      }, 
      { 
       "name": "VA", 
       "value": "6.0" 
      }, 
      { 
       "name": "VA IRRRL", 
       "value": "6.0" 
      }, 
      { 
       "name": "Non-Prime", 
       "value": "" 
      } 
      ] 
     }, 
     { 
      "name": "12", 
      "programs": [ 
      { 
       "name": "Conventional", 
       "value": "3.5" 
      }, 
      { 
       "name": "FHA - Standard", 
       "value": "5.0" 
      }, 
      { 
       "name": "FHA - Streamline", 
       "value": "" 
      }, 
      { 
       "name": "VA", 
       "value": "5.5" 
      }, 
      { 
       "name": "VA IRRRL", 
       "value": "6.0" 
      }, 
      { 
       "name": "Non-Prime", 
       "value": "" 
      } 
      ] 
     }, 
     { 
      "name": "13", 
      "programs": [ 
      { 
       "name": "Conventional", 
       "value": "" 
      }, 
      { 
       "name": "FHA - Standard", 
       "value": "5.0" 
      }, 
      { 
       "name": "FHA - Streamline", 
       "value": "" 
      }, 
      { 
       "name": "VA", 
       "value": "" 
      }, 
      { 
       "name": "VA IRRRL", 
       "value": "" 
      }, 
      { 
       "name": "Non-Prime", 
       "value": "2.0" 
      } 
      ] 
     } 
     ] 
    } 

Modelo:

public class Program 
    { 
     public string name { get; set; } 
     public string value { get; set; } 
    } 

    public class Investor 
    { 
     public string name { get; set; } 
     public List<Program> programs { get; set; } 
    } 

    public class RootObject 
    { 
     public List<Investor> investors { get; set; } 
    } 
Cuestiones relacionadas