【问题标题】:How to remove a value from a specific property in a JSON string by matching value?如何通过匹配值从 JSON 字符串中的特定属性中删除值?
【发布时间】:2016-10-05 08:06:30
【问题描述】:

我有一个这样的 JSON 字符串:

{"Country":"USA","States":["Chicago","Miami"]}

public string Remove(string json)
{
    string[] stateFilter = { "Chicago", "Miami"};
    foreach (var state in stateFilter)
    {
        //here I would like to create new copy of json for each state.
        string newJson = {"Country":"USA","States":["Chicago"]}  // Removed Miami from json for Chicago
    }
}

现在我想通过在 JSON 中查找状态并将其从 JSON 字符串中删除来为每个状态创建一个新的 JSON 字符串。因此,每个状态都将包含其新的 JSON 副本,并且不会包含任何其他状态。

例如:Chicago 将在 JSON 中包含 Chicago States 属性。

我正在尝试的代码:

public string Remove(string json)
{
    string[] stateFilter = { "Chicago", "Miami"};
    foreach (var state in stateFilter)
    {
        var jArr = JArray.Parse(json);

        jArr.Descendants().OfType<JProperty>()
            .Where(p => p.Name == state)
            .ToList()
            .ForEach(att => att.Remove());
    }
}

但是上面的代码从 JSON 字符串中移除了属性而不是值。

