Thankfully JIRA provides a REST web-service interface which after a bit of googling and working through their sparse online documentation managed to get me the calls I needed. The only downside is that they did not offer an XML based response from the REST queries that I would have hoped and only provided JSON instead.
So, looking at most of the mappings avaibale in C# these all had as expected JSON to object mappings. This was a bit more tedious than what I needed as the intention was only to have a quick script that I could run, process the data and dump into a CSV that I can then re-work in Excel. So, I had the search for something simpler to parse the JSON response.
After a bit of searching I turned up a link to Shawn Weisfeld who was using dynamic to parse JSON building on work from a few others. He's got a pretty good description of his thinking and how to use the code. I then looked at the modification by Drew Noakes in his StackOverflow posting.
In the end to make this work I had to hack about and change two of the private members to public. I know it's hacky, but this was a quick job and the script was secondary to the work I needed to do on the data. Anyway, here's what I used (as much for myself next time I need it!):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Dynamic; using System.Linq; using System.Text; using System.Web.Script.Serialization; using System.Xml; using System.Xml.Linq; namespace JSONProcess { public sealed class DynamicJsonConverter : JavaScriptConverter { public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) { if (dictionary == null) throw new ArgumentNullException("dictionary"); return type == typeof(object) ? new DynamicJsonObject(dictionary) : null; } public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) { throw new NotImplementedException(); } public override IEnumerable<Type> SupportedTypes { get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); } } #region Nested type: DynamicJsonObject //private sealed class DynamicJsonObject : DynamicObject public sealed class DynamicJsonObject : DynamicObject { //private readonly IDictionary<string, object> _dictionary; public readonly IDictionary<string, object> _dictionary; public DynamicJsonObject(IDictionary<string, object> dictionary) { if (dictionary == null) throw new ArgumentNullException("dictionary"); _dictionary = dictionary; } public override string ToString() { var sb = new StringBuilder("{"); ToString(sb); return sb.ToString(); } private void ToString(StringBuilder sb) { var firstInDictionary = true; foreach (var pair in _dictionary) { if (!firstInDictionary) sb.Append(","); firstInDictionary = false; var value = pair.Value; var name = pair.Key; if (value is string) { sb.AppendFormat("{0}:\"{1}\"", name, value); } else if (value is IDictionary<string, object>) { new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb); } else if (value is ArrayList) { sb.Append(name + ":["); var firstInArray = true; foreach (var arrayValue in (ArrayList)value) { if (!firstInArray) sb.Append(","); firstInArray = false; if (arrayValue is IDictionary<string, object>) new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb); else if (arrayValue is string) sb.AppendFormat("\"{0}\"", arrayValue); else sb.AppendFormat("{0}", arrayValue); } sb.Append("]"); } else { sb.AppendFormat("{0}:{1}", name, value); } } sb.Append("}"); } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (!_dictionary.TryGetValue(binder.Name, out result)) { // return null to avoid exception. caller can check for null this way... result = null; return true; } result = WrapResultObject(result); return true; } public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { if (indexes.Length == 1 && indexes[0] != null) { if (!_dictionary.TryGetValue(indexes[0].ToString(), out result)) { // return null to avoid exception. caller can check for null this way... result = null; return true; } result = WrapResultObject(result); return true; } return base.TryGetIndex(binder, indexes, out result); } private static object WrapResultObject(object result) { var dictionary = result as IDictionary<string, object>; if (dictionary != null) return new DynamicJsonObject(dictionary); var arrayList = result as ArrayList; if (arrayList != null && arrayList.Count > 0) { return arrayList[0] is IDictionary<string, object> ? new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x))) : new List<object>(arrayList.Cast<object>()); } return result; } } #endregion } }
Using this then was pretty easy, like below. I'll cover more in parsing the JIRA specifics as an example in another post.
JavaScriptSerializer jss = new JavaScriptSerializer(); jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() }); DynamicJsonConverter.DynamicJsonObject j = jss.Deserialize(json, typeof(object)) as DynamicJsonConverter.DynamicJsonObject; dynamic d = jss.Deserialize(json, typeof(object)) as dynamic;
No comments:
Post a Comment