21

I'm using JSON.NET to parse a JSON reponse from openexhangerates.org server side using .NET. The response contains a nested object ("rates") which has a long list of numeric properties:

    {
    "disclaimer": "Exchange rates provided for informational purposes only, with no guarantee whatsoever of accuracy, validity, availability, or fitness for any purpose; use at your own risk. Other than that, have fun! Usage subject to acceptance of terms: http://openexchangerates.org/terms/",
    "license": "Data sourced from various providers with public-facing APIs; copyright may apply; not for resale; no warranties given. Usage subject to acceptance of license agreement: http://openexchangerates.org/license/",
        "timestamp": 1357268408,
        "base": "USD",
        "rates": {
            "AED": 3.673033,
            "AFN": 51.5663,
            "ALL": 106.813749,
            "AMD": 403.579996,
            etc...
        }
    }

The property names correspond to the currency type (e.g. "USD"). I need to assume that the list of properties can change over time, so I want to convert the object into a Dictionary instead of a corresponding C# object.

So instead of deserializing the JSON object into something like this:

class Rates
{
public decimal AED; // United Arab Emirates Dirham
public decimal AFN; // Afghan Afghani
public decimal ALL; // Albanian Lek
public decimal AMD; // Armenian Dram
// etc...
}

I want to end up with this:

Dictionary<string,decimal>() {{"AED",0.2828},{"AFN",0.3373},{"ALL",2.2823},{"AMD",33.378} // etc...};

How do I do this starting from either the response string or from the JObject produced by calling JObject.Parse(responseString)?

Emmanuel
  • 3,475
  • 6
  • 29
  • 45
  • 1
    have you looked at google search results on how to deserialize JSON using C# there are lots of examples on the internet.. http://stackoverflow.com/questions/6375122/how-to-parse-json-response-into-dictionary – MethodMan Jan 04 '13 at 17:14

3 Answers3

31

JObject already implements IDictionary<string, JToken>, so I suspect that when you've navigated down to the rates member, you should be able to use:

var result = rates.ToDictionary(pair => pair.Key, pair => (decimal) pair.Value);

Unfortunately it uses explicit interface implementation, which makes this a bit of a pain - but if you go via the IDictionary<string, JToken> interface, it's fine.

Here's a short but complete example which appears to work with the JSON you've provided (saved into a test.json file):

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;

class Test
{
    static void Main()
    {
        JObject parsed = JObject.Parse(File.ReadAllText("test.json"));
        IDictionary<string, JToken> rates = (JObject) parsed["rates"];
        // Explicit typing just for "proof" here
        Dictionary<string, decimal> dictionary =
            rates.ToDictionary(pair => pair.Key,
                               pair => (decimal) pair.Value);
        Console.WriteLine(dictionary["ALL"]);
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • And how do I 'navigate' to "rates"? When I try using jo["rates"], get a JToken back - not a JObject. – Emmanuel Jan 04 '13 at 17:19
  • 1
    @Canoehead: You need to cast to `JObject`. See my edit for a full example. – Jon Skeet Jan 04 '13 at 17:23
  • You never cease to amaze with your knowledge and helpfulness! – Emmanuel Jan 04 '13 at 17:31
  • I used this to get some values out of the JSON. But, how would we use this same approach to get the whole JSON in a dictionary instead of just "rates"? – Shumais Ul Haq Oct 08 '13 at 11:10
  • How should I use this with a multidimensional JSON object? I want to extract the string values for the keys and values - this only works for the first level; after that it's still encoded JObjects. – CXL Dec 26 '19 at 19:56
  • @ClairelyClaire: It's not clear to me what you mean. I suggest you create a new question with a [mcve]. – Jon Skeet Dec 27 '19 at 08:13
9

Does this work for you?

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;

namespace JsonNetTest
{



    class Program
    {
        static void Main(string[] args)
        {

            string jsonString = @"{
                'disclaimer': 'Exchange rates provided for informational purposes only, with no guarantee whatsoever of accuracy, validity, availability, or fitness for any purpose; use at your own risk. Other than that, have fun! Usage subject to acceptance of terms: http://openexchangerates.org/terms/',
                'license': 'Data sourced from various providers with public-facing APIs; copyright may apply; not for resale; no warranties given. Usage subject to acceptance of license agreement: http://openexchangerates.org/license/',
                'timestamp': 1357268408,
                'base': 'USD',
                'rates': {
                    'AED': 3.673033,
                    'AFN': 51.5663,
                    'ALL': 106.813749,
                    'AMD': 403.579996
                }
            }";

            JObject parsed = JObject.Parse(jsonString);

            Dictionary<string, decimal> rates = parsed["rates"].ToObject<Dictionary<string, decimal>>();

            Console.WriteLine(rates["ALL"]);

            Console.ReadKey();

        }
    }
}
Adrian Halid
  • 589
  • 8
  • 17
3

If you're expecting the child object to have an object property(or field), it's better to use:

Dictionary<string, object> rates = parsed["rates"].ToObject<Dictionary<string, object>>();

Otherwise, it will throw an error.

Jose Capistrano
  • 693
  • 1
  • 8
  • 20
  • 1
    I found this to be the simplest method of accessing the keys. I used your answer to answer http://stackoverflow.com/questions/6522358/how-can-i-get-a-list-of-keys-from-json-net/ – Blairg23 Mar 29 '16 at 17:21