2012-06-11 13 views
6

Pracuję z zewnętrznym interfejsem API, który zwraca właściwość jako tablicę lub jako obiekt, w zależności od liczby. Jaki jest dobry sposób na radzenie sobie z tym?Analizowanie nieszablonowego obiektu JSON jako tablicy z Json.net

Wracając jako tablicy:

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

Wracając jako obiektu:

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

myślę obejście byłoby użyć niestandardowego Deserializator i zwraca tablicę długości 1 dla przypadku obiektu i domyślnej deserializacji dla przypadku tablicy, ale nie wiem jak to jeszcze zrobić.

Próbowałem deserializować obiekt do tablicy i mam nadzieję, że Json.net obsłuży tę sprawę dla mnie, ale nie będzie kostki.

Odpowiedz

3

Niestandardowy konwerter JSON.NET może w tym pomóc. To nie jest takie trudne.

Dla właściwości DateTime możesz zrobić to w następujący sposób. Wystarczy ozdobić właściwość, o której mowa, za pomocą niestandardowego konwertera.

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

JSON.NET zapewnia większą część instalacji hydraulicznej. Wystarczy wywnioskować z konwertera bazowego.

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

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

Wszystko, co musisz zrobić, to wdrożyć metody ReadJson (deserialization) i WriteJson (serialization).

można znaleźć pełny przykład tutaj:

Writing a custom Json.NET DateTime Converter

dla danego problemu trzeba trochę więcej kontroli. Spróbuj następujący typ konwertera:

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

Korzystanie niestandardową konwertera, jak ten powyżej można analizowania danych danych JSON siebie i komponować obiekt (-y) contact, jak należy.

zmodyfikowałem przykład mogę znaleźć tutaj:

JSON.NET Custom Converters–A Quick Tour

W tym przypadku trzeba zdać niestandardową konwertera gdy desearilizing.

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

Dzięki za dokładny wkład. Z twojego przykładu zrobiłem to działając i opublikowałem swój wynik końcowy. – angularsen

+0

Jeśli przydzielisz przynajmniej komentarz, dlaczego ... nie uderzaj i nie biegnij –

+0

Dzięki za link. :) –

5

podstawie Christophe Geers' answer, tutaj jest to, co skończyło się robi.

  1. Utwórz niestandardowy konwerter JSON, aby zawsze parsować JSON jako tablicę. Jeśli JSON jest obiektem nie będącym tablicą, wówczas przekształcić go w macierz i przekształcić w macierz.

  2. Zaznacz odpowiednie właściwości za pomocą niestandardowego atrybutu konwertera.

konwerter klienta

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

Struktury danych dla przykładu zapytania

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

UWAGA: Zamiast korzystać z CustomCreationConverter, można po prostu użyć zwykłego konwertera. Na przykład używam czegoś takiego:

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>); 
    } 
} 
Powiązane problemy