選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

431 行
14 KiB

  1. /*--------------------------------------------------------------------------
  2. * DynamicJson
  3. * ver 1.2.0.0 (May. 21th, 2010)
  4. *
  5. * created and maintained by neuecc <ils@neue.cc>
  6. * licensed under Microsoft Public License(Ms-PL)
  7. * http://neue.cc/
  8. * http://dynamicjson.codeplex.com/
  9. *--------------------------------------------------------------------------*/
  10. using System;
  11. using System.Collections;
  12. using System.Collections.Generic;
  13. using System.Diagnostics;
  14. using System.Dynamic;
  15. using System.IO;
  16. using System.Linq;
  17. using System.Reflection;
  18. using System.Runtime.Serialization.Json;
  19. using System.Text;
  20. using System.Xml;
  21. using System.Xml.Linq;
  22. namespace Codeplex.Data
  23. {
  24. public class DynamicJson : DynamicObject
  25. {
  26. private enum JsonType
  27. {
  28. @string, number, boolean, @object, array, @null
  29. }
  30. // public static methods
  31. /// <summary>from JsonSring to DynamicJson</summary>
  32. public static dynamic Parse(string json)
  33. {
  34. return Parse(json, Encoding.Unicode);
  35. }
  36. /// <summary>from JsonSring to DynamicJson</summary>
  37. public static dynamic Parse(string json, Encoding encoding)
  38. {
  39. using (var reader = JsonReaderWriterFactory.CreateJsonReader(encoding.GetBytes(json), XmlDictionaryReaderQuotas.Max))
  40. {
  41. return ToValue(XElement.Load(reader));
  42. }
  43. }
  44. /// <summary>from JsonSringStream to DynamicJson</summary>
  45. public static dynamic Parse(Stream stream)
  46. {
  47. using (var reader = JsonReaderWriterFactory.CreateJsonReader(stream, XmlDictionaryReaderQuotas.Max))
  48. {
  49. return ToValue(XElement.Load(reader));
  50. }
  51. }
  52. /// <summary>from JsonSringStream to DynamicJson</summary>
  53. public static dynamic Parse(Stream stream, Encoding encoding)
  54. {
  55. using (var reader = JsonReaderWriterFactory.CreateJsonReader(stream, encoding, XmlDictionaryReaderQuotas.Max, _ => { }))
  56. {
  57. return ToValue(XElement.Load(reader));
  58. }
  59. }
  60. /// <summary>create JsonSring from primitive or IEnumerable or Object({public property name:property value})</summary>
  61. public static string Serialize(object obj)
  62. {
  63. return CreateJsonString(new XStreamingElement("root", CreateTypeAttr(GetJsonType(obj)), CreateJsonNode(obj)));
  64. }
  65. // private static methods
  66. private static dynamic ToValue(XElement element)
  67. {
  68. var type = (JsonType)Enum.Parse(typeof(JsonType), element.Attribute("type").Value);
  69. switch (type)
  70. {
  71. case JsonType.boolean:
  72. return (bool)element;
  73. case JsonType.number:
  74. return (double)element;
  75. case JsonType.@string:
  76. return (string)element;
  77. case JsonType.@object:
  78. case JsonType.array:
  79. return new DynamicJson(element, type);
  80. case JsonType.@null:
  81. default:
  82. return null;
  83. }
  84. }
  85. private static JsonType GetJsonType(object obj)
  86. {
  87. if (obj == null) return JsonType.@null;
  88. switch (Type.GetTypeCode(obj.GetType()))
  89. {
  90. case TypeCode.Boolean:
  91. return JsonType.boolean;
  92. case TypeCode.String:
  93. case TypeCode.Char:
  94. case TypeCode.DateTime:
  95. return JsonType.@string;
  96. case TypeCode.Int16:
  97. case TypeCode.Int32:
  98. case TypeCode.Int64:
  99. case TypeCode.UInt16:
  100. case TypeCode.UInt32:
  101. case TypeCode.UInt64:
  102. case TypeCode.Single:
  103. case TypeCode.Double:
  104. case TypeCode.Decimal:
  105. case TypeCode.SByte:
  106. case TypeCode.Byte:
  107. return JsonType.number;
  108. case TypeCode.Object:
  109. return (obj is IEnumerable) ? JsonType.array : JsonType.@object;
  110. case TypeCode.DBNull:
  111. case TypeCode.Empty:
  112. default:
  113. return JsonType.@null;
  114. }
  115. }
  116. private static XAttribute CreateTypeAttr(JsonType type)
  117. {
  118. return new XAttribute("type", type.ToString());
  119. }
  120. private static object CreateJsonNode(object obj)
  121. {
  122. var type = GetJsonType(obj);
  123. switch (type)
  124. {
  125. case JsonType.@string:
  126. case JsonType.number:
  127. return obj;
  128. case JsonType.boolean:
  129. return obj.ToString().ToLower();
  130. case JsonType.@object:
  131. return CreateXObject(obj);
  132. case JsonType.array:
  133. return CreateXArray(obj as IEnumerable);
  134. case JsonType.@null:
  135. default:
  136. return null;
  137. }
  138. }
  139. private static IEnumerable<XStreamingElement> CreateXArray<T>(T obj) where T : IEnumerable
  140. {
  141. return obj.Cast<object>()
  142. .Select(o => new XStreamingElement("item", CreateTypeAttr(GetJsonType(o)), CreateJsonNode(o)));
  143. }
  144. private static IEnumerable<XStreamingElement> CreateXObject(object obj)
  145. {
  146. return obj.GetType()
  147. .GetProperties(BindingFlags.Public | BindingFlags.Instance)
  148. .Select(pi => new { Name = pi.Name, Value = pi.GetValue(obj, null) })
  149. .Select(a => new XStreamingElement(a.Name, CreateTypeAttr(GetJsonType(a.Value)), CreateJsonNode(a.Value)));
  150. }
  151. private static string CreateJsonString(XStreamingElement element)
  152. {
  153. using (var ms = new MemoryStream())
  154. using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.Unicode))
  155. {
  156. element.WriteTo(writer);
  157. writer.Flush();
  158. return Encoding.Unicode.GetString(ms.ToArray());
  159. }
  160. }
  161. // dynamic structure represents JavaScript Object/Array
  162. readonly XElement xml;
  163. readonly JsonType jsonType;
  164. /// <summary>create blank JSObject</summary>
  165. public DynamicJson()
  166. {
  167. xml = new XElement("root", CreateTypeAttr(JsonType.@object));
  168. jsonType = JsonType.@object;
  169. }
  170. private DynamicJson(XElement element, JsonType type)
  171. {
  172. Debug.Assert(type == JsonType.array || type == JsonType.@object);
  173. xml = element;
  174. jsonType = type;
  175. }
  176. public bool IsObject { get { return jsonType == JsonType.@object; } }
  177. public bool IsArray { get { return jsonType == JsonType.array; } }
  178. /// <summary>has property or not</summary>
  179. public bool IsDefined(string name)
  180. {
  181. return IsObject && (xml.Element(name) != null);
  182. }
  183. /// <summary>has property or not</summary>
  184. public bool IsDefined(int index)
  185. {
  186. return IsArray && (xml.Elements().ElementAtOrDefault(index) != null);
  187. }
  188. /// <summary>delete property</summary>
  189. public bool Delete(string name)
  190. {
  191. var elem = xml.Element(name);
  192. if (elem != null)
  193. {
  194. elem.Remove();
  195. return true;
  196. }
  197. else return false;
  198. }
  199. /// <summary>delete property</summary>
  200. public bool Delete(int index)
  201. {
  202. var elem = xml.Elements().ElementAtOrDefault(index);
  203. if (elem != null)
  204. {
  205. elem.Remove();
  206. return true;
  207. }
  208. else return false;
  209. }
  210. /// <summary>mapping to Array or Class by Public PropertyName</summary>
  211. public T Deserialize<T>()
  212. {
  213. return (T)Deserialize(typeof(T));
  214. }
  215. private object Deserialize(Type type)
  216. {
  217. return (IsArray) ? DeserializeArray(type) : DeserializeObject(type);
  218. }
  219. private dynamic DeserializeValue(XElement element, Type elementType)
  220. {
  221. var value = ToValue(element);
  222. if (value is DynamicJson)
  223. {
  224. value = ((DynamicJson)value).Deserialize(elementType);
  225. }
  226. return Convert.ChangeType(value, elementType);
  227. }
  228. private object DeserializeObject(Type targetType)
  229. {
  230. var result = Activator.CreateInstance(targetType);
  231. var dict = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
  232. .Where(p => p.CanWrite)
  233. .ToDictionary(pi => pi.Name, pi => pi);
  234. foreach (var item in xml.Elements())
  235. {
  236. PropertyInfo propertyInfo;
  237. if (!dict.TryGetValue(item.Name.LocalName, out propertyInfo)) continue;
  238. var value = DeserializeValue(item, propertyInfo.PropertyType);
  239. propertyInfo.SetValue(result, value, null);
  240. }
  241. return result;
  242. }
  243. private object DeserializeArray(Type targetType)
  244. {
  245. if (targetType.IsArray) // Foo[]
  246. {
  247. var elemType = targetType.GetElementType();
  248. dynamic array = Array.CreateInstance(elemType, xml.Elements().Count());
  249. var index = 0;
  250. foreach (var item in xml.Elements())
  251. {
  252. array[index++] = DeserializeValue(item, elemType);
  253. }
  254. return array;
  255. }
  256. else // List<Foo>
  257. {
  258. var elemType = targetType.GetGenericArguments()[0];
  259. dynamic list = Activator.CreateInstance(targetType);
  260. foreach (var item in xml.Elements())
  261. {
  262. list.Add(DeserializeValue(item, elemType));
  263. }
  264. return list;
  265. }
  266. }
  267. // Delete
  268. public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
  269. {
  270. result = (IsArray)
  271. ? Delete((int)args[0])
  272. : Delete((string)args[0]);
  273. return true;
  274. }
  275. // IsDefined, if has args then TryGetMember
  276. public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
  277. {
  278. if (args.Length > 0)
  279. {
  280. result = null;
  281. return false;
  282. }
  283. result = IsDefined(binder.Name);
  284. return true;
  285. }
  286. // Deserialize or foreach(IEnumerable)
  287. public override bool TryConvert(ConvertBinder binder, out object result)
  288. {
  289. if (binder.Type == typeof(IEnumerable) || binder.Type == typeof(object[]))
  290. {
  291. var ie = (IsArray)
  292. ? xml.Elements().Select(x => ToValue(x))
  293. : xml.Elements().Select(x => (dynamic)new KeyValuePair<string, object>(x.Name.LocalName, ToValue(x)));
  294. result = (binder.Type == typeof(object[])) ? ie.ToArray() : ie;
  295. }
  296. else
  297. {
  298. result = Deserialize(binder.Type);
  299. }
  300. return true;
  301. }
  302. private bool TryGet(XElement element, out object result)
  303. {
  304. if (element == null)
  305. {
  306. result = null;
  307. return false;
  308. }
  309. result = ToValue(element);
  310. return true;
  311. }
  312. public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
  313. {
  314. return (IsArray)
  315. ? TryGet(xml.Elements().ElementAtOrDefault((int)indexes[0]), out result)
  316. : TryGet(xml.Element((string)indexes[0]), out result);
  317. }
  318. public override bool TryGetMember(GetMemberBinder binder, out object result)
  319. {
  320. return (IsArray)
  321. ? TryGet(xml.Elements().ElementAtOrDefault(int.Parse(binder.Name)), out result)
  322. : TryGet(xml.Element(binder.Name), out result);
  323. }
  324. private bool TrySet(string name, object value)
  325. {
  326. var type = GetJsonType(value);
  327. var element = xml.Element(name);
  328. if (element == null)
  329. {
  330. xml.Add(new XElement(name, CreateTypeAttr(type), CreateJsonNode(value)));
  331. }
  332. else
  333. {
  334. element.Attribute("type").Value = type.ToString();
  335. element.ReplaceNodes(CreateJsonNode(value));
  336. }
  337. return true;
  338. }
  339. private bool TrySet(int index, object value)
  340. {
  341. var type = GetJsonType(value);
  342. var e = xml.Elements().ElementAtOrDefault(index);
  343. if (e == null)
  344. {
  345. xml.Add(new XElement("item", CreateTypeAttr(type), CreateJsonNode(value)));
  346. }
  347. else
  348. {
  349. e.Attribute("type").Value = type.ToString();
  350. e.ReplaceNodes(CreateJsonNode(value));
  351. }
  352. return true;
  353. }
  354. public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
  355. {
  356. return (IsArray)
  357. ? TrySet((int)indexes[0], value)
  358. : TrySet((string)indexes[0], value);
  359. }
  360. public override bool TrySetMember(SetMemberBinder binder, object value)
  361. {
  362. return (IsArray)
  363. ? TrySet(int.Parse(binder.Name), value)
  364. : TrySet(binder.Name, value);
  365. }
  366. public override IEnumerable<string> GetDynamicMemberNames()
  367. {
  368. return (IsArray)
  369. ? xml.Elements().Select((x, i) => i.ToString())
  370. : xml.Elements().Select(x => x.Name.LocalName);
  371. }
  372. /// <summary>Serialize to JsonString</summary>
  373. public override string ToString()
  374. {
  375. // <foo type="null"></foo> is can't serialize. replace to <foo type="null" />
  376. foreach (var elem in xml.Descendants().Where(x => x.Attribute("type").Value == "null"))
  377. {
  378. elem.RemoveNodes();
  379. }
  380. return CreateJsonString(new XStreamingElement("root", CreateTypeAttr(jsonType), xml.Elements()));
  381. }
  382. }
  383. }