如何通过值查找json令牌然后删除令牌

时间:2018-09-03 12:17:44

标签: c# json json.net

例如,我在C#中有一个像这样的json:

{
"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"
    }
]
}

我想按值从NestedRepetable数组中删除项目。 例如,包含GUID的remove元素:05aa2161-fcc2-45a6-b0b7-8749d94a2e61,所需的结果将类似于:

{
"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"
    }
]
}

我已经在Json.NET的帮助下尝试了几件事,但是我做不到。 请记住,整个JSON结构是动态的。我唯一知道的是这种情况下的字段名称(GUID)和应删除的字段中的值。

我已尝试按照本question中所述的方式进行操作, 但是他们使用的是json的硬编码路径。那不是我的情况。

我使用了以下代码:

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

但是我收到以下错误:

  

集合已修改;枚举操作可能无法执行”

可能是因为我正在尝试删除父元素。

1 个答案:

答案 0 :(得分:1)

您正在尝试查找和删除符合以下条件的对象:

  1. 名为"NestedRepetable"的数组属性包含的所有对象
  2. 具有名为"GUID"且具有特定值的属性。

最简单的方法是将JToken.SelectTokens()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();

如果您实际上不关心对象是否嵌套在"NestedRepetable"中(此时您的问题尚不清楚),您可以这样做

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

注意:

  • ..递归下降运算符。它会返回JToken层次结构并返回所有值。

  • NestedRepetable将具有所需名称的属性值匹配。

  • [?(@.GUID == '{0}')]将属于NestedRepetable数组的对象与具有指定值的名为GUID的属性匹配。

  • 在删除与查询匹配的令牌时,有必要通过调用ToList()来实现查询,以避免出现Collection was modified异常。

  • 有关JSONPath语法的更多信息,请参见JSONPath - XPath for JSON

为复杂查询提供示例工作的.Net小提琴here,为更简单查询提供示例here