【问题讨论】:

    标签: c# .net json linq json.net


    【解决方案1】:

    此解决方案基于您的规范:因此每个状态都将包含其新的 json 副本,并且不会包含任何其他状态

    您可以使用Newtonsoft json 序列化器来反序列化 json,为每个状态创建新实例并将它们序列化回 json

    public class States
    {
        public string Country { get; set; }
        public List<string> States { get; set; }        
    }
    
    public IEnumerable<string> GenerateSeparatedListOfStates(string json)
    {
        var original = JsonConvert.DeserializaeObject<States>(json);
    
        foreach(string state in original.States)
        {
            var temp = new States 
            { 
                Country = state.Country,
                States = new List<string> { state }
            }
            yield return JsonConvert.SerializeObject(temp);
        }
    }
    

    【讨论】:

    • 对不起,但实际上我的 json 字符串包含很多属性,但为了简单起见,我没有列出这些属性,因为不需要这就是为什么不将 json 字符串反序列化为类以避免增加不必要的开销的反序列化。不反序列化这可能吗???
    • 如果我理解正确,您希望为 States 数组中的每个状态创建单独的 json。因此,无论如何您都需要为每个州复制您的原始json。反序列化与您尝试手动执行相同的工作 - 读取字符串并创建对象。您在使用序列化方法时是否注意到性能问题/差异?
    • 但正如我所说,我有很多属性,所以我避免创建类并反序列化到类,但现在我意识到如果不反序列化到类是不可能的。对吗?
    • 不反序列化也可以,但是需要自己读取/创建json。而且我不确定“手动”方法会更快或更易读。您只需为 json 的所有属性创建一次 - 然后使用它。有不同的实用程序可以根据 json http://json2csharp.com/ 生成 c# 类
    【解决方案2】:

    您需要将您的 json 反序列化为对象,从 States List 中删除您不需要的对象,然后再次对其进行序列化。

        public class JsonClass
        {
            public string Country { get; set; }
    
            public List<string> States { get; set; }
        }
    
    
        static void Main(string[] args)
        {
            string json = @"{""Country"":""USA"",""States"":[""Chicago"",""Miami""]}";
    
            JsonClass className  = JsonConvert.DeserializeObject<JsonClass>(json);
    
            className.States.Remove("Miami");
    
            Console.WriteLine(JsonConvert.SerializeObject(className));
    
        }
    

    编辑:

    关于您的问题:删除所有没有芝加哥的元素:

    换行:

    className.States.Remove("Miami");
    

    收件人:

    className.States.RemoveAll(x => x != "Chicago");
    

    【讨论】:

    • 对不起,但实际上我的 json 字符串包含很多属性,但为了简单起见,我没有列出这些属性,因为不需要这就是为什么不将 json 字符串反序列化为类以避免增加不必要的开销的反序列化。不反序列化这可能吗???
    • @Learning 那么如果添加所有属性有什么问题呢?这是正确的做法。提示减少错误。
    • 你能说明如何有条件地删除 miami。你已经硬编码了 miami 值。我的状态有一个循环,假设我有 3-4 个状态,那么我如何在删除方法中提供这个条件。你能在你的回答中表明这一点吗?
    • @Learning 可以告诉你要删除哪个State,要删除的状态的确切条件是什么。我不明白删除的要求。举个例子,你有 20 个州,应该删除哪一个,为什么?
    • 假设我正在为芝加哥州创建新的 json,那么我想删除除芝加哥以外的所有其他 19 个州。如果我为迈阿密创建新的 json,那么我想删除所有其他 19 个州除了迈阿密,因为目前我正在为迈阿密创建新的 json
    【解决方案3】:

    我已经阅读了您所有的问题以及其他答案的所有 cmets,坦率地说,我仍然不确定这是否会回答我认为您要问的问题!

    此代码不需要任何外部库,您只需在项目中添加对System.Web.Extensions 的引用即可。

    string jsonString = "{\"Country\":\"USA\",\"States\":[\"Chicago\",\"Miami\"]}";
    var jss = new JavaScriptSerializer();
    dynamic json = jss.DeserializeObject(jsonString);
    var statesToRemove = new object[] { "Chicago", "Miami" };
    object[] originalStates = json["States"] as object[];
    foreach(var state in statesToRemove)
    {
        json["States"] = new[] { state }; 
        string newJson = jss.Serialize(json);
    }
    // Outputs...
    // {"Country":"USA","States":["Chicago"]}
    // {"Country":"USA","States":["Miami"]}
    

    我们将 json 反序列化为对象图并动态遍历它(使用 dynamic - 这就是 json["States"] 甚至编译的方式)。对于 statesToRemove 集合中的每个状态,我们序列化一个新的 json 字符串,并将其作为唯一的状态。

    【讨论】:

      【解决方案4】:

      如果您只是在寻找一种方法来复制 JSON 并仅将 States 数组替换为一个已知状态,您可以这样编写您的方法:

      public static string Remove(string json, string stateToKeep)
      {
          JObject jo = JObject.Parse(json);
          jo["States"] = new JArray(stateToKeep);
          return jo.ToString();
      }
      

      小提琴:https://dotnetfiddle.net/hVz6yF

      如果您想对 States 数组中的所有状态执行此操作,但事先不知道它们是什么,您可以这样做:

      public static string Remove(string json)
      {
          var obj = JObject.Parse(json);
          var result = obj["States"].Select(s =>
          {
              var clone = s.Root.DeepClone();
              clone["States"] = new JArray(s);
              return clone;
          });
          return new JArray(result).ToString();
      }
      

      基本上,我们将 JSON 解析为 JObject,然后使用 Select 遍历状态。对于每个状态,我们克隆整个 JSON,然后将克隆的 States 数组替换为仅包含单个状态的新 JArray。最后,我们将所有这些克隆放入一个新的JArray 并将其转换为字符串。

      鉴于您的原始 JSON,您最终会得到这个新结果:

      [
        {
          "Country": "USA",
          "States": [
            "Chicago"
          ]
        },
        {
          "Country": "USA",
          "States": [
            "Miami"
          ]
        }
      ]
      

      小提琴:https://dotnetfiddle.net/qb4fu0

      【讨论】:

      • 您能否告诉我,将 json 字符串反序列化到类中,然后从中查找和删除数据,然后再次序列化到 json 字符串中,因为上面的 2 个答案正在执行,这之间的性能差异是什么?
      • 我不知道;它可能取决于 JSON 的大小。您必须自己尝试并在您的环境中对其进行测量,以找出性能更好的方法。
      • 实际上 json 的大小很长,就像它包含很多属性一样,但我只关心 State 属性,但仍然支持您为帮助我所做的努力。我真的很感激
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 2019-12-27
      • 2018-01-09
      • 2021-05-19
      • 2022-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多