从分层JSON挑选出简单性质 [英] Picking Out Simple Properties from Hierarchical JSON

查看:131
本文介绍了从分层JSON挑选出简单性质的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

*尽管其他用户对我的标题进行了修改,但我正在寻找一个使用C#*中的JSON.NET库的解决方案。



包含伪码的回复很好! :)



我试图使用JSON数据集提供的分层数据。我使用C#和JSON.NET。我开放使用Linq一般和Linq JSON.NET的,特别是如果它会有所帮助;



理想情况下,我试图完美地完成两件事:


  1. 我想提取JSON代表每个分支和分支自己的属性 - 而不是它的子(嵌套)分支对象(我会在稍后解释更多)。


  2. 我想要在创建我的分支对象时跟踪父节点。


有关进一步考虑,请参阅以下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对象看起来像这样:

  {
Prop1A:1A,
Prop1B:1B,
Prop1C:1C,
Parent:
}
/ pre>

和:

  {
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:

  1. 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).

  2. 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 a JValue primitive. Thus the following query creates a List<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 the JToken.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", the JObject constructor may throw a duplicated key exception.

这篇关于从分层JSON挑选出简单性质的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