根据C#中的条件从JSON中删除元素

时间:2012-11-20 17:31:28

标签: c# json json.net

我有一个JSON字符串,我希望能够在C#中修改。我希望能够根据其中一个子值是特定值来删除一组数据。

采取以下

 {
  "responseHeader":{
    "status":0,
    "QTime":0,
    "params":{
      "explainOther":"",
      "fl":"*,score",
      "indent":"on",
      "start":"0",
      "q":"*:*",
      "hl.fl":"",
      "qt":"",
      "wt":"json",
      "fq":"",
      "version":"2.2",
      "rows":"2"}
  },
  "response":{"numFound":2,"start":0,"maxScore":1.0,"docs":
  [{
        "id":"438500feb7714fbd9504a028883d2860",
        "name":"John",
        "dateTimeCreated":"2012-02-07T15:00:42Z",
        "dateTimeUploaded":"2012-08-09T15:30:57Z",
        "score":1.0
   },
   {
        "id":"2f7661ae3c7a42dd9f2eb1946262cd24",
        "name":"David",
        "dateTimeCreated":"2012-02-07T15:02:37Z",
        "dateTimeUploaded":"2012-08-09T15:45:06Z",
        "score":1.0
    }]
 }}

上面显示了两个响应结果。我希望能够在其子“id”值匹配时删除整个父响应结果组,例如,如果我的id是“2f7661ae3c7a42dd9f2eb1946262cd24”,我希望删除第二组,因此我的结果将如下所示

{
  "responseHeader":{
    "status":0,
    "QTime":0,
    "params":{
      "explainOther":"",
      "fl":"*,score",
      "indent":"on",
      "start":"0",
      "q":"*:*",
      "hl.fl":"",
      "qt":"",
      "wt":"json",
      "fq":"",
      "version":"2.2",
      "rows":"2"}},
  "response":{"numFound":2,"start":0,"maxScore":1.0,"docs":[
  {
        "id":"438500feb7714fbd9504a028883d2860",
        "name":"John",
        "dateTimeCreated":"2012-02-07T15:00:42Z",
        "dateTimeUploaded":"2012-08-09T15:30:57Z",
        "score":1.0
    }]
  }}

我需要对Json文件执行多个删除操作。 Json文件可能包含数千个结果,我真的需要尽可能最高效的方式。

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:3)

var jObj = (JObject)JsonConvert.DeserializeObject(json);
HashSet<string> idsToDelete = new HashSet<string>() { "2f7661ae3c7a42dd9f2eb1946262cd24" };

jObj["response"]["docs"]
    .Where(x => idsToDelete.Contains((string)x["id"]))
    .ToList()
    .ForEach(doc=>doc.Remove());

var newJson = jObj.ToString();

答案 1 :(得分:3)

我一直试图在过去10分钟左右将其压缩成更好的LINQ语句,但事实上已知的ID列表本身就在改变每个元素的评估方式,这意味着我可能不会要做到这一点。

        var jObj = (JObject)JsonConvert.DeserializeObject(json);
        var docsToRemove = new List<JToken>();
        foreach (var doc in jObj["response"]["docs"])
        {
            var id = (string)doc["id"];
            if (knownIds.Contains(id))
            {
                docsToRemove.Add(doc);
            }
            else
            {
                knownIds.Add(id);
            }
        }
        foreach (var doc in docsToRemove)
            doc.Remove();

这似乎适合我旋转测试的糟糕的小控制台应用程序,但我的测试仅限于上面的示例数据,所以如果有任何问题继续并留下评论,以便我可以修复它们。

对于它的价值,这将基本上以线性时间运行,相对于你提供多少元素,这可能会让你获得更多的算法性能而不会对这个问题感到惊讶。使用任务并行库调用将处理其自己的小页面并返回已清理的JSON字符串的工作人员,将约100个记录的每个页面旋转到其自己的任务中。如果你在多核机器上运行它肯定会让它更快,我很乐意提供一些代码来帮助你开始,但它也是一个巨大的过度工程,因为它提出了问题的范围。

答案 2 :(得分:0)

上述答案都不适用于我,我必须Remove() Parent .Parent.Remove()的孩子,而不仅仅是Remove()。下面的工作代码示例:

namespace Engine.Api.Formatters
{
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Formatting;
    using System.Net.Http.Headers;
    using System.Threading.Tasks;
    using System.Web.Script.Serialization;
    using System.Xml;
    using System.Xml.Serialization;

    public class ReducedJson
    {
        public dynamic WriteToStreamAsync(object value)
        {
                    var json = new JavaScriptSerializer().Serialize(value);
                    var serializedJson = (JObject)JsonConvert.DeserializeObject(json);
                    foreach (var response in serializedJson["ProductData"]["Motor"]["QuoteResponses"])
                    {
                        response["NetCommResults"].Parent.Remove();
                        foreach (var netCommResult in response["BestPriceQuote"]["NetCommResults"])
                        {
                            netCommResult["Scores"].Parent.Remove();
                        }
                    }

          return serializedJson;
        }
}

希望这可以节省你一些时间。

答案 3 :(得分:0)

我只是找到另一个答案。

var aJson = JsonConvert.DeserializeObject<JObject>(json);
var doc = aJson["response"]["docs"];
JObject docs = new JObject();
docs["docs"] = doc;

// remove
docs.SelectTokens(string.Format("docs[?(@.id == '{0}')]", "2f7661ae3c7a42dd9f2eb1946262cd24")).ToList().ForEach(i => i.Remove());
// replace
aJson.SelectToken("response.docs").Replace(docs["docs"]);