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> where T : class
private static readonly IEqualityComparer<T> _defaultComparer;
static ObjectReferenceEqualityComparer() { _defaultComparer = new ObjectReferenceEqualityComparer<T>(); }
public static IEqualityComparer<T> Default { get { return _defaultComparer; } }
#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 input = JObject.Parse(GetInputJson());
input.RemoveAllExcept(new []
"employee[*].project[*].projectname",
"employee[*].fullname.firstname",
Console.WriteLine(input);
var expectedJson = JToken.Parse(GetExpectedJson());
Assert.IsTrue(JToken.DeepEquals(input, expectedJson));
static string GetInputJson()
""projectname"":""abcd_1"",
""datejoined"": ""2019-06-18T01:29:38.6013262+00:00"",
""projectmanager"": ""abcdM1"",
""projectname"":""abcd_2"",
""datejoined"": ""2018-06-18T01:29:38.6013262+00:00"",
""projectmanager"": ""abcdM2"",
""projectname"":""abcd_3"",
""datejoined"": ""2017-06-18T01:29:38.6013262+00:00"",
""projectmanager"": ""abcdM3"",
""projectname"":""abcd_1"",
""datejoined"": ""2019-06-18T01:29:38.6013262+00:00"",
""projectmanager"": ""abcdM1"",
""projectname"":""abcd_2"",
""datejoined"": ""2018-06-18T01:29:38.6013262+00:00"",
""projectmanager"": ""abcdM2"",
""projectname"":""abcd_3"",
""datejoined"": ""2017-06-18T01:29:38.6013262+00:00"",
""projectmanager"": ""abcdM3"",
static string GetExpectedJson()
""projectname"":""abcd_1"",
""projectname"":""abcd_2"",
""projectname"":""abcd_3"",
""projectname"":""abcd_1"",
""projectname"":""abcd_2"",
""projectname"":""abcd_3"",
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: ");