我试图使用c#和json.net
对OctoPart API(http://octopart.com/api/docs/v3/rest-api)的结果进行反序列化对大多数数据进行反序列化没有问题,但是我遇到了Part.specs属性(http://octopart.com/api/docs/v3/rest-api#notes-part.specs)的麻烦,因为属性会根据返回的项目而改变。
以下是API关于Part.Specs
的内容附加到Part实例的specs属性是一个JSON对象,它将属性短名称(例如“voltage_rating_dc”)映射到QualitativeValue和QuantitativeValue个实例。
值得注意的是,(Qual | Quant)itativeValue对象的所有值属性都是JSON数组。这样做的原因是为了适应多值属性,例如具有多个输出电压的电源:
因为我想维护这个类,我相信我可能需要实现一个自定义的JConverter? 我正在查看这个question,但不太确定如何应用于此示例,因为属性可以反序列化为QualitativeValue / QuantitativeValue类
这是我的Part类
public class Part
{
public string __class__ { get; set; }
public string uid { get; set; }
public long uid_v2 { get; set; }
public string mpn { get; set; }
public Manufacturer manufacturer { get; set; }
public Brand brand { get; set; }
public string octopart_url { get; set; }
public List<PartOffer> offers { get; set; }
public List<Datasheet> datasheets { get; set; }
public List<ComplianceDocument> compliance_documents { get; set; }
public List<Description> descriptions { get; set; }
public List<ImageSet> imagesets { get; set; }
public Dictionary<string, string> specs { get; set; }
public List<string> category_uids { get; set; }
public List<ExternalLinks> external_links { get; set; }
}
以下是API
中的示例结果(PartsMatchResponse){
"__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": null,
"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": null,
"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
}
]
}
答案 0 :(得分:1)
是的,您需要自定义JsonConverter
来解决此问题。基本上你需要做的是:
QualitativeValue
和QuantitativeValue
类定义为具有公共基类(例如AbstractQValue
)或接口。Parts
课程中,将specs
属性设为Dictionary<string, AbstractQValue>
。这将处理更改的属性名称。JsonConverter
属性创建自定义QualitativeValue
以处理具体QuantitativeValue
或__class__
的实例化。有关如何实现此目的的示例,请参阅this answer。JsonConverter
的实例传递到JsonConvert.DeserializeObject
方法。<强>演示强>
我有一点时间,所以我把一个工作的例子拼凑起来。以下是数据的类定义(为简洁起见,我删除了大部分无关的内容):
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; }
}
以下是自定义JsonConverter
类:
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();
}
}
这是一个演示程序,展示了在反序列化时如何使用转换器:
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
}
]
}";
}
最后,这是上述程序的输出:
manufacturer: Panasonic - ECG
mfr. part no: ERJ8BWFR010V
case_package: 1206
case_package_si: 3216
lead_free_status: Lead Free
lifecycle_status: Not Listed by Manufacturer
pin_count: 2
power_rating: 0.5 Watt
resistance: 0.01 Ohm
resistance_tolerance: ±1%
rohs_status: Compliant
答案 1 :(得分:0)
您需要这些类来建模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; }
}
然后使用JSON.NET&amp; .NET 4.5,做这样的事情。
HttpClient client = new HttpClient();
// Send a request asynchronously and continue when complete
HttpResponseMessage clientResult = await client.GetAsync(_address);
// Check that response was successful or throw exception
clientResult.EnsureSuccessStatusCode();
// Read response asynchronously as JToken and write out top facts for each country
string jsonString = await clientResult.Content.ReadAsStringAsync();
OctopartObject obj = JsonConvert.DeserializeObject<OctopartObject>(jsonString);
你将有一个很好的对象,应该对从_address URI
收到的数据进行建模我还没有完全测试过,所以可能存在一些问题。但是我一直在努力奋斗几个小时,终于找到了一些似乎有效的东西。我确信它不适用于数据表和任何额外的字段,因为这只返回基本的。但我基本上只是used this site来获取对象模型并将根目录的名称更改为OctopartObject