using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.ComponentModel;
using System.Collections.ObjectModel;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public abstract partial class KeyItemBase : INotifyPropertyChanged
public KeyItemBase() : this(null, Enumerable.Empty<KeyItemBase>()) { }
public KeyItemBase(string key, IEnumerable<KeyItemBase> children)
this.m_children = new ObservableCollection<KeyItemBase>(children);
RaisedOnPropertyChanged("key");
ObservableCollection<KeyItemBase> m_children;
public ObservableCollection<KeyItemBase> Children { get { return m_children; } }
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisedOnPropertyChanged(string _PropertyName)
var changed = PropertyChanged;
changed(this, new PropertyChangedEventArgs(_PropertyName));
public abstract partial class KeyItemBase
public bool ShouldSerializeChildren() { return Children != null && Children.Count > 0; }
public sealed class KeyItem : KeyItemBase
public KeyItem() : base() { }
public KeyItem(string key, IEnumerable<KeyItemBase> children) : base(key, children) { }
public class KeyIdItem : KeyItemBase
public KeyIdItem() : base() { }
public KeyIdItem(string key, IEnumerable<KeyItemBase> children, long t_id) : base(key, children) { this.m_id = t_id; }
RaisedOnPropertyChanged("T_id");
public static class KeyItemFactory
public static KeyItemBase ToKeyObject(string name, long? id, IEnumerable<KeyItemBase> children)
return new KeyItem(name, children);
return new KeyIdItem(name, children, id.Value);
public static IEnumerable<KeyItemBase> ToKeyObjects(JToken root)
return root.TopDescendantsWhere<JObject>(o => true)
.Select(o => ToKeyObject(((JProperty)o.Parent).Name, (long?)o["T_id"], ToKeyObjects(o)));
public static partial class JsonExtensions
public static IEnumerable<TJToken> TopDescendantsWhere<TJToken>(this JToken root, Func<TJToken, bool> predicate) where TJToken : JToken
throw new ArgumentNullException();
return GetTopDescendantsWhere<TJToken>(root, predicate, false);
static IEnumerable<TJToken> GetTopDescendantsWhere<TJToken>(JToken root, Func<TJToken, bool> predicate, bool includeSelf) where TJToken : JToken
var currentOfType = root as TJToken;
if (currentOfType != null && predicate(currentOfType))
yield return currentOfType;
var rootContainer = root as JContainer;
if (rootContainer == null)
var current = root.First;
var currentOfType = current as TJToken;
var isMatch = currentOfType != null && predicate(currentOfType);
yield return currentOfType;
var next = (isMatch ? null : current.FirstChild());
for (var parent = current.Parent; parent != null && parent != root && next == null; parent = parent.Parent)
static JToken FirstChild(this JToken token)
var container = token as JContainer;
return container == null ? null : container.First;
public static void Test()
var root = JToken.Parse(json);
var items = new ObservableCollection<KeyItemBase>(KeyItemFactory.ToKeyObjects(root));
var newJson = JsonConvert.SerializeObject(items, Formatting.Indented);
Console.WriteLine("Output ObservableCollection<KeyObjectBase>: ");
Console.WriteLine(newJson);
Console.WriteLine("\nInput JSON: ");
""T_state"":""Runnerups""
//many more nested n-levels
public static void Main()
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");