Itereate through a jsondocument in a recursive way

Viewed 2930

I need to iterate through an Jsondocument and perform some sort of check depending on the JsonValueKind I encounter.

I tried to do this validation check in such manner

public bool Dec(JsonElement Element)
{

    var ElementEnumeratable = Element.EnumerateObject();

    foreach (var Elm in ElementEnumeratable )
    {
        string name = Elm.Name;
        switch (Elm.Value.ValueKind)
        {
            case JsonValueKind.Array:
                var jArray = Elm.Value;
                return Dec(jArray);
            case JsonValueKind.String:
                string jString = Elm.Value.GetString();
                break;
            case JsonValueKind.Number:
                int jNumber = Elm.Value.GetInt32();
                break;
        }
    }

    return true;
}

Problem here is when Elm has ValueKind array - I cannot pass it to the Dec it seems like JsonElement which has valuekind as array, cannot be converted into an EnumerateObject?

What to do here?

3 Answers

As I understand, if ValueKind is JsonValueKind.Array then you need to iterate array by using EnumerateArray() so that you will have JElement and call Dec foreach element to validate each of them, like this:

public static bool Dec(JsonElement Element)
{

    var ElementEnumeratable = Element.EnumerateObject();

    foreach (var Elm in ElementEnumeratable)
    {
        string name = Elm.Name;
        switch (Elm.Value.ValueKind)
        {
            case JsonValueKind.Array:
                var jArray = Elm.Value;
                foreach (var item in jArray.EnumerateArray())
                {
                    Dec(item);
                }
                break;
            case JsonValueKind.String:
                string jString = Elm.Value.GetString();
                break;
            case JsonValueKind.Number:
                int jNumber = Elm.Value.GetInt32();
                break;
        }
    }

    return true;
}

I think you're doing the switch in the wrong place. If Dec() is called with an Array, it will still call EnumerateObject(). It would need to call EnumerateArray() for an array.

I updated the proposed code this way:

    public static JsonData Decode(JsonElement jsonElement, string elementName = "Root", JsonData parent = null)
    {
        JsonData result = null;
        string jsonString = null;
        double jsonDouble = 0;
        bool jsonBool = false;
        JsonElement jsonArray;

        result = new JsonData(elementName, parent);

        switch (jsonElement.ValueKind)
        {
            case JsonValueKind.Undefined:
                break;

            case JsonValueKind.Object:
                ObjectEnumerator objectEnumerator = jsonElement.EnumerateObject();

                foreach (var item in objectEnumerator)
                {
                    string name = item.Name;
                    switch (item.Value.ValueKind)
                    {
                        case JsonValueKind.Undefined:
                            break;

                        case JsonValueKind.Object:
                            JsonElement element = (JsonElement)item.Value;
                            result.Childrens.Add(Decode(element, name, result));
                            break;

                        case JsonValueKind.Array:
                            jsonArray = item.Value;
                            foreach (var arrayItem in jsonArray.EnumerateArray())
                            {
                                result.Childrens.Add(Decode(arrayItem, name, result));
                            }
                            break;

                        case JsonValueKind.String:
                            jsonString = item.Value.GetString();
                            result.Items.Add(name, jsonString);
                            break;

                        case JsonValueKind.Number:
                            jsonDouble = item.Value.GetDouble();
                            result.Items.Add(name, jsonDouble);
                            break;

                        case JsonValueKind.True:
                            jsonBool = item.Value.GetBoolean();
                            result.Items.Add(name, jsonBool);
                            break;

                        case JsonValueKind.False:
                            jsonBool = item.Value.GetBoolean();
                            result.Items.Add(name, jsonBool);
                            break;

                        case JsonValueKind.Null:
                            result.Items.Add(name, null);
                            break;

                        default:
                            break;
                    }
                }
                break;

            case JsonValueKind.Array:
                jsonArray = jsonElement;
                foreach (var arrayItem in jsonArray.EnumerateArray())
                {
                    result.Items.Add(elementName, arrayItem);
                }
                break;

            case JsonValueKind.String:
                jsonString = jsonElement.GetString();
                result.Items.Add(elementName, jsonString);

                break;
            case JsonValueKind.Number:
                jsonDouble = jsonElement.GetDouble();
                result.Items.Add(elementName, jsonDouble);
                break;

            case JsonValueKind.True:
                jsonBool = jsonElement.GetBoolean();
                result.Items.Add(elementName, jsonBool);
                break;

            case JsonValueKind.False:
                jsonBool = jsonElement.GetBoolean();
                result.Items.Add(elementName, jsonBool);
                break;

            case JsonValueKind.Null:
                result.Items.Add(elementName, null);
                break;

            default:
                break;
        }

        return result;
    }

Returned class is the following one:

public class JsonData
{
    public JsonData Parent { get; private set; }
    public List<JsonData> Childrens { get; private set; }
    public string Name { get; private set; }
    public Dictionary<string, object> Items { get; private set; }

    public JsonData(string name, JsonData parent = null)
    {
        Parent = parent;

        Childrens = new List<JsonData>();

        Name = name;

        Items = new Dictionary<string, object>();
    }

}

Usage:

        JsonDocument jsonDoc = null;
        JsonData jsonData = null;

        string json = File.ReadAllText(@"c:\jsonpath.json");

        if (!string.IsNullOrEmpty(json))
        {
            jsonDoc = JsonDocument.Parse(json, new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip });

            if (jsonDoc != null)
            {
                jsonData = Decode(jsonDoc.RootElement);
            }
        }
        
        if (jsonData != null)
        {
            JsonData financialData = jsonData.Childrens.FirstOrDefault(c => c.Name == "Financial Data");

            if (financialData != null)
            {
                List<JsonData> transactions = financialData.Childrens.Where(c => c.Name == "Transaction history").ToList<JsonData>();
            }
        }
Related