JSON.NET.从其子对象导航到 JArray 对象



有一个这样的JSON文件:

{
  "men": [
    {
      "name": "Jordan",
      "phone": "333-333-33"
    },
    {
      "name": "Timothey",
      "phone": "444-444-44"
    }
  ],
  "women": [
    {
      "name": "Jordan",
      "phone": "111-111-11"
    },
    {
      "name": "Sasha",
      "phone": "222-222-22"
    }
  ]
}

我想找到所有名字以J开头的人,看看这个人是男人还是女人。

var jsonProps = jsonDoc.Descendants().Where(t => t.Type == JTokenType.Property && ((JProperty)t).Name == prop);
var startsWithJ = jsonProps.Where(t => ((JProperty)t).Value.ToString().StartsWith("J"));
foreach (var person in startsWithJ)
{
    Console.WriteLine(person.Value<string>());
    Console.WriteLine(person.Parent.Parent.Value<string>());
}

问题是那个人。Parent.Parent 是空的,我希望它是 JArray 或至少是 JToken 或至少一些 JToken,所以我可以获得它的值。

更新:我有 100 种使用类似数据结构的类型。这些集合(男性、女性(可以处于任何嵌套级别,例如员工包括男性和女性集合,或者学生包括男性和女性集合。我无法为解决方案中的每种类型创建强类型对象。有时我需要从男性/女性集合中删除对象,并在此之后检查集合是否有任何元素。

这不是"如何使用 LINQ to JSON 进行查询"的直接答案,而是我发现使用强类型对象更容易的方法。

通过简单地创建以下数据结构(请注意,POCO 用 JsonProperty 装饰,这是一个 Json.NET 属性(:

public class RootObject
{
    public List<Person> Men { get; set; }
    public List<Person> Women { get; set; }
}
public class Person
{
    [JsonProperty("name")]
    public string Name { get; set; }
    [JsonProperty("phone")]
    public string PhoneNumber { get; set; }
    public Sex Sex { get; set }
}
public enum Sex
{
    Man,
    Women
}

现在,您可以使用 LINQ to Object 轻松查询所需内容:

var rootObject = JsonConvert.DeserializeObject<RootObject>(json);
foreach (var male in rootObject.Men)
{
    male.Sex = Sex.Man;
}
foreach (var female in rootObject.Women)
{
    female.Sex = Sex.Women;
}
var startsWithJ = rootObject.Men.Concat(rootObject.Women)
                            .Where(x => x.Name.StartsWith("J",
                                        StringComparison.OrdinalIgnoreCase))
                            .ToList();
foreach (var personStartsWithJ in startsWithJ)
{
    Console.WriteLine (personStartsWithJ.Name);
    Console.WriteLine (personStartsWithJ.Sex);
}

您的代码不起作用,因为您正在对值以"J"开头的所有name属性进行操作,而不是对包含值以"J"开头的name属性的 person 对象进行操作。 因此,当你向上导航时,你走得还不够远。 name属性的父级是 person 对象。 person 对象的父对象是数组,数组的父对象是men(或women(JProperty。 (另外,要确定数组包含属性的名称是"men"还是"woman",您需要获取其Name,而不是其Value

因此,如果将代码更改为以下内容,则应获得预期的结果:

foreach (JProperty nameProp in startsWithJ)
{
    Console.WriteLine(nameProp.Value);
    Console.WriteLine(((JProperty)nameProp.Parent.Parent.Parent).Name);
}

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

就我个人而言,我发现在JObject级别而不是JProperty级别工作更容易一些。 这是获得相同结果的另一种方法:

var people = jsonDoc["men"]
    .Children<JObject>()
    .Union(jsonDoc["women"].Children<JObject>())
    .Where(obj => obj["name"] != null && obj["name"].ToString().StartsWith("J"));
foreach (JObject person in people)
{
    Console.WriteLine(person["name"]);
    Console.WriteLine(((JProperty)person.Parent.Parent).Name);
}

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

如果您发现您总是希望以这种方式查找此人的父集合名称,则可以定义一个扩展方法:

public static class JHelper
{
    public static bool IsMale(this JObject person)
    {
        return ((JProperty)person.Parent.Parent).Name == "men";
    }
}

然后,您只需在JObject上调用IsMale()即可。 它使代码更具可读性。

foreach (JObject person in people)
{
    Console.WriteLine("Name: " + person["name"]);
    Console.WriteLine("Gender: " + (person.IsMale() ? "male" : "female"));
}

相关内容

  • 没有找到相关文章

最新更新