使用未知字段反序列化JSON

时间:2013-10-16 13:20:19

标签: c# json json.net

我试图使用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”)映射到QualitativeValueQuantitativeValue个实例。
  值得注意的是,(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
        }
    ]
}

2 个答案:

答案 0 :(得分:1)

是的,您需要自定义JsonConverter来解决此问题。基本上你需要做的是:

  1. 将您的QualitativeValueQuantitativeValue类定义为具有公共基类(例如AbstractQValue)或接口。
  2. Parts课程中,将specs属性设为Dictionary<string, AbstractQValue>。这将处理更改的属性名称。
  3. 根据JSON中的JsonConverter属性创建自定义QualitativeValue以处理具体QuantitativeValue__class__的实例化。有关如何实现此目的的示例,请参阅this answer
  4. 最后,在进行反序列化时,请务必将自定义JsonConverter的实例传递到JsonConvert.DeserializeObject方法。
  5. <强>演示

    我有一点时间,所以我把一个工作的例子拼凑起来。以下是数据的类定义(为简洁起见,我删除了大部分无关的内容):

    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