Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing JSON with numbers as keys

EDIT: I figured out how to get each key, now the problem is looping through each collection. Solution at bottom!

I'm trying to parse a JSON payload that has the following format:

{
    "version": "1.1", 
    "0": {
              "artist": "Artist 1",
              "title": "Title 1"
         },
    "1": {
              "artist": "Artist 2",
              "title": "Title 2"
         },
    ...
    "29": {
              "artist": "Artist 30",
              "title": "Title 30"
         }
}

I don't need the version key, so I'm ignoring it while coding my classes. This is what I have so far:

public class Song
{
    public string artist { get; set; }
    public string title { get; set; }
}

I've checked around StackOverflow and I've seen people using Dictionary<int, string> for similar problems, but it doesn't look like people have each JSON object in the root. I'm using JSON.net to parse everything.

In PHP, I could easily use json_decode() and walk through the array and extract all the info I need, but I'm stumped by C#.

EDIT: Solution begins below.

I looked at the JSON.net documentation and they used dictionaries, so I tried using nested dictionaries, and it seems to work!

Dictionary<int, Dictionary<string, string>> song = JsonConvert.DeserializeObject<Dictionary<int, Dictionary<string, string>>>(json);

And I can access the artist and title properties via:

song[0]["artist"]
song[0]["title"]

respectively.

This eliminates the need for pre-built classes. Now I'm having trouble looping through each set of data collection (e.g. artist and title info for song[1], song[2], song[3], ..., song[n]).

like image 769
lmike215 Avatar asked Nov 21 '13 01:11

lmike215


1 Answers

If you try to deserialize into a Dictionary<int, Dictionary<string, string>> with the above JSON you're going to run into problems with the version key because it does not fit the data format for the dictionaries (version is not an int, and 1.1 is not a Dictionary<string, string>). I know you said you're "ignoring it for now", but that implies that it will be there in the future, so you need to handle it.

If you don't want to have pre-defined classes, then you're better off using Json.Net's LINQ-to-JSON API to work with the data. Here is how you can get the data you want using this approach:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        {
            ""version"": ""1.1"", 
            ""0"": {
                      ""artist"": ""Artist 1"",
                      ""title"": ""Title 1""
                 },
            ""1"": {
                      ""artist"": ""Artist 2"",
                      ""title"": ""Title 2""
                 },
            ""29"": {
                      ""artist"": ""Artist 30"",
                      ""title"": ""Title 30""
                 }
        }";

        JObject songs = JObject.Parse(json);

        foreach (JProperty song in songs.Properties())
        {
            if (song.Name == "version") continue;  // skip "version" property
            Console.WriteLine("Song " + song.Name + " artist: " + song.Value["artist"]);
            Console.WriteLine("Song " + song.Name + " title: " + song.Value["title"]);
        }
    }
}

Output:

Song 0 artist: Artist 1
Song 0 title: Title 1
Song 1 artist: Artist 2
Song 1 title: Title 2
Song 29 artist: Artist 30
Song 29 title: Title 30

There are many other samples to be found in the documentation.

like image 162
Brian Rogers Avatar answered Nov 07 '22 14:11

Brian Rogers