2011-07-19 80 views
1

我試圖用JSON.Net解析從第三方API返回的結果。如何使用JSON.Net解析此問題?

正如您所看到的,第一個塊似乎是對後續行塊列的描述。我假設這不是標準做法,因爲我無法在任何地方找到對此風格的任何參考。 因爲它不是通常的名稱:值對格式,我有點難住。

{ cols: [{label: "name", type: 'string'}, 
    {label: "caller_id_number", type: 'string'}, 
    {label: "destination_number", type: 'string'}, 
    {label: "call_start", type: 'datetime'}, 
    {label: "duration", type: 'number'}, 
    {label: "bill_seconds", type: 'number'}, 
    {label: "uuid", type: 'string'}, 
    {label: "call_bill_total", type: 'number'}, 
    {label: "recorded", type: 'boolean'}], 
    rows: [ 
{c:[{v: "mydomain.com"}, 
    {v: "1650"}, 
    {v: "01902321654"}, 
    {v: new Date(2011, 6, 19, 14, 12, 25)}, 
    {v: 3}, 
    {v: 0}, 
    {v: "07752f6c-b203-11e0-92e6-495a2db86d6d"}, 
    {v: 0}, 
    {v: true}]} 
,{c:[{v: "mydomain.com"},{v: "1652"},{v: "034534514"},{v: new Date(2011, 6, 19, 14, 11, 34)},{v: 53},{v: 27},{v: "e8fe3a06-b202-11e0-92dd-495a2db86d6d"},{v: 0.05},{v: true}]}, 
{c:[{v: "mydomain.com"},{v: "1650"},{v: "034534580"},{v: new Date(2011, 6, 19, 14, 11, 34)},{v: 11},{v: 9},{v: "e8dfb9dc-b202-11e0-92dc-495a2db86d6d"},{v: 0.02},{v: true}]}, 
{c:[{v: "mydomain.com"},{v: "1650"},{v: "03453453600"},{v: new Date(2011, 6, 19, 14, 11, 11)},{v: 14},{v: 9},{v: "db7efd52-b202-11e0-92d6-495a2db86d6d"},{v: 0.02},{v: true}]}, 
{c:[{v: "mydomain.com"},{v: "1650"},{v: "0345345947"},{v: new Date(2011, 6, 19, 14, 9, 41)},{v: 42},{v: 21},{v: "a59314bc-b202-11e0-92c7-495a2db86d6d"},{v: 0.04},{v: true}]}, 
{c:[{v: "mydomain.com"},{v: "1653"},{v: "345345420"},{v: new Date(2011, 6, 19, 14, 9, 41)},{v: 28},{v: 0},{v: "a5a953f8-b202-11e0-92c8-495a2db86d6d"},{v: 0},{v: true}]}, 
{c:[{v: "mydomain.com"},{v: "1650"},{v: "353453120"},{v: new Date(2011, 6, 19, 14, 8, 52)},{v: 28},{v: 5},{v: "885515bc-b202-11e0-92bd-495a2db86d6d"},{v: 0.02},{v: true}]}, 
{c:[{v: "mydomain.com"},{v: "1653"},{v: "34534567"},{v: new Date(2011, 6, 19, 14, 8, 36)},{v: 10},{v: 3},{v: "7efc86d0-b202-11e0-92b8-495a2db86d6d"},{v: 0.02},{v: true}]}, 
{c:[{v: "mydomain.com"},{v: "1650"},{v: "34534584"},{v: new Date(2011, 6, 19, 14, 7, 43)},{v: 34},{v: 13},{v: "5f1cfb60-b202-11e0-92b2-495a2db86d6d"},{v: 0.02},{v: true}]}, 
{c:[{v: "mydomain.com"},{v: "1653"},{v: "34534534561"},{v: new Date(2011, 6, 19, 14, 6, 52)},{v: 52},{v: 0},{v: "411b3faa-b202-11e0-92ab-495a2db86d6d"},{v: 0},{v: true}]}]} 

我只有儘可能 var o = JObject.Parse(results); var records = o.SelectToken("rows").Select(s => s).ToList();

理想情況下,我想拉的記錄回一類如

public class CallDetailRecord 
{ 
    public String Name { get; set; } 
    public String CallerIdNumber { get; set; } 
    public String DestinationNumber { get; set; } 
    public DateTime CallStart { get; set; } 
    public int Duration { get; set; } 
    public String Uuid { get; set; } 
    public Decimal CallBillTotal { get; set; } 
    public bool Recorded { get; set; } 
} 

非常感謝任何幫助。

+2

