kafka
kafka

Reputation: 733

Iterate through a JsonDocument in a recursive way

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?

Upvotes: 7

Views: 5789

Answers (3)

Selim Yildiz
Selim Yildiz

Reputation: 5380

As I understand, if ValueKind is JsonValueKind.Array then you need to iterate array by using EnumerateArray() so that you will have JsonElement 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;
}

Upvotes: 7

Nodial Tone
Nodial Tone

Reputation: 31

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>();
            }
        }

Upvotes: 2

Richard
Richard

Reputation: 613

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.

Upvotes: 0

Related Questions