I'm trying to dynamically find the names of leaf nodes of a JSON object whose structure isn't known in advance. First, I'm parsing the string into a list of JTokens, like this:
        string req = @"{'creationRequestId':'A',
                        'value':{
                            'amount':1.0,
                            'currencyCode':'USD'
                        }
                        }";
        var tokens = JToken.Parse(req);
Then I'd like to identify which are leaves. In the above example, 'creationRequestId':'A', 'amount':1.0, and 'currencyCode':'USD' are the leaves, and the names are creationRequestId, amount, and currencyCode.
The below example recursively traverses the JSON tree and prints the leaf names:
    public static void PrintLeafNames(IEnumerable<JToken> tokens)
    {
        foreach (var token in tokens)
        {
            bool isLeaf = token.Children().Count() == 1 && !token.Children().First().Children().Any();
            if (token.Type == JTokenType.Property && isLeaf)
            {
                Console.WriteLine(((JProperty)token).Name);
            }
            if (token.Children().Any())
                PrintLeafNames(token.Children<JToken>());
        }
    }
This works, printing:
creationRequestId
amount
currencyCode
However, I'm wondering if there's a less ugly expression for determining whether a JToken is a leaf:
bool isLeaf = token.Children().Count() == 1 && !token.Children().First().Children().Any();
Incidentally, this is a one-liner in XML.
It looks like you've defined a leaf as any JProperty whose value does not have any child values.  You can use the HasValues property on the JToken to help make this determination:
public static void PrintLeafNames(IEnumerable<JToken> tokens)
{
    foreach (var token in tokens)
    {
        if (token.Type == JTokenType.Property)
        {
            JProperty prop = (JProperty)token;
            if (!prop.Value.HasValues)
                Console.WriteLine(prop.Name);
        }
        if (token.HasValues)
            PrintLeafNames(token.Children());
    }
}
Fiddle: https://dotnetfiddle.net/e216YS
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With