【问题标题】:How to filter JSON array in C#如何在 C# 中过滤 JSON 数组
【发布时间】:2014-07-05 02:12:04
【问题描述】:

我花了很多时间来解决我的问题。

在这个例子中,我在 SetNavRecords 数组中有 2 条记录。 第一个是 "Artikelnummer" : "21700",第二个是 "Artikelnummer" : "21701"

每条记录都有一个数组“OfflineVerkaufspreis”。

对我来说重要的是“OfflineVerkaufspreis”中的“Location_Code”字段 我只需要一个过滤的位置代码的孔信息。

如何选择一个位置代码的数据,例如“MH”?

我正在使用 C# 和 Newtonsoft 类进行 JSON 解析。

我尝试了一些带有 LINQ 的版本,但没有成功。

{ "SetNavRecords" : [ { "Artikelbeschreibung" : "Trikot \"Home\" 2012/2013",
    "Artikelbeschreibung2" : "weiß",
    "Artikelnummer" : "21700",
    "Artikelrabattgruppe" : "MERCH",
    "Gutschein" : false,
    "MwStProduktgruppe" : "VOLLNEU",
    "OfflineVerkaufspreis" : [ { "Allow_Line_Discount" : true,
          "Date" : "2014-05-16T00:00:00",
          "Item_No" : "21700",
          "Location_Code" : "BP",
          "Unit_Price" : 5.0
        },
        { "Allow_Line_Discount" : true,
          "Date" : "2014-05-16T00:00:00",
          "Item_No" : "21700",
          "Location_Code" : "MH",
          "Unit_Price" : 5.0
        },
        { "Allow_Line_Discount" : true,              
          "Date" : "2014-05-16T00:00:00",
          "Item_No" : "21700",
          "Location_Code" : "RY",
          "Unit_Price" : 5.0
        }
      ]
  },
  { "Artikelbeschreibung" : "Autogrammtrikot 2012/2013",
    "Artikelbeschreibung2" : "weiß",
    "Artikelnummer" : "21701",
    "Artikelrabattgruppe" : "MERCH",
    "Gutschein" : false,
    "MwStProduktgruppe" : "VOLLNEU",
    "OfflineVerkaufspreis" : [ { "Allow_Line_Discount" : false,
          "Date" : "2014-05-16T00:00:00",
          "Item_No" : "21701",
          "Location_Code" : "BP",
          "Unit_Price" : 69.99
        },
        { "Allow_Line_Discount" : false,
          "Date" : "2014-05-16T00:00:00",
          "Item_No" : "21701",
          "Location_Code" : "MH",
          "Unit_Price" : 69.99
        },
        { "Allow_Line_Discount" : false,
          "Date" : "2014-05-16T00:00:00",
          "Item_No" : "21701",
          "Location_Code" : "RY",
          "Unit_Price" : 69.99
        }
      ]
  }

] }

这是我的问题:

var tmpResult = JObject.Parse(File.ReadAllText(FileName));
var resultObject = tmpResult["SetNavRecords"]
      .Values("OfflineVerkaufspreis")
      .Values<JObject>()                                   
      .Where(n => n["Location_Code"].Value<string>() == "MH"); 

过滤器工作正常,但 tmpResult 中的数据不完整。我只在“OfflineVerkaufspreis”中获取数据。我也需要根数据。

有人有想法吗?

谢谢!

