Deserialise JSON with unknown fields Deserialise JSON with unknown fields json json

Deserialise JSON with unknown fields


Yes, you will need a custom JsonConverter to solve this. Basically what you need to do is this:

  1. Define your QualitativeValue and QuantitativeValue classes to have a common base class (e.g. AbstractQValue) or interface.
  2. In your Parts class, make the specs property a Dictionary<string, AbstractQValue>. This will handle the changing attribute names.
  3. Create a custom JsonConverter to handle the instantiation of the concrete QualitativeValue or QuantitativeValue based on the __class__ attribute in the JSON. See this answer for an example of how to implement this.
  4. Lastly, when you do your deserialization, be sure to pass an instance of the custom JsonConverter into the JsonConvert.DeserializeObject method.

Demo

I had a little time, so I threw together a working example. Here are the class definitions for the data (I cut out most of the extraneous stuff for brevity):

public class PartsMatchResponse{    public List<PartsMatchResult> results { get; set; }}public class PartsMatchResult{    public List<Part> items { get; set; }}public class Part{    public Manufacturer manufacturer { get; set; }    public string mpn { get; set; }    public Dictionary<string, AbstractQValue> specs { get; set; }}public class Manufacturer{    public string name { get; set; }}public abstract class AbstractQValue{    public List<string> value { get; set; }}public class QualitativeValue : AbstractQValue{}public class QuantitativeValue : AbstractQValue{    public string unit { get; set; }}

Here is the custom JsonConverter class:

public class QValueJsonConverter : JsonConverter{    public override bool CanConvert(Type objectType)    {        return typeof(AbstractQValue).IsAssignableFrom(objectType);    }    public override object ReadJson(JsonReader reader,         Type objectType, object existingValue, JsonSerializer serializer)    {        JObject jo = JObject.Load(reader);        if (jo["__class__"].ToString() == "QuantitativeValue")        {            return jo.ToObject<QuantitativeValue>();        }        return jo.ToObject<QualitativeValue>();    }    public override void WriteJson(JsonWriter writer,         object value, JsonSerializer serializer)    {        throw new NotImplementedException();    }}

Here is a demo program showing how to use the converter when deserializing:

