2013-02-15 24 views
39

Tôi có phương thức API web chấp nhận tải trọng json tùy ý vào thuộc tính JObject. Vì vậy, tôi không biết những gì sắp tới nhưng tôi vẫn cần dịch nó sang các loại .NET. Tôi muốn có một số Dictionary<string,object> để tôi có thể giải quyết nó theo bất kỳ cách nào tôi muốn.Chuyển đổi JObject sang Dictionary <string, object>. Có thể không?

Tôi đã tìm kiếm rất nhiều, nhưng không thể tìm thấy bất kỳ thứ gì và kết thúc bằng cách bắt đầu một phương pháp lộn xộn để thực hiện chuyển đổi này, khóa theo khóa, giá trị theo giá trị. Có cách nào dễ dàng để làm điều đó không?

Input ->

JObject person = new JObject(
    new JProperty("Name", "John Smith"), 
    new JProperty("BirthDate", new DateTime(1983, 3, 20)), 
    new JProperty("Hobbies", new JArray("Play football", "Programming")), 
    new JProperty("Extra", new JObject(
     new JProperty("Foo", 1), 
     new JProperty("Bar", new JArray(1, 2, 3)) 
    ) 
) 

Cảm ơn!

+2

Hai điều, công việc đã thực hiện Từ điển . Và câu hỏi, ý định của bạn là gì để đối phó với các thuộc tính phụ. Giá trị đó trong Từ điển của bạn có phải là một Từ điển khác không? – Rich

+0

Có @Rich, các thuộc tính phụ sẽ là một Từ điển khác tucaz

+0

Xem thêm [Làm thế nào để sử dụng JSON.NET để deserialize vào từ điển/đệ quy lồng nhau và Danh sách?] (Http://stackoverflow.com/q/5546142/10263). Phương thức trợ giúp 'ToObject (JToken)' trong câu trả lời đầu tiên sẽ thực hiện chuyển đổi này với mã tối thiểu. –

Trả lời

16

Tôi đã kết thúc bằng cách sử dụng kết hợp cả hai câu trả lời là không có câu trả lời nào.

ToObject() có thể thực hiện cấp thuộc tính đầu tiên trong đối tượng JSON, nhưng đối tượng lồng nhau sẽ không được chuyển đổi thành Dictionary().

Cũng không cần phải làm mọi thứ theo cách thủ công vì ToObject() khá tốt với thuộc tính cấp đầu tiên.

Đây là mã:

public static class JObjectExtensions 
{ 
    public static IDictionary<string, object> ToDictionary(this JObject @object) 
    { 
     var result = @object.ToObject<Dictionary<string, object>>(); 

     var JObjectKeys = (from r in result 
          let key = r.Key 
          let value = r.Value 
          where value.GetType() == typeof(JObject) 
          select key).ToList(); 

     var JArrayKeys = (from r in result 
          let key = r.Key 
          let value = r.Value 
          where value.GetType() == typeof(JArray) 
          select key).ToList(); 

     JArrayKeys.ForEach(key => result[key] = ((JArray)result[key]).Values().Select(x => ((JValue)x).Value).ToArray()); 
     JObjectKeys.ForEach(key => result[key] = ToDictionary(result[key] as JObject)); 

     return result; 
    } 
} 

Nó có thể có trường hợp cạnh nơi mà nó sẽ không hoạt động và việc thực hiện không phải là chất lượng mạnh nhất của nó.

Xin cảm ơn các bạn!

+0

Điều gì xảy ra nếu các giá trị của mảng là JSON (tức là 'JObject')? Bạn không chuyển đổi chúng thành 'Dictionary ' – Nawaz

+0

@Nawaz, tôi nghĩ anh ta làm - thứ hai để dòng cuối cùng của mã ở đây gọi phương thức đệ quy cho 'JObject' bên trong. – BrainSlugs83

+0

@ BrainSlugs83: Có. Nó gọi nó là đệ quy, nhưng vẫn còn, các phần tử của 'JArrays' có thể là' JOBject' hoặc 'JArrray', sau đó chúng cần được chuyển đổi thành * C# array *, và * C# Dictionary *, mà mã không làm. – Nawaz

68

Nếu bạn có JObject đối tượng, sau đây có thể làm việc:

JObject person; 
var values = person.ToObject<Dictionary<string, object>>(); 

Nếu không, this answer có thể chỉ cho bạn đi đúng hướng, vì nó deserializes một chuỗi JSON để một từ điển.

var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(json); 
+0

+1 vì tính năng này hoạt động tốt nếu bạn có từ điển nguyên thủy. Ví dụ, dòng mã này làm việc hoàn hảo cho tôi: Từ điển feeChanges = dict.feeChanges.ToObject >(); – allen1

+0

Chuỗi 'DeserializeObject >' làm việc tuyệt vời cho tôi; Tôi đã chuyển nó thành một dãy từ điển cho các nhu cầu của tôi, thông qua 'DeserializeObject []>'. – BrainSlugs83

3

Âm thanh như một trường hợp sử dụng tốt cho các phương pháp mở rộng - Tôi đã một cái gì đó nằm xung quanh đó là khá đơn giản để chuyển đổi sang Json.NET:

Tất nhiên, đây là một cách nhanh chóng hack với nhau (Cảm ơn NuGet!) - bạn muốn dọn dẹp nó, v.v.

public static class JTokenExt 
{ 
    public static Dictionary<string, object> 
     Bagify(this JToken obj, string name = null) 
    { 
     name = name ?? "obj"; 
     if(obj is JObject) 
     { 
      var asBag = 
       from prop in (obj as JObject).Properties() 
       let propName = prop.Name 
       let propValue = prop.Value is JValue 
        ? new Dictionary<string,object>() 
         { 
          {prop.Name, prop.Value} 
         } 
        : prop.Value.Bagify(prop.Name) 
       select new KeyValuePair<string, object>(propName, propValue); 
      return asBag.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); 
     } 
     if(obj is JArray) 
     { 
      var vals = (obj as JArray).Values(); 
      var alldicts = vals 
       .SelectMany(val => val.Bagify(name)) 
       .Select(x => x.Value) 
       .ToArray(); 
      return new Dictionary<string,object>() 
      { 
       {name, (object)alldicts} 
      }; 
     } 
     if(obj is JValue) 
     { 
      return new Dictionary<string,object>() 
      { 
       {name, (obj as JValue)} 
      }; 
     } 
     return new Dictionary<string,object>() 
     { 
      {name, null} 
     }; 
    } 
} 
10

Dưới đây là phiên bản ra đời: Tôi đã sửa đổi mã để JArrays recurse một JObjects lồng trong JArrays/JObjects, mà câu trả lời được chấp nhận không, như đã chỉ ra bởi @Nawaz.

using System.Collections.Generic; 
using System.Linq; 
using Newtonsoft.Json.Linq; 

public static class JsonConversionExtensions 
{ 
    public static IDictionary<string, object> ToDictionary(this JObject json) 
    { 
     var propertyValuePairs = json.ToObject<Dictionary<string, object>>(); 
     ProcessJObjectProperties(propertyValuePairs); 
     ProcessJArrayProperties(propertyValuePairs); 
     return propertyValuePairs; 
    } 

    private static void ProcessJObjectProperties(IDictionary<string, object> propertyValuePairs) 
    { 
     var objectPropertyNames = (from property in propertyValuePairs 
      let propertyName = property.Key 
      let value = property.Value 
      where value is JObject 
      select propertyName).ToList(); 

     objectPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToDictionary((JObject) propertyValuePairs[propertyName])); 
    } 

    private static void ProcessJArrayProperties(IDictionary<string, object> propertyValuePairs) 
    { 
     var arrayPropertyNames = (from property in propertyValuePairs 
      let propertyName = property.Key 
      let value = property.Value 
      where value is JArray 
      select propertyName).ToList(); 

     arrayPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToArray((JArray) propertyValuePairs[propertyName])); 
    } 

    public static object[] ToArray(this JArray array) 
    { 
     return array.ToObject<object[]>().Select(ProcessArrayEntry).ToArray(); 
    } 

    private static object ProcessArrayEntry(object value) 
    { 
     if (value is JObject) 
     { 
      return ToDictionary((JObject) value); 
     } 
     if (value is JArray) 
     { 
      return ToArray((JArray) value); 
     } 
     return value; 
    } 
} 
Các vấn đề liên quan