从分层JSON挑选出简单性质 [英] Picking Out Simple Properties from Hierarchical JSON
问题描述
*尽管其他用户对我的标题进行了修改,但我正在寻找一个使用C#*中的JSON.NET库的解决方案。
包含伪码的回复很好! :)
我试图使用JSON数据集提供的分层数据。我使用C#和JSON.NET。我开放使用Linq一般和Linq 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,我想为每个分支选择简单(字符串)属性。例如,我想提取Branch1的仅包含Prop1A,Prop1B和Prop1C属性的JSON。然后我想提取的Branch2的JSON,将只包含Prop2A,Prop2B和Prop2C属性等。我意识到,我可以表示整个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对象看起来像这样:
{
/ pre>
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< JObject>
:var root =(JContainer)JToken.Parse(jsonString);
var query1 = from root.DescendantsAndSelf().OutType< JObject>()// Find objects
let l = o.Properties()。其中(p => p .Value is JValue)//选择它们的原始属性
其中l.Any()//跳过没有属性的对象
select new JObject(l); //并返回一个JObject
var list1 = query1.ToList();
要始终跳过根对象,即使它具有原始属性,请使用
JContainer.Descendants()
。如果您真的只想要字串值属性(而不是原始属性),可以检查JToken.Type
属性:= o.Properties()。其中(p => p.Value.Type == JTokenType.String)//选择字符串值属性
可以通过使用
JToken.Ancestors
:var query2 = from root.DescendantsAndSelf()。OfType< JObject>()// Find objects
let l = o.Properties p => p.Value is JValue)//选择它们的原始属性
其中l.Any()//跳过没有属性的对象
//添加合成的Parent属性
let l2 = l.Concat(new [] {new JProperty(Parent,o.Ancestors()。OfType< JProperty>()。 a.Name).FirstOrDefault()? )})
select new JObject(l2); //并返回一个JObject。
var list2 = query2.ToList();
但是,在你想要的输出中,你似乎想要的对象的父级的属性名称,比对象的属性名称。如果是,你可以这样做:
var query3 = from root.DescendantsAndSelf().OffType< JObject>()/ / Find objects
let l = o.Properties()。其中(p => p.Value是JValue)//选择它们的原始属性
其中l.Any属性
//添加合成的Parent属性
let l2 = l.Concat(new [] {new JProperty(Parent,o.Ancestors()。OfType< JProperty> 1).Select(a => a.Name).FirstOrDefault()??)})
select new JObject(l2); //并返回一个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
}
]
$ b b请注意,如果JSON对象本身具有名为
Parent
的属性,则JObject
重复的键异常。* Despite the edit to my title by another user, I am seeking a solution that uses JSON.NET's library from C# *
A reply containing psuedocode is fine! :)
I'm trying to work with hierarchical data provided by a JSON dataset. I'm using C# and JSON.NET. I'm open to using Linq in general and Linq for JSON.NET in particular if it would help; otherwise, using non-Linq C#/JSON.NET is fine.
Ideally, I am trying to accomplish two things elegantly:
I want to extract JSON that represents each branch and that branch's own properties--not its child (nested) branch objects (I will explain more in a moment).
I want to track the parent node as I create my branch objects.
For further consideration, please refer to the following JSON excerpt:
{ "Branch1": { "Prop1A" : "1A", "Prop1B" : "1B", "Prop1C" : "1C", "Branch2" : { "Prop2A" : "2A", "Prop2B" : "2B", "Prop2C" : "2C", "Branch3" : { "Prop3A" : "3A", "Prop3B" : "3B", "Prop3C" : "3C" } } } }
Related to Goal 1 (from above): Given JSON that is composed of nested JSON objects, I want to pick out only the simple (string) properties for each branch. For instance, I would like to extract the JSON for Branch1 that would contain only Prop1A, Prop1B, and Prop1C properties. I would then like to extract the JSON for Branch2 that would contain only Prop2A, Prop2B, and Prop2C properties, etc. I realize that I can represent the entire JSON as a JSON.NET JToken object then iterate through its Children() and look only for JTokenType.Property types, but perhaps there is a more elegant way to quickly pick out just the property types using Linq...? In the end, I would have three separate JSON objects that would look like this:
JSON Object 1:
{ "Prop1A" : "1A", "Prop1B" : "1B", "Prop1C" : "1C" }
JSON Object 2:
{ "Prop2A" : "2A", "Prop2B" : "2B", "Prop2C" : "2C" }
JSON Object 3:
{ "Prop3A" : "3A", "Prop3B" : "3B", "Prop3C" : "3C" }
Related to Goal 2 (from above): Ideally, each extracted JSON above would also have a property indicating its parent. Thus, the final JSON objects would look something like this:
{ "Prop1A" : "1A", "Prop1B" : "1B", "Prop1C" : "1C", "Parent" : "" }
And:
{ "Prop2A" : "2A", "Prop2B" : "2B", "Prop2C" : "2C", "Parent" : "Branch1" }
And:
{ "Prop3A" : "3A", "Prop3B" : "3B", "Prop3C" : "3C", "Parent" : "Branch2" }
Any thoughts?
解决方案You can use
JContainer.DescendantsAndSelf()
to find all objects in the JSON hierarchy, then for each object, loop through its properties and filter out those whose value is aJValue
primitive. Thus the following query creates aList<JObject>
containing the property names and values you require:var root = (JContainer)JToken.Parse(jsonString); var query1 = from o in root.DescendantsAndSelf().OfType<JObject>() // 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();
To always skip the root object even if it has primitive properties, use
JContainer.Descendants()
. And if you really only want string-valued properties (rather than primitive properties), you can check theJToken.Type
property:let l = o.Properties().Where(p => p.Value.Type == JTokenType.String) // Select their string-valued properties
The query can be enhanced to include a synthetic "Parent" property giving the name of the immediate parent property containing the object, using
JToken.Ancestors
:var query2 = from o in root.DescendantsAndSelf().OfType<JObject>() // 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<JProperty>().Select(a => a.Name).FirstOrDefault() ?? "") }) select new JObject(l2); // And return a JObject. var list2 = query2.ToList();
However, in your desired output you seem to want the property name of the parent of the object, rather than the property name of the object. If so, you can do:
var query3 = from o in root.DescendantsAndSelf().OfType<JObject>() // 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<JProperty>().Skip(1).Select(a => a.Name).FirstOrDefault() ?? "") }) select new JObject(l2); // And return a JObject. var list3 = query3.ToList();
For the final query, if I do:
Console.WriteLine(JsonConvert.SerializeObject(list3, Formatting.Indented));
The following output is generated, showing the
JObject
list has the contents you require:[ { "Prop1A": "1A", "Prop1B": "1B", "Prop1C": "1C", "Parent": "" }, { "Prop2A": "2A", "Prop2B": "2B", "Prop2C": "2C", "Parent": "Branch1" }, { "Prop3A": "3A", "Prop3B": "3B", "Prop3C": "3C", "Parent": "Branch2" } ]
Note that if the JSON objects themselves have a property named
"Parent"
, theJObject
constructor may throw a duplicated key exception.这篇关于从分层JSON挑选出简单性质的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!