Amit Anand
Amit Anand

Reputation: 1109

Find value of a property from a Nested JSON without recursion in C#

I want to find the value of a property from a nested JSON data. I have a a recursive approach of doing this using the following methods and it works well. Is there a way I can convert this to an Iterative method. The code snippet is as follows --

    public static class JsonExtensions
    {
        /// <summary>
        /// Finds the value of a JToken from the given JSON data for the given property name.
        /// If the resultant JToken have multiple occurrence at different levels of JSON data the this methods returns the first or default.
        /// </summary>
        /// <param name="containerToken">Given JSON data.</param>
        /// <param name="propertyName">Property name whose value needs to be find.</param>
        /// <returns></returns>
        public static string FindJToken(this JToken containerToken, string propertyName)
        {
            if (containerToken == null)
            {
                throw new ArgumentNullException(nameof(containerToken));
            }

            if (string.IsNullOrWhiteSpace(propertyName))
            {
                throw new ArgumentException("Parameter Cannot be Null, Empty or White spaces.", nameof(propertyName));
            }

            List<JToken> matches = new List<JToken>();
            GetJTokenValue(containerToken, propertyName, matches);
            return matches.FirstOrDefault()?.ToString();
        }

        /// <summary>
        /// Recursive method to find value of the given JToken / property name from the given JSON
        /// </summary>
        /// <param name="containerToken">Given JSON data</param>
        /// <param name="propertyName">Property name whose value needs to be find.</param>
        /// <param name="matches">List of matching tokens</param>
        private static void GetJTokenValue(JToken containerToken, string propertyName, List<JToken> matches)
        {
            if (containerToken.Type == JTokenType.Object)
            {
                foreach (JProperty child in containerToken.Children<JProperty>())
                {
                    if (child.Name == propertyName)
                    {
                        matches.Add(child.Value);
                    }
                    GetJTokenValue(child.Value, propertyName, matches);
                }
            }
            else if (containerToken.Type == JTokenType.Array)
            {
                foreach (JToken child in containerToken.Children())
                {
                    GetJTokenValue(child, propertyName, matches);
                }
            }
        }
}

I want to convert the method GetJTokenValue() as an iterator and change the matches into IEnumerable so that I can avoid recursion and reduce the complexity . Any help will be appreciated.

Thanks and Regards,

Amit Anand

Upvotes: 0

Views: 712

Answers (1)

Davey van Tilburg
Davey van Tilburg

Reputation: 718

Have you tried using JsonPath? I find it very useful for these sorts of situations.

You didn't really give a source example so I just made up something simple:

//{
//  "ToBeFound": "test",
//  "lala": [
//    {
//     "ToBeFound": "test"
//    },
//    {
//     "NotToBeFound": "test2"
//    }
//  ]
//}

var source = JToken.Parse(@"{ ""ToBeFound"": ""test"", ""lala"": [ { ""ToBeFound"": ""test"" }, { ""NotToBeFound"": ""test2"" } ] }");

var results = source.SelectTokens("$..ToBeFound");

foreach(JToken result in results)
    Console.WriteLine(result.Value<string>());

See it run: https://dotnetfiddle.net/zoH7FQ

Hope this helps you!

Upvotes: 1

Related Questions