从分层JSON中挑选简单属性

本文关键字:简单 属性 挑选 分层 JSON | 更新日期: 2023-09-27 17:58:31

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

包含psuedocode的回复可以!:)

我正在尝试使用JSON数据集提供的分层数据。我使用的是C#和JSON.NET。如果有帮助的话,我对一般使用Linq持开放态度,尤其是对JSON.NET使用Linq;否则,可以使用非Linq C#/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的JSON,它只包含Prop1A、Prop1B和Prop1C属性。然后,我想提取Branch2的JSON,其中只包含Prop2A、Prop2B和Prop2C属性等。我意识到我可以将整个JSON表示为JSON.NET JToken对象,然后遍历其Children()并只查找JTokenType.属性类型,但也许有一种更优雅的方法可以使用Linq快速挑选属性类型。。。?最后,我会有三个独立的JSON对象,看起来像这样:

JSON对象1:

{
  "Prop1A" : "1A",
  "Prop1B" : "1B",
  "Prop1C" : "1C"
}

JSON对象2:

{
  "Prop2A" : "2A",
  "Prop2B" : "2B",
  "Prop2C" : "2C"
}

JSON对象3:

{"道具3A":"3A","Prop3B":"3B","道具3C":"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"
}

有什么想法吗?

从分层JSON中挑选简单属性

您可以使用JContainer.DescendantsAndSelf()查找JSON层次结构中的所有对象,然后对于每个对象,循环遍历其属性并筛选出值为JValue基元的对象。因此,以下查询创建了一个List<JObject>,其中包含您需要的属性名称和值:

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();

要始终跳过根对象(即使它具有基元属性),请使用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<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();

但是,在所需的输出中,您似乎想要对象的父对象的属性名,而不是对象的属性名称。如果是这样,你可以做:

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();

对于最后的查询,如果我这样做:

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构造函数可能会抛出一个重复的键异常。