2012-04-12 10 views
15

Mam sytuację, w której JSON zwrócony z usługi REST -service wyświetla listę obiektów Movie-object, wszystkie wyszczególnione z dużą ilością informacji. Kilka pól w tym wyniku usługi zmienia się w zależności od dostępnych informacji.JSON.net - pole jest ciągiem lub Listą <string>

Przykład: Film zawsze zawiera zrzuty ekranu (zdjęcia), aktorów i reżyserów. W zależności od danego filmu może istnieć jeden lub więcej obrazów, jeden lub więcej aktorów i jeden lub więcej reżyserów. JSON próbki dla kilku przypadków:

{ 
    "title": "Movie title", 
    "images": [ 
     "http://www.url.com/img_0.jpg", 
     "http://www.url.com/img_1.jpg", 
     "http://www.url.com/img_2.jpg", 
     "http://www.url.com/img_3.jpg", 
     "http://www.url.com/img_4.jpg" 
    ], 
    "actors": [ 
     "Steven Berkoff", 
     "Nikolaj Coster-Waldau", 
     "Julie Cox" 
    ], 
    "directors": "Simon Aeby" 
}, 
{ 
    "title": "Another movie", 
    "images": "http://www.url.com/img_1.jpg", 
    "actors": "actor 1" 
    "directors": [ 
     "Justin Bieber", 
     "Justin Timberlake" 
    ] 
} 

Chodzi o to, używając Json.NET, w jaki sposób można stworzyć konwertera, który zajmuje się tym problemem? Przeszukuję internet, ale wciąż nie znalazłem rozwiązania.

Kolejny spin na to samo pytanie: Jeśli pole jest listą ciągów lub prostym łańcuchem, w jaki sposób utworzyć JSON.NET utworzyć listę w dowolny sposób (a jeśli tylko prosty ciąg, utwórz listę z jednym członek)

EDIT: Ta usługa REST jest poza moją kontrolą

+0

jest to usługa lub osoba trzecia? Proponuję edytować usługę, jeśli to możliwe. ponieważ nie można serializować fileld do tablicy, jeśli nie jest to tablica w jsonie. – maxlego

+0

lub możesz dokonać deserializacji do obiektu, a następnie zmapować je do swoich klas. – jjchiw

+0

Zaktualizowano ogólną wiadomość, aby było wyraźniej. –

Odpowiedz

7

Ok, zrobiłem to dla zabawy, ale nie sądzę, jest użyteczna lub najlepszym sposobem, tak ...

Deklarowanie „dynamiczne” atrybuty obiektu, a następnie utworzyć metody w celu uzyskania właściwości jako coś jak ImagesAsList lub ImagesAsString. Zrobiłem to z rozszerzeniem metody .....

var movies = JsonConvert.DeserializeObject<List<Movie>>(str); 

Klasa

class Movie 
{ 

    [JsonProperty("title")] 
    public string Title { get; set; } 

    [JsonProperty("images")] 
    public object Images { get; set; } 

    [JsonProperty("actors")] 
    public object Actor { get; set; } 

    [JsonProperty("directors")] 
    public object Directors { get; set; } 
} 

Extension Methods

static class MovieExtension 
{ 
    public static List<string> ImagesAsList(this Movie m) 
    { 
     var jArray = (m.Images as JArray); 
     if (jArray == null) return null; 

     return jArray.Select(x => x.ToString()).ToList(); 
    } 

    public static string ImagesAsString(this Movie m) 
    { 
     return m.Images as string; 
    } 

} 

EDIT

Po przeczytaniu @yamen komentarze zrobiłem kilka zmian, takich jak:

var settings = new JsonSerializerSettings(); 
settings.Converters.Add(new MoviesConverter()); 

var movies = JsonConvert.DeserializeObject<List<Movie>>(str, settings); 

klasy

class Movie 
{ 

    [JsonProperty("title")] 
    public List<string> Title { get; set; } 

    [JsonProperty("images")] 
    public List<string> Images { get; set; } 

    [JsonProperty("actors")] 
    public List<string> Actor { get; set; } 

    [JsonProperty("directors")] 
    public List<string> Directors { get; set; } 
} 

Converter

class MoviesConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(string)) || (objectType == typeof(List<string>)) ; 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.StartArray) 
     { 
      var l = new List<string>(); 
      reader.Read(); 
      while (reader.TokenType != JsonToken.EndArray) 
      { 
       l.Add(reader.Value as string); 

       reader.Read(); 
      } 
      return l; 
     } 
     else 
     { 
      return new List<string> { reader.Value as string }; 
     } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     //ToDo here we can decide to write the json as 
     //if only has one attribute output as string if it has more output as list 
    } 
} 
+0

Nie sądzę, że istnieje potrzeba zadeklarowania jako obiektu. Deklaruj zawsze jako List (lub Listę ) i po prostu zwracaj pojedynczy element, gdy bazowy JSON nie jest tablicą. Tak powinien zachowywać się interfejs API, dlatego też kodowanie systemu w ten sposób ma również wpływ na przyszłość. Dodatkową premią jest posiadanie wyraźnej warstwy odwzorowania. – yamen

+0

OK, wprowadzono pewne zmiany i przedłużono klasę JsonCovert – jjchiw

+0

Ta odpowiedź powinna być bardzo korzystna dla bieżącej wybranej odpowiedzi przez yamen. Dobrze korzysta z konwerterów JSON.NET i wszelkie ogólne przetwarzanie będzie działało tak długo, jak długo będziesz ozdabiać swoje obiekty :) +1 –

3

nie będą mogli serialise bezpośrednio do obiektu, ale można to zrobić ręcznie, bez zbytniego wysiłku. JSON.Net zawiera LINQ do JSON. Najpierw określić sposób, że zawsze zwraca listę typu T, nawet jeśli określone JSON jest macierz: Wykorzystanie

public List<T> getSingleOrArray<T>(JToken token) 
{ 
    if (token.HasValues) 
    { 
     return token.Select(m => m.ToObject<T>()).ToList(); 
    } 
    else 
    { 
     return new List<T> { token.ToObject<T>() }; 
    } 
} 

próbki:

JObject m1 = JObject.Parse(@"{ 
""title"": ""Movie title"", 
""images"": [ 
    ""http://www.url.com/img_0.jpg"", 
    ""http://www.url.com/img_1.jpg"" 
], 
""actors"": [ 
    ""Steven Berkoff"", 
    ""Julie Cox"" 
], 
""directors"": ""Simon Aeby"" 
}"); 

JObject m2 = JObject.Parse(@"{ 
""title"": ""Another movie"", 
""images"": ""http://www.url.com/img_1.jpg"", 
""actors"": ""actor 1"", 
""directors"": [ 
    ""Justin Bieber"", 
    ""Justin Timberlake"" 
] 
}"); 

IList<String> m1_directors = getSingleOrArray<string>(m1["directors"]); 
IList<String> m2_directors = getSingleOrArray<string>(m2["directors"]); 

m1_directory jest listą z jednego elementu m2_directors to lista z dwoma elementami.

Powiązane problemy