2012-06-11 30 views
6

Estoy trabajando con una API externa que devuelve una propiedad como matriz o como objeto, según el recuento. ¿Cuál es una buena manera de manejar esto?Analizar objeto JSON no de matriz como matriz con Json.net

Volviendo como matriz:

{ 
    "contacts": { 
     "address": [ 
      { 
       "id": "47602070", 
       "type": "Work", 
       "street": "MyStreet", 
       "city": "MyCity", 
       "zip": "12345", 
       "country": "USA" 
      }, 
      { 
       "id": "47732816", 
       "type": "GPS", 
       "street": "50.0,30.0" 
      } 
     ] 
    } 
} 

Volviendo como objeto:

{ 
    "contacts": { 
     "address": { 
      "id": "47602070", 
      "type": "Work", 
      "street": "MyStreet", 
      "city": "MyCity", 
      "zip": "12345", 
      "country": "USA" 
     } 
    } 
} 

Estoy pensando en una solución alternativa sería utilizar un deserializer costumbre y devolver una matriz de longitud 1 para el caso del objeto y la deserialización predeterminada para el caso de la matriz, pero todavía no sé cómo hacerlo.

Intenté deserializar el objeto a una matriz y esperando que Json.net manejara este caso para mí, pero no dados.

Respuesta

3

Un convertidor JSON.NET personalizado podría hacer el truco aquí. No es tan dificil.

Para una propiedad DateTime, puede hacerlo de la siguiente manera. Simplemente decore la propiedad en cuestión con el convertidor personalizado.

[JsonObject(MemberSerialization.OptIn)] 
public class MyClass 
{ 
    [JsonProperty(PropertyName = "creation_date")] 
    [JsonConverter(typeof(UnixDateTimeConverter))] 
    public DateTime CreationDate { get; set; } 
} 

JSON.NET proporciona la mayoría de las cañerías. Solo deriva de un convertidor base.

public class UnixDateTimeConverter : DateTimeConverterBase 
{ 
    public override void WriteJson(JsonWriter writer, object value, 
            JsonSerializer serializer) 
    { ...} 

    public override void WriteJson(JsonWriter writer, object value, 
            JsonSerializer serializer) 
    { ... } 
} 

Todo lo que tiene que hacer es poner en práctica el ReadJson (deserialización) y WriteJson métodos (serialización).

se puede encontrar un ejemplo completo aquí:

Writing a custom Json.NET DateTime Converter

para su problema particular que necesita un poco más de control. Pruebe el siguiente tipo de convertidor:

public class Contact 
{ 
    private List<Address> _addresses = new List<Address>();  
    public IEnumerable<Address> Addresses { get { return _addresses; } 
} 

public class ContactConverter : CustomCreationConverter<Contact> 
{ 
    public override Contact Create(Type objectType) 
    { 
     return new Contact(); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object 
     existingValue, JsonSerializer serializer) 
    { 
     var mappedObj = new Contact(); 

     // Parse JSON data here 
     // ... 

     return mappedObj; 
    } 
} 

El uso de un convertidor de costumbre como la de arriba se puede analizar los datos JSON a sí mismo y componer el objeto (s) de contacto cuando lo desee.

he modificado un ejemplo que encontré aquí:

JSON.NET Custom Converters–A Quick Tour

En este caso se necesita pasar el convertidor personalizado cuando desearilizing.

Contact contact = 
    JsonConvert.DeserializeObject<Contact>(json, new ContactConverter()); 
+0

Gracias por la entrada completa. De su ejemplo, lo tengo funcionando y publicado mi resultado final. – angularsen

+0

Si rechazas al menos comentar por qué ... no aciertes y corras –

+0

Gracias por el enlace. :) –

5

Sobre la base de Christophe Geers answer, esto es lo que terminé haciendo.

  1. Cree un convertidor JSON personalizado para analizar siempre el JSON como una matriz. Si el JSON es un objeto que no es de matriz, deserialice el objeto y envuélvalo en una matriz.

  2. Marque las propiedades correspondientes con un atributo de convertidor personalizado.

convertidor personalizado

public class JsonToArrayConverter<T> : CustomCreationConverter<T[]> 
{ 
    public override T[] Create(Type objectType) 
    { 
     // Default value is an empty array. 
     return new T[0]; 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object 
     existingValue, JsonSerializer serializer) 
    { 

     if (reader.TokenType == JsonToken.StartArray) 
     { 
      // JSON object was an array, so just deserialize it as usual. 
      object result = serializer.Deserialize(reader, objectType); 
      return result; 
     } 
     else 
     { 
      // JSON object was not an arry, so deserialize the object 
      // and wrap it in an array. 
      var resultObject = serializer.Deserialize<T>(reader); 
      return new T[] {resultObject}; 
     } 
    } 
} 

Las estructuras de datos para el ejemplo de pregunta

public class Organisation 
{ 
    public Contacts contacts; 
} 

public class Address 
{ 
    public string id; 
    public string street; 
    public string city; 
    public string type; 
    public string zip; 
    public string country; 
} 

public class Contacts 
{ 
    // Tell JSON.net to use the custom converter for this property. 
    [JsonConverter(typeof(JsonToArrayConverter<Address>))] 
    public Address[] address; 
} 
1

Nota: En lugar de utilizar un CustomCreationConverter, sólo puede utilizar un convertidor de corriente. Por ejemplo, uso algo como esto:

public class SingleToArrayConverter<T> : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var items = (IEnumerable<T>)value; 
     if (value == null || !items.Any()) 
     { 
      writer.WriteNull(); 
     } 
     else if (items.Count() == 1) 
     { 
      serializer.Serialize(writer, items.ElementAt(0)); 
     } 
     else 
     { 
      serializer.Serialize(writer, items); 
     } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (!CanConvert(objectType)) 
     { 
      throw new NotSupportedException(); 
     } 

     if (reader.TokenType == JsonToken.Null) 
     { 
      reader.Skip(); 
      return null; 
     } 
     else if (reader.TokenType == JsonToken.StartObject) 
     { 
      return new T[] { serializer.Deserialize<T>(reader) }; 
     } 
     else 
     { 
      return serializer.Deserialize<T[]>(reader); 
     } 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(IEnumerable<T>); 
    } 
} 
Cuestiones relacionadas