source: uKadecot/trunk/tools/EcnlControllerUI/EcnlCtrlUI/DynamicJson.cs@ 101

Last change on this file since 101 was 101, checked in by coas-nagasima, 9 years ago

TOPPERS/uKadecotのソースコードを追加

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