https://stackoverflow.com/questions/60994574/extract-all-jsonvalues-for-a-reappearing-jsonproperty-in-a-json

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Data;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Reflection;
using System.Collections.ObjectModel;

using System.Text.Json;
using System.Text.Json.Serialization;

using NUnit.Framework; // Throws NUnit.Framework.AssertionException

using JToken = Newtonsoft.Json.Linq.JToken;

//https://stackoverflow.com/questions/60994574/extract-all-jsonvalues-for-a-reappearing-jsonproperty-in-a-json

	public static partial class JsonExtensions
	{
		public static IEnumerable<JsonElement> DescendantPropertyValues(this JsonElement element, string name, StringComparison comparison = StringComparison.Ordinal)
		{
			if (name == null)
				throw new ArgumentNullException();
			return DescendantPropertyValues(element, n => name.Equals(n, comparison));
		}
		
		public static IEnumerable<JsonElement> DescendantPropertyValues(this JsonElement element, Predicate<string> match)
		{
			if (match == null)
				throw new ArgumentNullException();
			var query = RecursiveEnumerableExtensions.Traverse(
				(Name: (string)null, Value: element),
				t => 
				{
					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));
						default:
							return Enumerable.Empty<(string, JsonElement)>();
					}
				}, false)
				.Where(t => t.Name != null && match(t.Name))
				.Select(t => t.Value);
			return query;
		}
	}

    public static partial class RecursiveEnumerableExtensions
    {
        // Rewritten from the answer by Eric Lippert https://stackoverflow.com/users/88656/eric-lippert
        // to "Efficient graph traversal with LINQ - eliminating recursion" https://stackoverflow.com/questions/10253161/efficient-graph-traversal-with-linq-eliminating-recursion
        // to ensure items are returned in the order they are encountered.
        public static IEnumerable<T> Traverse<T>(
            T root,
            Func<T, IEnumerable<T>> children, bool includeSelf = true)
        {
			if (includeSelf)
	            yield return root;
            var stack = new Stack<IEnumerator<T>>();
            try
            {
                stack.Push(children(root).GetEnumerator());
                while (stack.Count != 0)
                {
                    var enumerator = stack.Peek();
                    if (!enumerator.MoveNext())
                    {
                        stack.Pop();
                        enumerator.Dispose();
                    }
                    else
                    {
                        yield return enumerator.Current;
                        stack.Push(children(enumerator.Current).GetEnumerator());
                    }
                }
            }
            finally
            {
                foreach (var enumerator in stack)
                    enumerator.Dispose();
            }
        }
    }

    class TestClass
    {
        public static void Test()
        {
			Test("id");
		}
		
        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)
							.Select(e => e.Clone()) // Clone the elements before disposing the JsonDocument
							.ToList();              // Materialize the query before disposing the JsonDocument
					}

					foreach (var e in elements)
					{
						Console.WriteLine(e);
					}
				}
			}
		}	
		
		static IEnumerable<string> GetJson()
		{
			var tests = new []
			{
				@"[[{""id"": { ""id"" : 1 },""ID"": { ""ID"" : 1 }}]]",
				@"null",
				@"[[[[]]]]",
				@"{""menu"": {
    ""header"": ""SVG Viewer"",
    ""items"": [
        {""id"": ""Open""},
        {""id"": ""OpenNew"", ""label"": ""Open New""},
        null,
        {""id"": ""ZoomIn"", ""label"": ""Zoom In""},
        {""id"": ""ZoomOut"", ""label"": ""Zoom Out""},
        {""id"": ""OriginalView"", ""label"": ""Original View""},
        null,
        {""id"": ""Quality""},
        {""id"": ""Pause""},
        {""id"": ""Mute""},
        null,
        {""id"": ""Find"", ""label"": ""Find...""},
        {""id"": ""FindAgain"", ""label"": ""Find Again""},
        {""id"": ""Copy""},
        {""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""},
        null,
        {""id"": ""Help""},
        {""id"": ""About"", ""label"": ""About Adobe CVG Viewer...""}
    ]
}}",
				@"{""widget"": {
    ""debug"": ""on"",
    ""window"": {
        ""title"": ""Sample Konfabulator Widget"",
        ""id"": ""main_window"",
        ""width"": 500,
        ""height"": 500
    },
    ""image"": { 
        ""src"": ""Images/Sun.png"",
        ""id"": ""sun1"",
        ""hOffset"": 250,
        ""vOffset"": 250,
        ""alignment"": ""center""
    },
    ""text"": {
        ""data"": ""Click Here"",
        ""size"": 36,
        ""style"": ""bold"",
        ""id"": ""text1"",
        ""hOffset"": 250,
        ""vOffset"": 100,
        ""alignment"": ""center"",
        ""onMouseUp"": ""sun1.opacity = (sun1.opacity / 100) * 90;""
    }
}}    ",
				@"{
    ""glossary"": {
        ""title"": ""example glossary"",
		""GlossDiv"": {
            ""title"": ""S"",
			""GlossList"": {
                ""GlossEntry"": {
                    ""ID"": ""SGML"",
					""SortAs"": ""SGML"",
					""GlossTerm"": ""Standard Generalized Markup Language"",
					""Acronym"": ""SGML"",
					""Abbrev"": ""ISO 8879:1986"",
					""GlossDef"": {
                        ""para"": ""A meta-markup language, used to create markup languages such as DocBook."",
						""GlossSeeAlso"": [""GML"", ""XML""]
                    },
					""GlossSee"": ""markup""
                }
            }
        }
    }
}",
			};
			return tests;
		}
	}

	class JsonTestCase
	{
		public string Json { get; set; }
		public string [] IdenticalJson { get; set; }
		public string [] DifferentJson { get; set; }
	}

	public class Program
	{
		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();

			try
			{
				TestClass.Test();
			}
			catch (Exception ex)
			{
				Console.WriteLine("Failed with unhandled exception: ");
				Console.WriteLine(ex);
				throw;
			}
		}
		
		public static string GetNetCoreVersion()
		{
			//https://techblog.dorogin.com/how-to-detect-net-core-version-in-runtime-ecd65ad695be
			//
			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];
			return null;
		}
	}
;