我今天發現了數據使用[谷歌的數據可視化API]生產(http://code.google.com/apis/chart/interactive/docs/reference.html) 使許多更有突然感覺到。 – Mechamonkey

回答

1

雖然你的樣本數據沒有嚴格有效的JSON,你試圖解析它是相當接近。

您看到的佈局有時會被一些相信通過別名字段名稱可以改進(減少)結果集大小的參與方使用。不幸的是,處理這件事並不是那麼簡單,但是你可以將項目轉回到對象中。

我在這些情況下的首選是使用dynamic關鍵字和ExpandoObject s。如果您願意,您可以使用課程,因爲創建對象的大部分工作發生在下面的最後Select(),您可以重寫它以將元素集映射到類的字段而不是ExpandoObject。訪問字段的語法是相同的,正如您可以通過將所有值寫入控制檯的結尾處的片段所看到的一樣。

請注意,我寫了一個幫助器lambda來處理將Date()映射到DateTime()的情況。我只是指出了這一點,因爲你可能有一個更好的地方來放這個方法(可能是DateTime上的擴展方法);但是將它複製並粘貼到代碼的適當位置並沒有什麼壞處。

using System.Dynamic; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Converters; 
using Newtonsoft.Json.Linq; 

// ... other code removed 

// You already have a means that loads your pseudo-json into results 
// I used a file for the sake of this example 
string results = File.ReadAllText(@"C:\temp\sample.json"); 

var o = JObject.Parse(results); 
var headers = o.SelectToken("cols") 
    .Select(x => { return new { label = x.SelectToken("label").Value<string>(), type = x.SelectToken("type").Value<string>()}; }).ToArray(); 
var rows = o.SelectToken("rows").Select(s => { return s.SelectToken("c");}).ToList(); 

Func<JConstructor, DateTime> MapAsDateTime = (s) => 
{ 
    // This is sloppy on my part, you should improve this as you like. 
    List<int> v = new List<int>(); 
    foreach (JToken t in s) 
    { 
     v.Add(t.Value<int>()); 
    } 
    return new DateTime(v[0], v[1], v[2], v[3], v[4], v[5]); 
}; 

IEnumerable<dynamic> finalValues = rows.Select(s => 
    { 
     var innerValues = s.ToList().Select(x => { return x.SelectToken("v"); }).ToArray(); 
     int i = 0; 
     dynamic val = new ExpandoObject(); 
     IDictionary<string, object> valueMap = (IDictionary<string, object>)val; 
     foreach (var innerValue in innerValues) 
     { 
      switch (headers[i].type) 
      { 
       case "string": 
        // NOTE: This can be improved, you could try to match and convert GUIDs with a regex or something else. 
        valueMap[headers[i].label] = innerValue.Value<string>(); 
        break; 
       case "datetime": 
        valueMap[headers[i].label] = MapAsDateTime((JConstructor)innerValue); 
        break; 
       case "number": 
        // NOTE: This can be improved, your specific case needs decimal to handle things like 0.25, but many others could get by with just int 
        valueMap[headers[i].label] = innerValue.Value<decimal>(); 
        break; 
       case "boolean": 
        valueMap[headers[i].label] = innerValue.Value<bool>(); 
        break; 
       default: 
        // NOTE: You will need to add more cases if they 'define' more types. 
        throw new ArgumentException(string.Format("unhandled type \"{0}\" found in schema headers.", headers[i].type)); 
      } 
      i++; 
     } 
     return val; 
    }); 

foreach (dynamic d in finalValues) 
{ 
    Console.WriteLine("name: {0}", d.name); 
    Console.WriteLine("caller_id_number: {0}", d.caller_id_number); 
    Console.WriteLine("destination_number: {0}", d.destination_number); 
    Console.WriteLine("call_start: {0}", d.call_start); 
    Console.WriteLine("duration: {0}", d.duration); 
    Console.WriteLine("bill_seconds: {0}", d.bill_seconds); 
    Console.WriteLine("uuid: {0}", d.uuid); 
    Console.WriteLine("call_bill_total: {0}", d.call_bill_total); 
    Console.WriteLine("recorded: {0}", d.recorded); 
    Console.WriteLine("--"); 
} 

最後,您樣本中第一個數據單元的樣本輸出。

name: mydomain.com 
caller_id_number: 1650 
destination_number: 01902321654 
call_start: 6/19/2011 2:12:25 PM 
duration: 3 
bill_seconds: 0 
uuid: 07752f6c-b203-11e0-92e6-495a2db86d6d 
call_bill_total: 0 
recorded: True 
-- 
+0

輝煌的東西,這當然讓我擺脫了泡菜! 這是字段名稱別名,這是扔了我這麼多。 非常感謝您爲創造這一點所花費的時間。 – Mechamonkey

+0

實現代碼@meklarian,完美的作品:) – Mechamonkey

3

我不知道那是什麼,但它不是JSON。它看起來像JavaScript,並可能會解析罰款與JavaScript引擎。

JSON規格:http://json.org/

驗證:http://jsonlint.com/

+0

我明白你的意思了,我一定會看看這個,謝謝。 – Mechamonkey