从分层JSON中挑选简单属性
*尽管其他用户对我的标题进行了编辑,但我正在寻找一种使用来自C#*的JSON.NET库的解决方案
包含psuedocode的回复很好! 🙂
我正在尝试使用JSON数据集提供的分层数据。 我正在使用C#和JSON.NET。 我很乐意使用Linq,尤其是Linq for JSON.NET,如果有帮助的话。 否则,使用非Linq C#/ JSON.NET就可以了。
理想情况下,我试图优雅地完成两件事:
-
我想提取代表每个分支的JSON和该分支自己的属性 – 而不是它的子(嵌套)分支对象(我稍后会详细解释)。
-
我想在创建分支对象时跟踪父节点。
有关进一步的考虑,请参阅以下JSON摘录:
{ "Branch1": { "Prop1A" : "1A", "Prop1B" : "1B", "Prop1C" : "1C", "Branch2" : { "Prop2A" : "2A", "Prop2B" : "2B", "Prop2C" : "2C", "Branch3" : { "Prop3A" : "3A", "Prop3B" : "3B", "Prop3C" : "3C" } } } }
与目标1相关(从上面):鉴于JSON由嵌套的JSON对象组成,我想只挑选每个分支的简单(字符串)属性。 例如,我想提取仅包含Prop1A,Prop1B和Prop1C属性的Branch1的JSON。 然后我想提取仅包含Prop2A,Prop2B和Prop2C属性等的Branch2的JSON。我意识到我可以将整个JSON表示为JSON.NET JToken对象,然后遍历其Children()并仅查看对于JTokenType.Property类型,但也许有一种更优雅的方法可以使用Linq快速选择属性类型…? 最后,我将有三个单独的JSON对象,如下所示:
JSON对象1:
{ "Prop1A" : "1A", "Prop1B" : "1B", "Prop1C" : "1C" }
JSON对象2:
{ "Prop2A" : "2A", "Prop2B" : "2B", "Prop2C" : "2C" }
JSON对象3:
{“Prop3A”:“3A”,“Prop3B”:“3B”,“Prop3C”:“3C”}
与目标2相关(从上面):理想情况下,上面提取的每个JSON也会有一个指示其父级的属性。 因此,最终的JSON对象看起来像这样:
{ "Prop1A" : "1A", "Prop1B" : "1B", "Prop1C" : "1C", "Parent" : "" }
和:
{ "Prop2A" : "2A", "Prop2B" : "2B", "Prop2C" : "2C", "Parent" : "Branch1" }
和:
{ "Prop3A" : "3A", "Prop3B" : "3B", "Prop3C" : "3C", "Parent" : "Branch2" }
有什么想法吗?
您可以使用JContainer.DescendantsAndSelf()
查找JSON层次结构中的所有对象,然后为每个对象循环遍历其属性并过滤掉其值为 JValue
原语的对象。 因此,以下查询创建一个List
其中包含您需要的属性名称和值:
var root = (JContainer)JToken.Parse(jsonString); var query1 = from o in root.DescendantsAndSelf().OfType() // Find objects let l = o.Properties().Where(p => p.Value is JValue) // Select their primitive properties where l.Any() // Skip objects with no properties select new JObject(l); // And return a JObject var list1 = query1.ToList();
要始终跳过根对象,即使它具有基本属性,请使用JContainer.Descendants()
。 如果你真的只想要字符串值属性(而不是原始属性),你可以检查JToken.Type
属性:
let l = o.Properties().Where(p => p.Value.Type == JTokenType.String) // Select their string-valued properties
可以使用JToken.Ancestors
增强查询以包括合成的“Parent”属性,该属性给出包含该对象的直接父属性的名称:
var query2 = from o in root.DescendantsAndSelf().OfType() // Find objects let l = o.Properties().Where(p => p.Value is JValue) // Select their primitive properties where l.Any() // Skip objects with no properties // Add synthetic "Parent" property let l2 = l.Concat(new[] { new JProperty("Parent", o.Ancestors().OfType().Select(a => a.Name).FirstOrDefault() ?? "") }) select new JObject(l2); // And return a JObject. var list2 = query2.ToList();
但是,在您想要的输出中,您似乎需要对象父级的属性名称,而不是对象的属性名称。 如果是这样,你可以这样做:
var query3 = from o in root.DescendantsAndSelf().OfType() // Find objects let l = o.Properties().Where(p => p.Value is JValue) // Select their primitive properties where l.Any() // Skip objects with no properties // Add synthetic "Parent" property let l2 = l.Concat(new[] { new JProperty("Parent", o.Ancestors().OfType().Skip(1).Select(a => a.Name).FirstOrDefault() ?? "") }) select new JObject(l2); // And return a JObject. var list3 = query3.ToList();
对于最终查询,如果我这样做:
Console.WriteLine(JsonConvert.SerializeObject(list3, Formatting.Indented));
生成以下输出,显示JObject
列表包含您需要的内容:
[ { "Prop1A": "1A", "Prop1B": "1B", "Prop1C": "1C", "Parent": "" }, { "Prop2A": "2A", "Prop2B": "2B", "Prop2C": "2C", "Parent": "Branch1" }, { "Prop3A": "3A", "Prop3B": "3B", "Prop3C": "3C", "Parent": "Branch2" } ]
请注意,如果JSON对象本身具有名为"Parent"
的属性,则JObject
构造函数可能会抛出重复的键exception。