Mark Camilleri
Mark Camilleri

Reputation: 130

Parsing JSON key value pairs in C#

With reference to Parse JSON in C#

I am trying to parse the following JSON feed in C# and I have a problem with accessing the data in "rates". I have tried to deserialize this into a List> or Dictionary and various other types I always get 0 results. The only way I managed to get it work was by creating a custom type and having all the currencies I need as properties - which is quite nice.

Here are my current DataContracts:

    [DataContract]
    public class OpenExchangeRatesResult
    {
        public OpenExchangeRatesResult() { }

        [DataMember]
        public string disclaimer { get; set; }

        [DataMember]
        public RatesObj rates { get; set; }

    }

    [DataContract]
    public class RatesObj
    {
        public RatesObj() { }
        [DataMember]
        public decimal EUR { get; set; }
        [DataMember]
        public decimal USD { get; set; }
        [DataMember]
        public decimal GBP { get; set; }
        [DataMember]
        public decimal AUD { get; set; }
        [DataMember]
        public decimal CAD { get; set; }
        [DataMember]
        public decimal CHF { get; set; }
        [DataMember]
        public decimal DKK { get; set; }
        [DataMember]
        public decimal LYD { get; set; }
        [DataMember]
        public decimal NZD { get; set; }
        [DataMember]
        public decimal SEK { get; set; }
        [DataMember]
        public decimal JPY { get; set; }
        [DataMember]
        public decimal ZAR { get; set; }
    }

I would love to be able to replace the RatesObj with a collection of some sort.

Any ideas?

Upvotes: 3

Views: 7158

Answers (3)

(IMHO it would be great if IExtensibleDataObject could be used for these kind of things but as ExtensionDataObject is completely opaque it's explicitly disallowed. You can of course extract the internal dictionary using Reflection but there are no guarantees for the behavior if you do so)

It's possible to use: JsonReaderWriterFactory.CreateJsonReader to create an XmlReader object which allows for a more dynamic schema. Using XmlReaders are painful most of the time so I can't claim this code is perfect but perhaps it can serve as inspiration.

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Xml;

namespace ConsoleApplication1
{

    class Program
    {
        static dynamic RecursiveBuildUp (XmlReader reader)
        {
            object result = null;
            while (reader.Read ())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        // TODO: It seems array elements are identified with the an "item" key
                        // This can create problems if the json object has a property name "item"
                        if (reader.LocalName == "item")
                        {
                            var list = result as List<object>;
                            if (list == null)
                            {
                                list = new List<object>();
                                result = list;
                            }
                            list.Add (RecursiveBuildUp (reader));
                        }
                        else
                        {
                            var dic = result as IDictionary<string, object>;
                            if (dic == null)
                            {
                                dic = new ExpandoObject ();
                                result = dic;
                            }
                            var localName = reader.LocalName;
                            dic[localName] = RecursiveBuildUp (reader);
                        }
                        break;
                    case XmlNodeType.Text:
                        result = reader.Value;
                        break;
                    case XmlNodeType.EndElement:
                        return result;
                    default:
                        throw new Exception ("Unhandled node type: " + reader.NodeType);
                }
            }
            return result;
        }

        static void Main (string[] args)
        {
            var wc = new WebClient ();
            var json = wc.DownloadData ("https://raw.github.com/currencybot/open-exchange-rates/master/latest.json");

            var quotas = new XmlDictionaryReaderQuotas ();
            var reader = JsonReaderWriterFactory.CreateJsonReader (json, quotas);

            var result = RecursiveBuildUp (reader);
            Console.WriteLine (result.root.rates.AED);
        }
    }
}

Upvotes: 0

David Hoerster
David Hoerster

Reputation: 28701

I'm using JSON.net (documentation here), which is probably similar to the DataContractJsonSerializer, but I just replaced your RatesObj with a Dictionary<string,decimal>:

[DataContract]
public class OpenExchangeRatesResult
{
    public OpenExchangeRatesResult() { }
    [DataMember]
    public string disclaimer { get; set; }
    [DataMember]
    public Dictionary<string, decimal> rates { get; set; }
}

And my test code:

class Program
{
    static void Main(string[] args)
    {
        HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(@"https://raw.github.com/currencybot/open-exchange-rates/master/latest.json");
        wr.Timeout = 30 * 1000;
        HttpWebResponse response = (HttpWebResponse)wr.GetResponse();
        using (var s = new StreamReader(response.GetResponseStream()))
        {
            string json = s.ReadToEnd();

            var oerr = JsonConvert.DeserializeObject<OpenExchangeRatesResult>(json);

            Console.WriteLine(json);
        }
    }
}

I end up with the rates property having some 150 entries of strings (the currency name) and decimals (the rates). Hopefully this is what you're looking for.

I hope this helps. Let me know if you have other questions and I'll elaborate my answer.

Good luck!

Upvotes: 3

ADIMO
ADIMO

Reputation: 1117

Try JSon.Net, it's a great library.

http://json.codeplex.com

Upvotes: 0

Related Questions