Alx*_*ndr 22 c# recursion json data-structures
我在C#中有一个json对象(表示为Newtonsoft.Json.Linq.JObject对象),我需要将其展平为字典.让我举例说明我的意思:
{
"name": "test",
"father": {
"name": "test2"
"age": 13,
"dog": {
"color": "brown"
}
}
}
Run Code Online (Sandbox Code Playgroud)
这应该产生一个包含以下键值对的字典:
["name"] == "test",
["father.name"] == "test2",
["father.age"] == 13,
["father.dog.color"] == "brown"
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
Sar*_*uri 27
JObject jsonObject=JObject.Parse(theJsonString);
IEnumerable<JToken> jTokens = jsonObject.Descendants().Where(p => p.Count() == 0);
Dictionary<string, string> results = jTokens.Aggregate(new Dictionary<string, string>(), (properties, jToken) =>
{
properties.Add(jToken.Path, jToken.ToString());
return properties;
});
Run Code Online (Sandbox Code Playgroud)
我有一个将嵌套的json结构展平为字典对象的相同要求.在这里找到解决方案.
事实上,今天早些时候我也遇到了同样的问题,一开始无法在 SO 上找到这个问题,最终编写了我自己的扩展方法来返回JValue包含 JSON blob 叶节点值的对象。它与已接受的答案类似,但有一些改进:
.Count()您最终不需要的后代根据您的用例,这些可能相关也可能不相关,但它们适合我的情况。我在博客上写了有关学习扁平化 JSON.NET 对象的文章。这是我写的扩展方法:
public static class JExtensions
{
public static IEnumerable<JValue> GetLeafValues(this JToken jToken)
{
if (jToken is JValue jValue)
{
yield return jValue;
}
else if (jToken is JArray jArray)
{
foreach (var result in GetLeafValuesFromJArray(jArray))
{
yield return result;
}
}
else if (jToken is JProperty jProperty)
{
foreach (var result in GetLeafValuesFromJProperty(jProperty))
{
yield return result;
}
}
else if (jToken is JObject jObject)
{
foreach (var result in GetLeafValuesFromJObject(jObject))
{
yield return result;
}
}
}
#region Private helpers
static IEnumerable<JValue> GetLeafValuesFromJArray(JArray jArray)
{
for (var i = 0; i < jArray.Count; i++)
{
foreach (var result in GetLeafValues(jArray[i]))
{
yield return result;
}
}
}
static IEnumerable<JValue> GetLeafValuesFromJProperty(JProperty jProperty)
{
foreach (var result in GetLeafValues(jProperty.Value))
{
yield return result;
}
}
static IEnumerable<JValue> GetLeafValuesFromJObject(JObject jObject)
{
foreach (var jToken in jObject.Children())
{
foreach (var result in GetLeafValues(jToken))
{
yield return result;
}
}
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
然后在我的调用代码中,我只是从返回的对象中提取Path和属性:ValueJValue
var jToken = JToken.Parse("blah blah json here");
foreach (var jValue in jToken.GetLeafValues())
{
Console.WriteLine("{0} = {1}", jValue.Path, jValue.Value);
}
Run Code Online (Sandbox Code Playgroud)
从 .NET Core 3.0 开始JsonDocument是一种方式(不需要 Json.NET)。我相信这会变得更容易。
using System.Linq;
using System.Text.Json;
(...)
public static Dictionary<string, JsonElement> GetFlat(string json)
{
IEnumerable<(string Path, JsonProperty P)> GetLeaves(string path, JsonProperty p)
=> p.Value.ValueKind != JsonValueKind.Object
? new[] { (Path: path == null ? p.Name : path + "." + p.Name, p) }
: p.Value.EnumerateObject() .SelectMany(child => GetLeaves(path == null ? p.Name : path + "." + p.Name, child));
using (JsonDocument document = JsonDocument.Parse(json)) // Optional JsonDocumentOptions options
return document.RootElement.EnumerateObject()
.SelectMany(p => GetLeaves(null, p))
.ToDictionary(k => k.Path, v => v.P.Value.Clone()); //Clone so that we can use the values outside of using
}
Run Code Online (Sandbox Code Playgroud)
下面显示了一个更具表现力的版本。
using System.Linq;
using System.Text.Json;
(...)
var json = @"{
""name"": ""test"",
""father"": {
""name"": ""test2"",
""age"": 13,
""dog"": {
""color"": ""brown""
}
}
}";
var d = GetFlat(json);
var options2 = new JsonSerializerOptions { WriteIndented = true };
Console.WriteLine(JsonSerializer.Serialize(d, options2));
Run Code Online (Sandbox Code Playgroud)
{
"name": "test",
"father.name": "test2",
"father.age": 13,
"father.dog.color": "brown"
}
Run Code Online (Sandbox Code Playgroud)
using System.Linq;
using System.Text.Json;
(...)
static Dictionary<string, JsonElement> GetFlat(string json)
{
using (JsonDocument document = JsonDocument.Parse(json))
{
return document.RootElement.EnumerateObject()
.SelectMany(p => GetLeaves(null, p))
.ToDictionary(k => k.Path, v => v.P.Value.Clone()); //Clone so that we can use the values outside of using
}
}
static IEnumerable<(string Path, JsonProperty P)> GetLeaves(string path, JsonProperty p)
{
path = (path == null) ? p.Name : path + "." + p.Name;
if (p.Value.ValueKind != JsonValueKind.Object)
yield return (Path: path, P: p);
else
foreach (JsonProperty child in p.Value.EnumerateObject())
foreach (var leaf in GetLeaves(path, child))
yield return leaf;
}
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)
您可以使用https://github.com/jsonfx/jsonfx将 json 反序列化为动态对象。然后使用 ExpandoObject 来获得你想要的。
public Class1()
{
string json = @"{
""name"": ""test"",
""father"": {
""name"": ""test2"",
""age"": 13,
""dog"": {
""color"": ""brown""
}
}
}";
var reader = new JsonFx.Json.JsonReader();
dynamic output = reader.Read(json);
Dictionary<string, object> dict = new Dictionary<string, object>();
GenerateDictionary((System.Dynamic.ExpandoObject) output, dict, "");
}
private void GenerateDictionary(System.Dynamic.ExpandoObject output, Dictionary<string, object> dict, string parent)
{
foreach (var v in output)
{
string key = parent + v.Key;
object o = v.Value;
if (o.GetType() == typeof(System.Dynamic.ExpandoObject))
{
GenerateDictionary((System.Dynamic.ExpandoObject)o, dict, key + ".");
}
else
{
if (!dict.ContainsKey(key))
{
dict.Add(key, o);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10044 次 |
| 最近记录: |