0

I'm trying to deserialize the following json string to a series of custom c# classes below. I'm not sure if this is the right or best approach but short of doing a Find/Replace on the json string(doesn't seem like a very clean way to do it, there must be a better way than that) I'm not sure what else can be done.

    "Meta Data": {
        "1. Information": "Daily Prices (open, high, low, close) and Volumes",
        "2. Symbol": "NVDA",
        "3. Last Refreshed": "2024-12-06",
        "4. Output Size": "Full size",
        "5. Time Zone": "US/Eastern"
    },
    "Time Series (Daily)": {
        "2024-12-06": {
            "1. open": "144.6000",
            "2. high": "145.7000",
            "3. low": "141.3100",
            "4. close": "142.4400",
            "5. volume": "188505573"
        },
        "2024-12-05": {
            "1. open": "145.1100",
            "2. high": "146.5400",
            "3. low": "143.9500",
            "4. close": "145.0600",
            "5. volume": "172621180"
        },
        // Many more entries

But, I want to rearrange and reorganize the json to:

"MetaData": {
            "Information": "Daily Prices (open, high, low, close) and Volumes",
            "Symbol": "NVDA",
            "LastRefreshed": "2024-12-06",
            "OutputSize": "Full size",
            "TimeZone": "US/Eastern"
        },
        "TimeSeries": {
            "Data": {
                "open": "144.6000",
                "high": "145.7000",
                "low": "141.3100",
                "close": "142.4400",
                "volume": "188505573", 
                "date": "2024-12-06",
                "series": "Daily"
            },
            "Data": {
                "open": "145.1100",
                "high": "146.5400",
                "low": "143.9500",
                "close": "145.0600",
                "volume": "172621180",
                "date": "2024-12-05",
                "series": "Daily"
            }
        }

So I can create the following classes

    public class Data
    {
        [JsonProperty("open")]
        public string open { get; set; }

        [JsonProperty("high")]
        public string high { get; set; }

        [JsonProperty("low")]
        public string low { get; set; }

        [JsonProperty("close")]
        public string close { get; set; }

        [JsonProperty("volume")]
        public string volume { get; set; }

        [JsonProperty("date")]
        public string date { get; set; }

        [JsonProperty("series")]
        public string series { get; set; }
    }

    public class Root
    {
        [JsonProperty("MetaData")]
        public MetaData MetaData { get; set; }

        [JsonProperty("TimeSeries")]
        public TimeSeries TimeSeries { get; set; }
    }

    public class TimeSeries
    {
        [JsonProperty("Data")]
        public Data Data { get; set; }
    }

    public class MetaData
    {
        [JsonProperty("Information")]
        public string Information { get; set; }

        [JsonProperty("Symbol")]
        public string Symbol { get; set; }

        [JsonProperty("Last Refreshed")]
        public string LastRefreshed { get; set; }

        [JsonProperty("Output Size")]
        public string OutputSize { get; set; }

        [JsonProperty("Time Zone")]
        public string TimeZone { get; set; }
    }   

This way I could deserialize the json string. I've done some research looking in to this but I haven't found what I'm looking for yet. I'm using Newtonsoft and I'd like answers to use Newtonsoft as well. But, if there is something better out there I'll be willing to switch to another package. First, I'd like to know if this approach would work. If not, I'd like ideas on how communiy members would tackle this problem.

4
  • 3
    The intended JSON isn't even normalized: it has duplicate Data keys in Time Series. Perhaps you should have a single Data key with an array of objects? Commented Dec 8, 2024 at 4:17
  • As noted by @Charlieface, your proposed JSON has duplicate keys. While duplicate keys are not disallowed by JSON RFC 8259, they are discouraged: The names within an object SHOULD be unique... When the names within an object are not unique, the behavior of software that receives such an object is unpredictable... Other implementations report an error or fail to parse the object. Can you please confirm you really want that? Commented Dec 8, 2024 at 14:47
  • 1
    Incidentally, your current "Time Series (Daily)" JSON property value can easily be serialized as a [JsonProperty("Time Series (Daily)")] public Dictionary<string, Data> { get; set; } or Dictionary<DateOnly, Data> so I recommend sticking with the current format. Commented Dec 8, 2024 at 14:54
  • If you must serialize and deserialize duplicate property names you will need to write a converter. Does How to serialize and deserialize a JSON object with duplicate property names in a specific order? answer your question? I'm not sure it answers your question exactly because it requires a List<KeyValuePair<string, string>> property where the KeyValuePair.Key is the (possibly duplicated) property name -- but in your case the duplicated property name is always "Data". Commented Dec 8, 2024 at 17:39

1 Answer 1

0

this is an example how to deserialize your json with simpler class structure

void Main()
{
    string json = "{\"Meta Data\":{\"1. Information\":\"Daily Prices (open, high, low, close) and Volumes\",\"2. Symbol\":\"NVDA\",\"3. Last Refreshed\":\"2024-12-06\",\"4. Output Size\":\"Full size\",\"5. Time Zone\":\"US/Eastern\"},\"Time Series (Daily)\":{\"2024-12-06\":{\"1. open\":\"144.6000\",\"2. high\":\"145.7000\",\"3. low\":\"141.3100\",\"4. close\":\"142.4400\",\"5. volume\":\"188505573\"},\"2024-12-05\":{\"1. open\":\"145.1100\",\"2. high\":\"146.5400\",\"3. low\":\"143.9500\",\"4. close\":\"145.0600\",\"5. volume\":\"172621180\"}}}";
    
    var obj = JsonConvert.DeserializeObject<Root>(json).Dump();
    
    JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented).Dump();
        
}

public class Root
{
    [JsonProperty("Meta Data")]
    public Dictionary<string,string> MetaData { get; set; }

    [JsonProperty("Time Series (Daily)")]
    public Dictionary<string, Dictionary<string,string>> TimeSeriesDaily { get; set; }
}

as you can see it deserialize, so you can write a custom JsonConverter (WriteJson part where you can remove list numbers, etc..) or maybe custom ContractResolver to convert to structure you want. enter image description here

UPDATE: you can clean up numbering in dictionary as i made as CustomConverter in example for understanding

public class DictionaryConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType) => typeof(T) == objectType;
    public override bool CanWrite => false;
    public override bool CanRead => true;
    
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var jo = Newtonsoft.Json.Linq.JObject.Load(reader).AsJEnumerable().ToList();
        var d = new Dictionary<string,string>();
        foreach (JProperty item in jo)
        {
            if(item.Name.Substring(1,1) == ".")
                d.Add(item.Name.Substring(3), item.Value.ToString());
            else
            d.Add(item.Name, item.Value.ToString());
        }
        return d;
    }

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

and to use it add line to class property:

[JsonProperty("Meta Data")]
[JsonConverter(typeof(DictionaryConverter<JObject>))]
public Dictionary<string, string> MetaData { get; set; }

the result would be: dictionary names without a row number.

enter image description here

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

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.