using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
using JToken = Newtonsoft.Json.Linq.JToken;
public static partial class JsonExtensions
public static IEnumerable<JsonElement> DescendantPropertyValues(this JsonElement element, string name, StringComparison comparison = StringComparison.Ordinal)
throw new ArgumentNullException();
return DescendantPropertyValues(element, n => name.Equals(n, comparison));
public static IEnumerable<JsonElement> DescendantPropertyValues(this JsonElement element, Predicate<string> match)
throw new ArgumentNullException();
var query = RecursiveEnumerableExtensions.Traverse(
(Name: (string)null, Value: element),
switch (t.Value.ValueKind)
case JsonValueKind.Array:
return t.Value.EnumerateArray().Select(i => ((string)null, i));
case JsonValueKind.Object:
return t.Value.EnumerateObject().Select(p => (p.Name, p.Value));
return Enumerable.Empty<(string, JsonElement)>();
.Where(t => t.Name != null && match(t.Name))
public static partial class RecursiveEnumerableExtensions
public static IEnumerable<T> Traverse<T>(
Func<T, IEnumerable<T>> children, bool includeSelf = true)
var stack = new Stack<IEnumerator<T>>();
stack.Push(children(root).GetEnumerator());
var enumerator = stack.Peek();
if (!enumerator.MoveNext())
yield return enumerator.Current;
stack.Push(children(enumerator.Current).GetEnumerator());
foreach (var enumerator in stack)
public static void Test()
public static void Test(string internalName)
foreach (var jsonString in GetJson())
foreach (var comparison in new [] { StringComparison.Ordinal, StringComparison.OrdinalIgnoreCase })
List<JsonElement> elements;
using (var doc = JsonDocument.Parse(jsonString))
Console.WriteLine("Finding properties named \"{0}\" using {1} in:\n{2}", internalName, comparison, doc.RootElement);
elements = doc.RootElement.DescendantPropertyValues(internalName, comparison)
foreach (var e in elements)
static IEnumerable<string> GetJson()
@"[[{""id"": { ""id"" : 1 },""ID"": { ""ID"" : 1 }}]]",
""header"": ""SVG Viewer"",
{""id"": ""OpenNew"", ""label"": ""Open New""},
{""id"": ""ZoomIn"", ""label"": ""Zoom In""},
{""id"": ""ZoomOut"", ""label"": ""Zoom Out""},
{""id"": ""OriginalView"", ""label"": ""Original View""},
{""id"": ""Find"", ""label"": ""Find...""},
{""id"": ""FindAgain"", ""label"": ""Find Again""},
{""id"": ""CopyAgain"", ""label"": ""Copy Again""},
{""id"": ""CopySVG"", ""label"": ""Copy SVG""},
{""id"": ""ViewSVG"", ""label"": ""View SVG""},
{""id"": ""ViewSource"", ""label"": ""View Source""},
{""id"": ""SaveAs"", ""label"": ""Save As""},
{""id"": ""About"", ""label"": ""About Adobe CVG Viewer...""}
""title"": ""Sample Konfabulator Widget"",
""src"": ""Images/Sun.png"",
""alignment"": ""center""
""data"": ""Click Here"",
""alignment"": ""center"",
""onMouseUp"": ""sun1.opacity = (sun1.opacity / 100) * 90;""
""title"": ""example glossary"",
""GlossTerm"": ""Standard Generalized Markup Language"",
""Abbrev"": ""ISO 8879:1986"",
""para"": ""A meta-markup language, used to create markup languages such as DocBook."",
""GlossSeeAlso"": [""GML"", ""XML""]
public string Json { get; set; }
public string [] IdenticalJson { get; set; }
public string [] DifferentJson { get; set; }
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Assembly.GetName().Name, typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.CodeBase.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];