3

It seems to be very simple, but I just can't figure out how to do it. I use an external api to get JSON results (using Newtonsoft.JSON), problem is a poor design which leaves me with a array with mixed types like this:

{"data":["Monday 13 january", {"id":"1234aa","name":"teamA"},{"id":"1234bb","name":"teamB"}, "Tuesday 14 january", {"id":"1234aa","name":"teamA"}]}

This will result in an object like:

public class RootObject
{
  public List<object> data { get; set; }
}

I want to ignore those date strings and deserialize the objects into a typed array

public class RootObject
{
   public List<Team> data { get; set; }
}

Any idea's how to achieve this kind of behavior?

Update: Maybe I wasn't clear about it, but I'm not looking for a solution which does soms transformation after the deserialization. I want some integrated solution, eg with a JsonConverter.

Tom Kuijsten
  • 337
  • 4
  • 16

2 Answers2

4

This is possible to do with a custom JsonConverter.

Assuming that you have your classes set up like this:

public class RootObject
{
    [JsonProperty("data")]
    [JsonConverter(typeof(TeamListConverter))]
    public List<Team> Teams { get; set; }
}

public class Team
{
    [JsonProperty("id")]
    public string Id { get; set; }
    [JsonProperty("name")]
    public string Name { get; set; }
}

Then you can use this JsonConverter to handle the deserialization of the JSON array. This will ignore all the plain strings (dates) in the array and only try to deserialize the objects.

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JArray array = JArray.Load(reader);
        List<Team> teams = new List<Team>();
        foreach (JToken token in array.Children())
        {
            if (token.Type == JTokenType.Object)
            {
                teams.Add(token.ToObject<Team>());
            }
        }
        return teams;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Here is demo program:

public class Program
{
    public static void Main(string[] args)
    {
        string json = @"
        {
            ""data"":
            [
                ""Monday 13 january"",
                {
                    ""id"":""1234aa"",
                    ""name"":""teamA""
                },
                {
                    ""id"":""1234bb"",
                    ""name"":""teamB""
                }, 
                ""Tuesday 14 january"", 
                {
                    ""id"":""1234aa"",
                    ""name"":""teamA""
                }
            ]
        }";

        RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);

        foreach (Team t in obj.Teams)
        {
            Console.WriteLine(t.Id + " - " + t.Name);
        }
    }
}

And here is the output:

1234aa - teamA
1234bb - teamB
1234aa - teamA

Is this what you are looking for?

Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
  • That's exactly what I'm looking for, thanks! I figured something like that out yesterday evenening, but I used 2 converters. Yours looks better and cleaner. I give it a shot tonight, and mark it if it works. Thanks! – Tom Kuijsten Nov 01 '13 at 09:40
0

When you are serializing an Object that time you can configure which property to ignore, if are willing to do so. If you have done that way then you have to iterate the list List<Object> data to find Team Object and put them in separate list.

Madhusudan Joshi
  • 4,438
  • 3
  • 26
  • 42
  • I don't follow, my question is not about a property but about ignoring an array item. Please add some sample code to see if your solution helps. – Tom Kuijsten Oct 31 '13 at 10:42