using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public static partial class JsonExtensions
public static TJToken RemoveAllExcept<TJToken>(this TJToken obj, IEnumerable<string> paths) where TJToken : JToken
if (obj == null || paths == null)
throw new NullReferenceException();
var keepers = new HashSet<JToken>(paths.SelectMany(path => obj.SelectTokens(path)), ObjectReferenceEqualityComparer<JToken>.Default);
var keepersAndParents = new HashSet<JToken>(keepers.SelectMany(t => t.AncestorsAndSelf()), ObjectReferenceEqualityComparer<JToken>.Default);
foreach (var token in obj.DescendantsAndSelfReversed().Where(t => !keepersAndParents.Contains(t) && !t.AncestorsAndSelf().Any(p => keepers.Contains(p))))
token.RemoveFromLowestPossibleParent();
public static string SerializeAndSelectTokens<T>(T root, string[] paths, Formatting formatting = Formatting.None, JsonSerializerSettings settings = null)
var obj = JObject.FromObject(root, JsonSerializer.CreateDefault(settings));
obj.RemoveAllExcept(paths);
var json = obj.ToString(formatting);
public static TJToken RemoveFromLowestPossibleParent<TJToken>(this TJToken node) where TJToken : JToken
var property = node.Parent as JProperty;
if (toRemove.Parent != null)
public static IEnumerable<JToken> DescendantsAndSelfReversed(this JToken node)
throw new ArgumentNullException();
return RecursiveEnumerableExtensions.Traverse(node, t => ListReversed(t as JContainer));
static IEnumerable<T> ListReversed<T>(this IList<T> list)
for (int i = list.Count - 1; i >= 0; i--)
public static partial class RecursiveEnumerableExtensions
public static IEnumerable<T> Traverse<T>(
Func<T, IEnumerable<T>> children)
var stack = new Stack<IEnumerator<T>>();
stack.Push((children(root) ?? Enumerable.Empty<T>()).GetEnumerator());
var enumerator = stack.Peek();
if (!enumerator.MoveNext())
yield return enumerator.Current;
stack.Push((children(enumerator.Current) ?? Enumerable.Empty<T>()).GetEnumerator());
foreach (var enumerator in stack)
public class ObjectReferenceEqualityComparer<T> : IEqualityComparer<T>
private static IEqualityComparer<T> _defaultComparer;
public static IEqualityComparer<T> Default
get { return _defaultComparer ?? (_defaultComparer = new ObjectReferenceEqualityComparer<T>()); }
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
return ReferenceEquals(x, y);
public int GetHashCode(T obj)
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
public static void Test()
var root = new RootObject
FirstLevel1 = new FirstLevel
SecondLevel1 = new List<SecondLevel> { new SecondLevel { A = "a11", B = "b11", Third1 = new ThirdLevel { Foo = "Foos11", Bar = "Bars11" }, Third2 = new List<ThirdLevel> { new ThirdLevel { Foo = "FooList11", Bar = "BarList11" } } } },
SecondLevel2 = new List<SecondLevel> { new SecondLevel { A = "a12", B = "b12", Third1 = new ThirdLevel { Foo = "Foos12", Bar = "Bars12" }, Third2 = new List<ThirdLevel> { new ThirdLevel { Foo = "FooList12", Bar = "BarList12" } } } },
FirstLevel2 = new FirstLevel
SecondLevel1 = new List<SecondLevel> { new SecondLevel { A = "a21", B = "b21", Third1 = new ThirdLevel { Foo = "Foos21", Bar = "Bars21" }, Third2 = new List<ThirdLevel> { new ThirdLevel { Foo = "FooList21", Bar = "BarList21" } } } },
SecondLevel2 = new List<SecondLevel> { new SecondLevel { A = "a22", B = "b22", Third1 = new ThirdLevel { Foo = "Foos22", Bar = "Bars22" }, Third2 = new List<ThirdLevel> { new ThirdLevel { Foo = "FooList22", Bar = "BarList22" } } } },
Assert.IsTrue(JObject.FromObject(root).DescendantsAndSelf().OfType<JValue>().Count() == 24);
var paths1 = new string[]
"$.FirstLevel2.SecondLevel1[*].A",
"$.FirstLevel1.SecondLevel2[*].Third2[*].Bar",
var paths3 = new string[]
"$.FirstLevel1.SecondLevel2[*].Third2[*].Bar",
var paths4 = new string[]
"$.*.SecondLevel2[*].Third2[*].Bar",
static void Test<T>(T root, string [] paths, int expectedCount)
var json = JsonExtensions.SerializeAndSelectTokens(root, paths, Formatting.Indented);
Console.WriteLine("Result using paths: {0}", JsonConvert.SerializeObject(paths));
Assert.IsTrue(JObject.Parse(json).DescendantsAndSelf().OfType<JValue>().Count() == expectedCount);
public string Foo { get; set; }
public string Bar { get; set; }
public ThirdLevel Third1 { get; set; }
public List<ThirdLevel> Third2 { get; set; }
public string A { get; set; }
public string B { get; set; }
public List<SecondLevel> SecondLevel1 { get; set; }
public List<SecondLevel> SecondLevel2 { get; set; }
public FirstLevel FirstLevel1 { get; set; }
public FirstLevel FirstLevel2 { get; set; }
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: ");