有一个这样的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"));
}