How to find json token by value and then delete the token

人走茶凉 提交于 2021-01-27 21:22:18

问题


I have, for example, a json like this in C# :

{
"Harry.firstName": "Harry",
"Harry.lastName": "Birimirski",
"Harry.recordTitle": "My title",
"Harry.SomeRepeatable": [{
        "GUID": "9dd8c7bb-64e1-452b-90d5-db2b6e505492",
        "NestedRepetable": [{
                "GUID": "05aa2161-fcc2-45a6-b0b7-8749d94a2e61",
                "nestedText": "Nested first"
            },
            {
                "GUID": "dfd67eeb-703b-4cc4-9321-b6a39084e687",
                "nestedText": "Nested first 2"
            }
        ],
        "name": "First"
    },
    {
        "GUID": "3318e544-1be8-4795-9bab-fa05de79cf46",
        "NestedRepetable": [{
            "GUID": "c1b60869-7c75-4af4-8037-be26aeca7939",
            "nestedText": "Nested second"
        }],
        "name": "Second"
    }
]
}

And I would like to remove item from NestedRepetable array by value. For example remove element that contains GUID: 05aa2161-fcc2-45a6-b0b7-8749d94a2e61, desired result will looks like :

{
"Harry.firstName": "Harry",
"Harry.lastName": "Birimirski",
"Harry.recordTitle": "My title",
"Harry.SomeRepeatable": [{
        "GUID": "9dd8c7bb-64e1-452b-90d5-db2b6e505492",
        "NestedRepetable": [
            {
                "GUID": "dfd67eeb-703b-4cc4-9321-b6a39084e687",
                "nestedText": "Nested first 2"
            }
        ],
        "name": "First"
    },
    {
        "GUID": "3318e544-1be8-4795-9bab-fa05de79cf46",
        "NestedRepetable": [{
            "GUID": "c1b60869-7c75-4af4-8037-be26aeca7939",
            "nestedText": "Nested second"
        }],
        "name": "Second"
    }
]
}

I've tried a couple of things with the help of Json.NET, but I cannot do it. Keep in mind that the whole JSON structure is dynamic. The only thing that I know is the field name (GUID) in this case and the value in the field, that should be removed.

I've tried to do it in that way described in this question, But they are using a hardcoded path of the json. That's not my case.

I've used the following code :

        private JToken RemoveFields(JToken token, string fieldValue)
    {
        JContainer container = token as JContainer;
        if (container == null)
        {
            return token;
        }

        List<JToken> removeList = new List<JToken>();
        foreach (JToken el in container.Children())
        {
            JProperty p = el as JProperty;
            if (p != null)// && fields.Contains(p.Name))
            {
                if (p.Value.ToString() == fieldValue)
                {
                    removeList.Add(el);

                    //try to remove the whole thing, not only GUID field ..
                    //removeList.Add(el.Parent);

                }
            }

            RemoveFields(el, fieldValue);
        }

        foreach (JToken el in removeList)
        {
            el.Parent.Remove();
            return token;
        }

        return token;
    }

But I'm receiving the following error :

Collection was modified; enumeration operation may not execute"

Probably because I'm trying to remove the parent element.


回答1:


You are attempting to find and remove objects that match the following criteria:

  1. All objects contained by an array property named "NestedRepetable"
  2. that have a property named "GUID" with a specific value.

The easiest way to do this will be to use JToken.SelectTokens() with a JSONPath query:

var value = "05aa2161-fcc2-45a6-b0b7-8749d94a2e61";

var queryStringTemplate = "..NestedRepetable[?(@.GUID == '{0}')]";
var query = root.SelectTokens(string.Format(queryStringTemplate, value));

foreach (var obj in query.ToList())
    obj.Remove();

If you don't actually care whether the objects are nested inside "NestedRepetable" (your question is unclear on this point) you can just do

var queryStringTemplate = "..[?(@.GUID == '{0}')]";

Notes:

  • .. is the recursive descent operator. It descends the JToken hierarchy returning all values.

  • NestedRepetable matches values of properties with the required name.

  • [?(@.GUID == '{0}')] matches objects belonging to the NestedRepetable array with a property named GUID with the specified value.

  • When removing tokens that match the query, it is necessary to materialize the query by calling ToList() to avoid the Collection was modified exception you are seeing.

  • For more on JSONPath syntax see JSONPath - XPath for JSON.

Sample working .Net fiddle here for the complex query and here for the simpler query.



来源:https://stackoverflow.com/questions/52149657/how-to-find-json-token-by-value-and-then-delete-the-token

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!