class Program{    static void Main(string[] args)    {        // (jsonString is defined as a constant below)        PartsMatchResponse response =             JsonConvert.DeserializeObject<PartsMatchResponse>(jsonString,                 new QValueJsonConverter());        foreach (Part part in response.results[0].items)        {            Console.WriteLine("manufacturer: " + part.manufacturer.name);            Console.WriteLine("mfr. part no: " + part.mpn);            foreach (KeyValuePair<string, AbstractQValue> kvp in part.specs)            {                string unit = "";                if (kvp.Value is QuantitativeValue)                     unit = ((QuantitativeValue)kvp.Value).unit;                Console.WriteLine(kvp.Key + ": " +                     string.Join(", ", kvp.Value.value) + " " + unit);            }            Console.WriteLine();        }    }    // Note: this is the same as the example JSON in the question, except     // I added units for some of the QuantitativeValue specs for demo purposes.    const string jsonString = @"        {            ""__class__"": ""PartsMatchResponse"",            ""msec"": 183,            ""request"": {                ""__class__"": ""PartsMatchRequest"",                ""exact_only"": false,                ""queries"": [                    {                        ""__class__"": ""PartsMatchQuery"",                        ""brand"": null,                        ""limit"": 10,                        ""mpn"": ""ERJ8BWFR010V"",                        ""mpn_or_sku"": null,                        ""q"": """",                        ""reference"": null,                        ""seller"": null,                        ""sku"": null,                        ""start"": 0                    }                ]            },            ""results"": [                {                    ""__class__"": ""PartsMatchResult"",                    ""error"": null,                    ""hits"": 1,                    ""items"": [                        {                            ""__class__"": ""Part"",                            ""brand"": {                                ""__class__"": ""Brand"",                                ""name"": ""Panasonic - ECG"",                                ""uid"": ""4c528d5878c09b95""                            },                            ""category_uids"": [                                ""7542b8484461ae85"",                                ""cd01000bfc2916c6"",                                ""5c6a91606d4187ad""                            ],                            ""compliance_documents"": [],                            ""datasheets"": null,                            ""external_links"": {                                ""__class__"": ""ExternalLinks"",                                ""evalkit_url"": null,                                ""freesample_url"": null,                                ""product_url"": null                            },                            ""imagesets"": null,                            ""manufacturer"": {                                ""__class__"": ""Manufacturer"",                                ""name"": ""Panasonic - ECG"",                                ""uid"": ""c20a0700af7c11cd""                            },                            ""mpn"": ""ERJ8BWFR010V"",                            ""octopart_url"": ""http://octopart.com/erj8bwfr010v-panasonic+-+ecg-7979066"",                            ""offers"": null,                            ""specs"": {                                ""case_package"": {                                    ""__class__"": ""QualitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": []                                    },                                    ""value"": [                                        ""1206""                                    ]                                },                                ""case_package_si"": {                                    ""__class__"": ""QualitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": []                                    },                                    ""value"": [                                        ""3216""                                    ]                                },                                ""lead_free_status"": {                                    ""__class__"": ""QualitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": [                                            {                                                ""__class__"": ""Source"",                                                ""name"": ""Future Electronics"",                                                ""uid"": ""e4032109c4f337c4""                                            }                                        ]                                    },                                    ""value"": [                                        ""Lead Free""                                    ]                                },                                ""lifecycle_status"": {                                    ""__class__"": ""QualitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": []                                    },                                    ""value"": [                                        ""Not Listed by Manufacturer""                                    ]                                },                                ""pin_count"": {                                    ""__class__"": ""QuantitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": [                                            {                                                ""__class__"": ""Source"",                                                ""name"": ""Farnell"",                                                ""uid"": ""58989d9272cd8b5f""                                            }                                        ]                                    },                                    ""max_value"": null,                                    ""min_value"": null,                                    ""unit"": null,                                    ""value"": [                                        ""2""                                    ]                                },                                ""power_rating"": {                                    ""__class__"": ""QuantitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": [                                            {                                                ""__class__"": ""Source"",                                                ""name"": ""Newark"",                                                ""uid"": ""d294179ef2900153""                                            }                                        ]                                    },                                    ""max_value"": null,                                    ""min_value"": null,                                    ""unit"": ""Watt"",                                    ""value"": [                                        ""0.5""                                    ]                                },                                ""resistance"": {                                    ""__class__"": ""QuantitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": [                                            {                                                ""__class__"": ""Source"",                                                ""name"": ""Farnell"",                                                ""uid"": ""58989d9272cd8b5f""                                            }                                        ]                                    },                                    ""max_value"": null,                                    ""min_value"": null,                                    ""unit"": ""Ohm"",                                    ""value"": [                                        ""0.01""                                    ]                                },                                ""resistance_tolerance"": {                                    ""__class__"": ""QualitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": []                                    },                                    ""value"": [                                        ""\u00b11%""                                    ]                                },                                ""rohs_status"": {                                    ""__class__"": ""QualitativeValue"",                                    ""attribution"": {                                        ""__class__"": ""Attribution"",                                        ""first_acquired"": null,                                        ""sources"": [                                            {                                                ""__class__"": ""Source"",                                                ""name"": ""Newark"",                                                ""uid"": ""d294179ef2900153""                                            }                                        ]                                    },                                    ""value"": [                                        ""Compliant""                                    ]                                }                            },                            ""uid"": ""69e8a09b8cb4b62f"",                            ""uid_v2"": 797906654705                        }                    ],                    ""reference"": null                }            ]        }";}

And finally, here is the output of the above program:

manufacturer: Panasonic - ECGmfr. part no: ERJ8BWFR010Vcase_package: 1206case_package_si: 3216lead_free_status: Lead Freelifecycle_status: Not Listed by Manufacturerpin_count: 2power_rating: 0.5 Wattresistance: 0.01 Ohmresistance_tolerance: ±1%rohs_status: Compliant


You'll need these classes to model the JSON

public class OctopartObject{    public string __class__ { get; set; }    public int msec { get; set; }    public Request request { get; set; }    public List<Result> results { get; set; }}public class Query{    public string __class__ { get; set; }    public object brand { get; set; }    public int limit { get; set; }    public string mpn { get; set; }    public object mpn_or_sku { get; set; }    public string q { get; set; }    public object reference { get; set; }    public object seller { get; set; }    public object sku { get; set; }    public int start { get; set; }}public class Request{    public string __class__ { get; set; }    public bool exact_only { get; set; }    public List<Query> queries { get; set; }}public class Brand{    public string __class__ { get; set; }    public string name { get; set; }    public string uid { get; set; }}public class Manufacturer{    public string __class__ { get; set; }    public string name { get; set; }    public string uid { get; set; }}public class Item{    public string __class__ { get; set; }    public Brand brand { get; set; }    public Manufacturer manufacturer { get; set; }    public string mpn { get; set; }    public string octopart_url { get; set; }    public List<object> offers { get; set; }    public string uid { get; set; }    public object uid_v2 { get; set; }}public class Result{    public string __class__ { get; set; }    public object error { get; set; }    public int hits { get; set; }    public List<Item> items { get; set; }    public object reference { get; set; }}

Then using JSON.NET & .NET 4.5, do something like this.

HttpClient client = new HttpClient();// Send a request asynchronously and continue when completeHttpResponseMessage clientResult = await client.GetAsync(_address);// Check that response was successful or throw exceptionclientResult.EnsureSuccessStatusCode();// Read response asynchronously as JToken and write out top facts for each countrystring jsonString = await clientResult.Content.ReadAsStringAsync();OctopartObject obj = JsonConvert.DeserializeObject<OctopartObject>(jsonString);

You'll have a nice object that should model the data received from the _address URI

I still haven't fully tested this, so there could be some issues. But I've been struggling for a few hours on this and finally found something that seems to be working. I'm sure it won't work for datasheets and any extra fields, as this only returns the basic. But I essentially just used this site to get the object models and changed the name of the root one to OctopartObject