【问题标题】:How to find json token by value and then delete the token如何按值查找json令牌然后删除令牌
【发布时间】:2018-09-04 01:05:25
【问题描述】:

例如,我在 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 的元素: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;
    }

但我收到以下错误:

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

可能是因为我试图删除父元素。

【问题讨论】:

  • 如果只是一击,您可以在移除对象后返回。由于您使用的是迭代器(foreach 执行此操作),因此您无法在迭代时添加或删除项目,这会导致问题。那么在拆除工作后返回吗?
  • 您指向的示例在迭代完成后进行删除。因为您正在递归调用该函数,所以最有可能发生的是它完成了内部迭代并尝试删除一些元素,而外部迭代仍在进行中。尝试构建要删除的项目列表,然后确保删除它们在任何 JSON 遍历之外
  • 您是否尝试将ToList() 添加到您的removeList 迭代中?够了吗?
  • ToList() 对我不起作用,它返回整个令牌,没有从数组中删除元素。我同意你们所有人的看法 - 问题是集合已被修改,但我无法找到返回正确结果的方法。
  • this answer 之类的东西似乎接近您想要的,即删除具有特定值的 "GUID" 属性的对象。

标签: c# json json.net


【解决方案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 fiddle here 用于复杂查询,here 用于简单查询。

【讨论】:

  • 这样就行了,非常感谢!不同的方法,但更清晰的解决方案。看来我必须花一些时间才能更好地理解 JSONPath。
猜你喜欢
  • 2019-02-08
  • 2016-06-12
  • 1970-01-01
  • 1970-01-01
  • 2017-03-29
  • 2014-04-28
  • 2021-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多