PageRenderTime 66ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/ED47.Stack.Web/Json/JsonObject.cs

https://github.com/ed47/ED47.Stack
C# | 418 lines | 326 code | 64 blank | 28 comment | 60 complexity | 365e170ef41e5c2cab21a214c182c276 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics.CodeAnalysis;
  4. using System.Linq;
  5. using System.Runtime.Serialization;
  6. using System.Text.RegularExpressions;
  7. using System.Xml.Linq;
  8. using Newtonsoft.Json;
  9. using Newtonsoft.Json.Linq;
  10. namespace ED47.Stack.Web
  11. {
  12. [Serializable]
  13. [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
  14. public class JsonObject : ISerializable
  15. {
  16. private readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
  17. private JsonObjectSerialization _serializationType = JsonObjectSerialization.DataOnly;
  18. private readonly object _source;
  19. private string _typeName = "";
  20. public JsonObject()
  21. {
  22. }
  23. public JsonObject(string json)
  24. {
  25. if (String.IsNullOrWhiteSpace(json)) return;
  26. JObject obj = JsonConvert.DeserializeObject(json) as JObject;
  27. foreach (var property in obj.Properties())
  28. {
  29. AddProperty(property.Name, property.Value);
  30. }
  31. }
  32. /// <summary>
  33. /// Creates a JsonObject from a XDocument.
  34. /// </summary>
  35. /// <param name="source">The XDocument to build the JsonObject from.</param>
  36. public JsonObject(XDocument source)
  37. {
  38. if (source == null) return;
  39. if (source.Root == null) return;
  40. XmlAddRecursive(source.Root.Elements());
  41. }
  42. /// <summary>
  43. /// Recursively traverse the XDocument and add properties when a bottom element is found.
  44. /// </summary>
  45. /// <param name="elements">The elements to explore.</param>
  46. /// <param name="path">The path to this dept.</param>
  47. private void XmlAddRecursive(IEnumerable<XElement> elements, string path = "")
  48. {
  49. foreach (var element in elements)
  50. {
  51. var nextPath = String.IsNullOrWhiteSpace(path) ? element.Name.ToString() : path + "." + element.Name;
  52. if (element.HasElements)
  53. {
  54. XmlAddRecursive(element.Elements(), nextPath);
  55. }
  56. else
  57. {
  58. AddProperty(nextPath, element.Value);
  59. }
  60. }
  61. }
  62. public JsonObject(object source)
  63. {
  64. if (source == null) return;
  65. _source = source;
  66. dynamic t = new { };
  67. var pps = source.GetType().GetProperties();
  68. foreach (var p in pps)
  69. {
  70. AddProperty(p.Name, p.GetValue(source, null));
  71. }
  72. }
  73. public JsonObjectSerialization SerializationType
  74. {
  75. get { return _serializationType; }
  76. set { _serializationType = value; }
  77. }
  78. public JsonObject Parent { get; set; }
  79. public object Source
  80. {
  81. get { return _source; }
  82. }
  83. public string[] Properties
  84. {
  85. get { return _properties.Keys.ToArray(); }
  86. }
  87. public object this[string propertyName]
  88. {
  89. get
  90. {
  91. if (_properties.ContainsKey(propertyName))
  92. return _properties[propertyName];
  93. if (propertyName == "parent")
  94. return Parent;
  95. return null;
  96. }
  97. set
  98. {
  99. if (_properties.ContainsKey(propertyName))
  100. _properties[propertyName] = value;
  101. else
  102. _properties.Add(propertyName, value);
  103. }
  104. }
  105. public string TypeName
  106. {
  107. get { return _typeName; }
  108. set { _typeName = value; }
  109. }
  110. public void RemoveProperty(string name)
  111. {
  112. if (_properties.ContainsKey(name))
  113. _properties.Remove(name);
  114. }
  115. public bool HasProperty(string propertyName)
  116. {
  117. return _properties.ContainsKey(propertyName) || (Parent != null && propertyName == "parent");
  118. }
  119. public void AddProperty(string name, object value)
  120. {
  121. var jsonObject = value as JsonObject;
  122. if (jsonObject != null)
  123. {
  124. (jsonObject).Parent = this;
  125. }
  126. var jsonObjectList = value as JsonObjectList;
  127. if (jsonObjectList != null)
  128. {
  129. (jsonObjectList).Parent = this;
  130. }
  131. if (_properties.ContainsKey(name))
  132. this[name] = value;
  133. else
  134. _properties.Add(name, value);
  135. }
  136. public static void FindAllChildren(JsonObject obj, List<JsonObject> result)
  137. {
  138. result.Add(obj);
  139. foreach (var p in obj._properties.Values)
  140. {
  141. if (p is JsonObjectList)
  142. {
  143. foreach (JsonObject o in (JsonObjectList)p)
  144. {
  145. FindAllChildren(o, result);
  146. }
  147. }
  148. else if (p is JsonObject)
  149. {
  150. FindAllChildren((JsonObject)p, result);
  151. }
  152. }
  153. }
  154. public List<JsonObject> FindChildrenByRegex(string pattern)
  155. {
  156. var reg = new Regex(pattern);
  157. var result = new List<JsonObject>();
  158. if (String.IsNullOrEmpty(pattern))
  159. {
  160. FindAllChildren(this, result);
  161. }
  162. else
  163. {
  164. FindChildren(this, reg, result);
  165. }
  166. return result;
  167. }
  168. public void Apply(Action<JsonObject> fn)
  169. {
  170. fn(this);
  171. var children = new List<JsonObject>();
  172. FindAllChildren(this, children);
  173. foreach (var o in children)
  174. {
  175. if (o != this)
  176. o.Apply(fn);
  177. }
  178. }
  179. public IEnumerable<TResult> Apply<TResult>(Func<JsonObject,TResult> fn)
  180. {
  181. var res = new List<TResult>();
  182. res.Add(fn(this));
  183. var children = new List<JsonObject>();
  184. FindAllChildren(this, children);
  185. foreach (var o in children)
  186. {
  187. if (o != this)
  188. res.AddRange(o.Apply(fn));
  189. }
  190. return res;
  191. }
  192. [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
  193. private static void FindChildren(JsonObject o, Regex pattern, string path, ref List<JsonObject> result)
  194. {
  195. if (pattern.Match(path).Success)
  196. result.Add(o);
  197. foreach (var k in o._properties.Keys)
  198. {
  199. var p = o._properties[k];
  200. var list = p as JsonObjectList;
  201. if (list != null)
  202. {
  203. foreach (JsonObject obj in list)
  204. {
  205. FindChildren(obj, pattern, path + (!String.IsNullOrEmpty(path) ? "." : "") + k, ref result);
  206. }
  207. }
  208. else
  209. {
  210. var jsonObject = p as JsonObject;
  211. if (jsonObject != null)
  212. {
  213. FindChildren(jsonObject, pattern, path + (!String.IsNullOrEmpty(path) ? "." : "") + k, ref result);
  214. }
  215. }
  216. }
  217. }
  218. public static void FindChildren(JsonObject o, Regex pattern, List<JsonObject> result)
  219. {
  220. FindChildren(o, pattern, "", ref result);
  221. }
  222. /// <summary>
  223. /// Finds the children.
  224. /// </summary>
  225. /// <param name="o">The o.</param>
  226. /// <param name="path">The path to find the children</param>
  227. /// <param name="result">The result list to be filled</param>
  228. [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
  229. public static void FindChildren(JsonObject o, string path, List<JsonObject> result)
  230. {
  231. var i = path.IndexOf(".", System.StringComparison.Ordinal);
  232. if (i > 0)
  233. {
  234. var field = path.Substring(0, i);
  235. var child = o[field];
  236. if (child is JsonObjectList)
  237. {
  238. var col = child as JsonObjectList;
  239. foreach (JsonObject c in col)
  240. {
  241. FindChildren(c, path.Substring(i + 1), result);
  242. }
  243. }
  244. else if (child is JsonObject)
  245. {
  246. FindChildren(child as JsonObject, path.Substring(i + 1), result);
  247. }
  248. }
  249. else
  250. {
  251. var child = o[path];
  252. if (child is JsonObjectList)
  253. {
  254. var col = child as JsonObjectList;
  255. result.AddRange(col.Cast<JsonObject>());
  256. }
  257. else
  258. {
  259. result.Add(child as JsonObject);
  260. }
  261. }
  262. }
  263. /// <summary>
  264. /// Adds and merges an object to the current JsonObject.
  265. /// </summary>
  266. /// <param name="obj">The object to be merge</param>
  267. public void AddObject(JsonObject obj)
  268. {
  269. foreach (var k in obj._properties.Keys.Where(k => !_properties.ContainsKey(k)))
  270. {
  271. this[k] = obj[k];
  272. }
  273. }
  274. private static object GetPropertyValue(object obj, string property)
  275. {
  276. if (obj is JsonObject && ((JsonObject)obj).HasProperty(property))
  277. {
  278. var res = ((JsonObject)obj)[property];
  279. if (res != null)
  280. return res;
  281. }
  282. var pinfo = obj != null ? obj.GetType().GetProperty(property) : null;
  283. if (pinfo != null)
  284. {
  285. return pinfo.GetValue(obj, null);
  286. }
  287. if (property == "this" || property == "values")
  288. {
  289. return obj;
  290. }
  291. return null;
  292. }
  293. /// <summary>
  294. /// Get the value of a property of a child property (with a path like prop1.prop2)
  295. /// </summary>
  296. /// <param name="propertyName">The name or path of the property</param>
  297. /// <param name="dataObject">The data object to explore (by default the current JsonObject)</param>
  298. /// <returns></returns>
  299. public object GetValue(string propertyName, object dataObject = null)
  300. {
  301. var obj = dataObject ?? this;
  302. if (propertyName == "this" || propertyName == ".")
  303. return obj;
  304. var path = propertyName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
  305. if (path.Length == 0)
  306. return obj;
  307. var index = 0;
  308. var child = GetPropertyValue(obj, path[0]);
  309. index++;
  310. var scope = child;
  311. while (index < path.Length)
  312. {
  313. if (child != null)
  314. {
  315. child = GetPropertyValue(child, path[index]);
  316. scope = child ?? scope;
  317. }
  318. else
  319. {
  320. break;
  321. }
  322. index++;
  323. }
  324. //var lastIdent = path[path.Length - 1];
  325. //Match mfunc = new Regex(_RegSimpleFunc).Match(lastIdent);
  326. return child;
  327. }
  328. public override string ToString()
  329. {
  330. return Serialize();
  331. }
  332. private string Serialize()
  333. {
  334. return JsonConvert.SerializeObject(this, Formatting.None);
  335. }
  336. public static object Deserialize(string str)
  337. {
  338. return JsonConvert.DeserializeObject(str);
  339. }
  340. #region ISerializable Membres
  341. protected JsonObject(SerializationInfo info, StreamingContext context)
  342. {
  343. //Deserialize(info.GetString("data"));
  344. }
  345. public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
  346. {
  347. foreach (var property in _properties)
  348. {
  349. info.AddValue(property.Key, property.Value);
  350. }
  351. }
  352. #endregion
  353. }
  354. }