4

我有一个带有类似 JSON 的 JObject:

{"name" : "user1", "groups" : ["group 1", "group2"]}

我想按名称删除一组。所以我有这样的代码:

JObject userJson = JObject.Parse(user);

JArray groups = userJson["groups"] as JArray;
JToken group = new JValue (groupName);

groups.Remove(group);

但是方法 JArray.remove(Jtoken item) 返回 false (这意味着它不能被删除)。这里的信息:

https://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Linq_JArray_Remove.htm

所以尝试设置参数JToken group = new JValue (groupName); JToken group = new JValue (groupName); as JTokenJValue group = new JValue (groupName);但它不起作用:S

这个人很好地解释了 JToken 层次结构,但我不知道我做错了什么。

https://stackoverflow.com/a/38560188/8849646

4

2 回答 2

10

基本问题是JToken层次结构是双连通图。也就是说,每个令牌都知道它Parent,每个父代都知道它Children。实际上,如果您将已经有父代的令牌添加到父代,它会被克隆,如此所述。

因此,由于每个令牌都知道其父级,因此当您尝试从父级移除令牌时,Json.NET 可能会执行以下两种操作之一:

  1. 如果孩子实际上属于父母(使用引用相等),它可能会从父母中删除孩子,或者
  2. 如果子项具有作为父项的某个子项的保存值,它可能会从父项中删除子项。

而且,事实上,Json.NET 选择了前一个选项。 Jarray.Remove(JToken item)调用JContainer.RemoveItem()which 调用JArray.IndexOfItem()以确定要删除的项目的索引。反过来,此方法使用引用相等:

internal override int IndexOfItem(JToken item)
{
    return _values.IndexOfReference(item);
}

由于您的JToken group = new JValue (groupName)不属于JArray groups,因此不会将其删除。

那么,您有哪些按值删除 JSON 数组项的选项?你可以:

  • 使用 LINQ 搜索:

    groups.Where(i => i.Type == JTokenType.String && (string)i == groupName).ToList().ForEach(i => i.Remove());
    
  • Search using JTokenEqualityComparer,可用于搜索复杂对象以及原始值:

    var comparer = new JTokenEqualityComparer();
    groups.Where(i => comparer.Equals(i, group)).ToList().ForEach(i => i.Remove());
    
  • 使用搜索SelectTokens()

    userJson.SelectTokens(string.Format("groups[?(@ == '{0}')]", groupName)).ToList().ForEach(i => i.Remove());
    

    SelectTokens()支持JSONPath 查询语法,可以通过数组搜索匹配项。

最后,关于. RemoveItem()它指出(添加斜体):

JArray.Remove Method (JToken)

从 JArray 中删除特定对象的第一个匹配项。

由于我们已经看到具有父代的令牌在添加到父代时会被克隆,因此在给定的父代中似乎只能出现一次任何令牌。然而,文档似乎另有暗示;我会大胆猜测这个特定的文档语句已经过时,并且可以追溯到一些更早的 Json.NET 版本,其中相同的标记可能多次出现在父级中。

于 2017-12-15T05:03:35.777 回答
0
//Removing obj from oldArray
private static JArray RemoveValue(JArray oldArray, dynamic obj)
{
    List<string> temp2 = oldArray.ToObject<List<string>>();
    temp2.Remove(obj); 
    return JArray.FromObject(temp2);
}
于 2018-02-11T18:56:54.480 回答