CSharp · Console
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;
}
}