2013-10-16 139 views
3

我試圖使用C#和json.netDeserialise JSON與未知的領域

沒有問題deserialising的大部分數據以deserialise從OctoPart API(http://octopart.com/api/docs/v3/rest-api)的結果,但是我運行的煩惱與零件.specs屬性(http://octopart.com/api/docs/v3/rest-api#notes-part.specs),因爲屬性會根據返回的項目而變化。

這裏是什麼API說,關於該規格屬性附接到部分實例Part.Specs

是JSON對象映射屬性短名稱(例如「voltage_rating_dc」),以QualitativeValueQuantitativeValue實例。
重要的是要注意(Qual | Quant)itativeValue對象的所有值屬性都是JSON數組。這樣做的原因是爲了適應多值的屬性,如電源具有多種輸出電壓:

因爲我想維護類,我認爲我可能需要實現自定義JConverter? 我看着這個question,但並不太高知道如何應用到這個例子beccause的屬性可以deserialised到QualitativeValue/QuantitativeValue類

這裏是我的部件類

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

{ 
    "__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": "e9c4f337c4" 
            } 
           ] 
          }, 
          "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 
     } 
    ] 
} 

回答

1

是結果(PartsMatchResponse),則需要自定義JsonConverter來解決這個問題。基本上你需要做的是這樣的:

  1. 定義你QualitativeValueQuantitativeValue類有一個共同的基類(例如AbstractQValue)或接口。
  2. 在您的Parts類中,使specs屬性爲Dictionary<string, AbstractQValue>。這將處理更改的屬性名稱。
  3. 根據JSON中的__class__屬性創建自定義JsonConverter以處理具體的QualitativeValueQuantitativeValue的實例化。請參閱this answer瞭解如何實現此目的的示例。
  4. 最後,當您進行反序列化時,請確保將自定義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"": ""e9c4f337c4"" 
              } 
             ] 
            }, 
            ""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 
+0

這很棒,非常感謝您的幫助。我會盡快嘗試! – Spacko

0

你需要這些類模型然後使用JSON.NET & .NET 4.5中的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; } 
} 

,做這樣的事情。

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