【问题讨论】:

  • 不要使用 .Values("OfflineVerkaufspreis"),因为那样你得到的只是 "OfflineVerkaufspreis" 对象。访问 Where 子句中的“OfflineVerkaufspreis”对象,例如 .Where(n =&gt; n["OfflineVerkaufspreis"]["Location_Code"] ...(我相信,我还没有测试过)
  • 那是因为你的代码告诉它当它显示.Values("OffilineVerkaufspreis") 时只获取OfflineVerkaufspreis 的值。把它拿出来,然后对 tmpResult["SetNavRecords"] 做一个 where。未经测试,但这应该可以,只需弄清楚确切的语法即可。
  • 关于我上面评论中建议的方法,好吧,这是错误的(请参阅,相信不能代替思考)。阅读下面老金的回答以获得简短的解释。

标签: c# json filter json.net


【解决方案1】:

这感觉像是一项可以通过将 json 序列化为对象来简化一些工作。要将 json 反序列化为您可以使用的对象:

RootObject obj = JsonConvert.DeserializeObject<RootObject>(jsonString);

同样,您可以使用以下方法将对象转回 json:

string jsonString = JsonConvert.SerializeObject(RootObject);

根据您在问题中提供的 json,您的对象的结构是这样的:

public class OfflineVerkaufsprei
{
    public bool Allow_Line_Discount { get; set; }
    public string Date { get; set; }
    public string Item_No { get; set; }
    public string Location_Code { get; set; }
    public double Unit_Price { get; set; }
}

public class SetNavRecord
{
    public string Artikelbeschreibung { get; set; }
    public string Artikelbeschreibung2 { get; set; }
    public string Artikelnummer { get; set; }
    public string Artikelrabattgruppe { get; set; }
    public bool Gutschein { get; set; }
    public string MwStProduktgruppe { get; set; }
    public List<OfflineVerkaufsprei> OfflineVerkaufspreis { get; set; }
}

public class RootObject
{
    public List<SetNavRecord> SetNavRecords { get; set; }
}

然后您可以通过以下方式轻松地遍历您的对象:

for each(SetNavRecord i in obj.SetNavRecords)
{
    // do something to the record
}

【讨论】:

  • 我还应该提到,上面的代码使用了 json.net 库,可以通过 nuget 包找到并在此链接中引用:james.newtonking.com/json
【解决方案2】:
var tmpResult = JObject.Parse(File.ReadAllText(FileName));
var resultObject = tmpResult["SetNavRecords"].Values("OfflineVerkaufspreis").Values<JObject>()                                   
            .Where(n => n["Location_Code"].Value<string>() == "MH");   

此代码将导航到OfflineVerkaufspreis.Values,然后过滤它们。 但是(我猜)您想选择与您的 Where 子句匹配的位置,然后还选择父详细信息。

您可以使用Select 选择您真正感兴趣的所有信息。

var resultObject = tmpResult["SetNavRecords"].Values("OfflineVerkaufspreis").Values<JObject>()
           .Where(n => n["Location_Code"].Value<string>() == "MH")
           .Select(n => new { Location = n, Context = n.Parent }).ToArray();

当然,您可以只选择您真正需要的信息,而不是选择整个 Parent。

为了使这段代码更具可读性,我建议创建一些匹配 JSon 输入的类,以便您可以将 JSon 映射到这个对象图。这将使您的 Linq 更易于编写、阅读和理解。

更新: 在 cmets 中建议使用:.Where(n =&gt; n["OfflineVerkaufspreis"]["Location_Code"] ...。这种方法的问题在于,最终您不知道哪个 OfflineVerkaufspreis 实际匹配您的 where 子句...

【讨论】:

  • 感谢您的建议。不幸的是,它不起作用。问题是,“Context = n.Parent”不包含过滤位置代码的根数据。而不是它包含“OfflineVerkaufspreis”的第一个条目。
  • 添加另一个.Parent 应该可以吗?另请检查 tezromania 的回答:如果格式或您想要对其执行的操作经常更改,则当您摆脱所有 ["xxx"] 并改为使用时,这种方法将使更改变得更加容易(例如不同的 where 子句)一种更自然的 c# 方法。
  • 请注意,对于.Parent.ParentContext 属性将包含所有 OfflineVerkaufspreis,而不仅仅是与 where 匹配的那个。 Location 属性仅包含匹配的位置。因此,您可能还想在此处添加另一个 .Parent
  • 再次感谢您的快速回复。我添加了一些 .Parent 但结果不是我所期望的。然后我更改了我的代码,以便可以使用 DeSerializeObject。
【解决方案3】:

我会创建名为 SetNavRecords 和 OfflineVerkaufspreis 的类。然后我会使用命名空间 System.Web.Script.Serialization.JavaScriptSerializer 中的 JavaScriptSerializer 来反序列化它。

代码是这样的-

JavaScriptSerializer.Deserialize(String, Type);

然后我可以像简单的通用集合一样操作它,例如。列表。

希望对你有所帮助。

【讨论】:

    猜你喜欢
    • 2017-11-24
    • 1970-01-01
    • 2017-09-15
    • 2018-08-22
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多