2

I have defined a Quote class like this:

public class Quote
{
    public double Price { get; set; }
    public string Symbol { get; set; }
}

The following JSON is returned by a Web API rest endpoint and does not include an explicit symbol field. The symbols are the named objects, e.g. AAPL, GOOG, FB:

{                       
    "AAPL": {           
        "price": 205    
    },                  
    "GOOG": {           
        "price": 1230.38
    },                  
    "FB": {             
        "price": 178.41 
    }                   
}    

What is the best way to convert this JSON to a List<Quote>?

10
  • Where is the symbol in you json? Commented Apr 7, 2019 at 5:31
  • The json doesn't explicitly have a "symbol" field, that's the tricky part. Commented Apr 7, 2019 at 5:32
  • So where this symbol comes from to assign it to Symbol property in your class while deserialization Commented Apr 7, 2019 at 5:33
  • Quote.Symbol is the stock ticker, e.g. AAPL GOOG FB Commented Apr 7, 2019 at 5:39
  • Where is this json object defined? any local file or is it just a string, than you want to convert to json for this Quote class? Commented Apr 7, 2019 at 5:42

2 Answers 2

3

One simple approach to deal with your tricky part of json

1) Deserialize your json to Dictionary<string, dynamic>.

2) Then flatten your dictionary result to List<Quote>.

string json = File.ReadAllText(@"Path to your json");

List<Quote> quotes = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(json)
    .Select(x => new Quote
    {
        Symbol = x.Key,
        Price = x.Value.price    //<= x.Value is dynamic type so you can access your key with dot(.) separator
    })
    .ToList();


//-------------Print the result to Console-------------

Console.WriteLine("Symbol\tPrice");
Console.WriteLine("----------------------");
foreach (var quote in quotes)
{
    Console.WriteLine(quote.Symbol +"\t" + quote.Price);
}

Alternative:

You can use JToken instead of dynamic,

List<Quote> quotes = JsonConvert.DeserializeObject<Dictionary<string, JToken>>(json)
    .Select(x => new Quote
    {
        Symbol = x.Key,
        Price = Convert.ToDouble(x.Value["price"])
    })
    .ToList();

Output:

enter image description here

Sign up to request clarification or add additional context in comments.

8 Comments

That's much simpler. I want to know , is it applicable to xml format?
@its4zahoor, Yes if you would like to use xml with XDocument. Because XDocument support LINQ and with LINQ you can flatten your result to whatever you want :)
ah right i forgot about dynamic - used this years ago. but VS is giving me a method not found error for .Select - any idea why ?
@BaltoStar, Add this namespace to top of your program => using System.Linq;
@BaltoStar, What happen? Does it work for you? If yes then please mark the tick on left side of answer to make it green :)
|
2

You could make a custom JsonConverter to convert this JSON structure into the List<Quote> format you want.

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

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        return obj.Properties()
                  .Select(p => new Quote
                  {
                      Symbol = p.Name,
                      Price = p.Value["price"].ToObject<double>()
                  })
                  .ToList();
    }

    public override bool CanWrite
    {
        get { return false; }
    }

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

Then use it like this:

var quotes = JsonConvert.DeserializeObject(json, new QuoteListConverter());

Working demo: https://dotnetfiddle.net/kcU8DO

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.