C# 遍历JSON文件,并在C中用斜杠将其展平#
我是JSON新手,我正在尝试用斜杠将一个大的JSON文件展平,斜杠将每个级别分开。在此基础上,我尝试将值设置为单个int或字符串,或字符串列表(用逗号分隔)。 例如,如果JSON看起来像这样:C# 遍历JSON文件,并在C中用斜杠将其展平#,c#,json,nested,json.net,C#,Json,Nested,Json.net,我是JSON新手,我正在尝试用斜杠将一个大的JSON文件展平,斜杠将每个级别分开。在此基础上,我尝试将值设置为单个int或字符串,或字符串列表(用逗号分隔)。 例如,如果JSON看起来像这样: { "This": { "Is": { "A": [ "json", "file" ], "Another"
{
"This": {
"Is": {
"A": [
"json",
"file"
],
"Another": {
"JSON": "File"
}
},
"File": {
"Is": 4,
"Line": [
{
"Nested": "JSON"
},
{
"Nested2:": "JSON2"
}
]
}
}
}
function traverse(jsonObj) {
if( jsonObj !== null && typeof jsonObj == "object" ) {
Object.entries(jsonObj).forEach(([key, value]) => {
// key is either an array index or object key
traverse(value);
});
}
else {
// jsonObj is a number or string
}
}
JObject jo = JObject.Parse(json);
Dictionary<string, List<string>> dict =
jo.Descendants()
.OfType<JProperty>()
.Where(jp => jp.Value is JValue ||
(jp.Value is JArray && jp.Value.Children().All(jt => jt is JValue)))
.Select(jp => new
{
Path = Regex.Replace(jp.Path, @"\[\d+\]", "").Replace(".", " / "),
Value = jp.Value is JValue
? (string)jp.Value
: string.Join(", ", jp.Value.Children().Select(jt => (string)jt))
})
.GroupBy(a => a.Path)
.ToDictionary(g => g.Key, g => g.Select(a => a.Value).ToList());
它将变平为:
This/Is/A:json,文件
This/Is/other/JSON:file
This/File/Is:4
This/File/Line/Nested:JSON
This/File/Line/Nested 2:JSON2
我在StackOverflow上看到了一个Javascript解决方案,它说要执行以下操作:
{
"This": {
"Is": {
"A": [
"json",
"file"
],
"Another": {
"JSON": "File"
}
},
"File": {
"Is": 4,
"Line": [
{
"Nested": "JSON"
},
{
"Nested2:": "JSON2"
}
]
}
}
}
function traverse(jsonObj) {
if( jsonObj !== null && typeof jsonObj == "object" ) {
Object.entries(jsonObj).forEach(([key, value]) => {
// key is either an array index or object key
traverse(value);
});
}
else {
// jsonObj is a number or string
}
}
JObject jo = JObject.Parse(json);
Dictionary<string, List<string>> dict =
jo.Descendants()
.OfType<JProperty>()
.Where(jp => jp.Value is JValue ||
(jp.Value is JArray && jp.Value.Children().All(jt => jt is JValue)))
.Select(jp => new
{
Path = Regex.Replace(jp.Path, @"\[\d+\]", "").Replace(".", " / "),
Value = jp.Value is JValue
? (string)jp.Value
: string.Join(", ", jp.Value.Children().Select(jt => (string)jt))
})
.GroupBy(a => a.Path)
.ToDictionary(g => g.Key, g => g.Select(a => a.Value).ToList());
但我很困惑,在遍历时如何在关键点之间添加斜线?还请注意,我正在寻找一个C#解决方案,而不是Javascript
好的,所以我试着尝试一下。我正在使用Newtonsoft.Linq库。我的JSON文件包含的值是整数、字符串、列表、对象和对象列表。我想将所有扁平化的响应保存到字典中(而不是将其写入控制台)。但我遇到了一个问题,即字典中已经存在密钥。这是在有对象列表的情况下,对象列表键是相同的,因为它们遵循图案块,但值不同。例如:
{
"Level1": [
{
"Level2": {
"A": "something1",
"B": 1
},
"Level3": [
{
"3A": "content"
}
],
"Level41": null,
"Level42": null,
"Level43": null,
"Level44": "content",
"Level45": "content",
"Level46": "content"
},
{
"Level2": {
"A": "something1",
"B": 2
},
"Level3": [
{
"3A": "morecontent"
}
],
"Level41": null,
"Level42": null,
"Level43": null,
"Level44": "content",
"Level45": "morecontent",
"Level46": "content"
}
]
}
有没有办法确保如果字典已经看到该键,它会将该键的所有值保存在列表中?或者这不是我的问题?以下是我所做的:
// The JSON file has been deserialized into a Dictionary with string key and object value
// We will be saving all the key value pairs we have seen into a Dictionary called dictionary
Dictionary<string, object> dictionary = new Dictionary<string,object>();
// I was using a datgridview to input the values in a cell but we can ignore that
private void AddValue(string key, object value)
{
if (value != null && value.GetType() == typeof(JObject)) // if key == string, value == object
{
foreach (var a in (JObject)value)
{
string name = a.Key;
JToken obj = a.Value;
AddValue(name + a + " / ", obj);
}
}
else if (value != null && value.GetType() == typeof(JArray)) // if key == string, value == array
{
foreach (var a in (JArray)value)
{
if (a.GetType() == typeof(JObject)) // if key == string, value == object
{
foreach (var item in (JObject)a)
{
string objectName = item.Key;
JToken objValue = item.Value;
AddValue(objectName + item + " / ", objValue);
}
}
else //key == string, value == string
{
string name = (string)a;
AddValue(name + " / ", a);
}
}
}
else // key == string, value == string
{
var keyCell = new DataGridViewTextBoxCell();
var row = new DataGridViewRow();
var valCell = new DataGridViewTextBoxCell();
if (value != null)
{
keyCell.Value = key;
valCell.Value = value;
row.Cells.Add(keyCell);
row.Cells.Add(valCell);
this.treeView.Rows.Add(row);
if (dictionary.ContainsKey((string)keyCell.Value)) // this is if
{
string optionKey = (string)keyCell.Value;
object keyValueObject = dictionary[(string)keyCell.Value];
//values.Add((string)valCell.Value);
dictionary.Remove((string)keyCell.Value);
}
dictionary.Add((string)keyCell.Value, null); // I know this isn't right, because then this just overrides the key each time. Not sure how to fix
else
{
keyCell.Value = key;
valCell.Value = String.Empty;
row.Cells.Add(keyCell);
row.Cells.Add(valCell);
this.datagridview.Rows.Add(row);
if (dictionary.ContainsKey((string)keyCell.Value))
{
values.Add((string)valCell.Value);
dictionary.Remove((string)keyCell.Value);
}
dictionary.Add((string)keyCell.Value, values);
}
}
}
//JSON文件已反序列化到具有字符串键和对象值的字典中
//我们将把看到的所有键值对保存到一个名为Dictionary的字典中
字典=新字典();
//我使用datgridview在单元格中输入值,但我们可以忽略它
私有void AddValue(字符串键、对象值)
{
if(value!=null&&value.GetType()==typeof(JObject))//if key==string,value==object
{
foreach(在(JObject)值中的var a)
{
字符串名称=a.键;
JToken obj=a.值;
附加值(名称+a+“/”,obj);
}
}
else if(value!=null&&value.GetType()==typeof(JArray))//if key==string,value==array
{
foreach(在(JArray)值中的var a)
{
if(a.GetType()==typeof(JObject))//if key==string,value==object
{
foreach(在(JObject)a中的var项目)
{
字符串objectName=item.Key;
JToken objValue=项目值;
AddValue(objectName+item+“/”,objValue);
}
}
else//key==string,value==string
{
字符串名称=(字符串)a;
附加值(名称+“/”,a);
}
}
}
else//key==string,value==string
{
var keyCell=新的DataGridViewTextBoxCell();
var row=新的DataGridViewRow();
var valCell=新的DataGridViewTextBoxCell();
if(值!=null)
{
keyCell.Value=key;
valCell.Value=值;
row.Cells.Add(keyCell);
row.Cells.Add(valCell);
this.treeView.Rows.Add(row);
if(dictionary.ContainsKey((string)keyCell.Value))//这是if
{
字符串选项key=(字符串)keyCell.Value;
object keyValueObject=字典[(字符串)keyCell.Value];
//添加((字符串)valCell.Value);
删除((字符串)keyCell.Value);
}
dictionary.Add((string)keyCell.Value,null);//我知道这不对,因为这样每次都会覆盖键。不确定如何修复
其他的
{
keyCell.Value=key;
valCell.Value=String.Empty;
row.Cells.Add(keyCell);
row.Cells.Add(valCell);
this.datagridview.Rows.Add(row);
if(dictionary.ContainsKey((string)keyCell.Value))
{
添加((字符串)valCell.Value);
删除((字符串)keyCell.Value);
}
添加((字符串)keyCell.Value,值);
}
}
}
使用(作业对象),您可以将JSON展平到字典中,如下所示:
{
"This": {
"Is": {
"A": [
"json",
"file"
],
"Another": {
"JSON": "File"
}
},
"File": {
"Is": 4,
"Line": [
{
"Nested": "JSON"
},
{
"Nested2:": "JSON2"
}
]
}
}
}
function traverse(jsonObj) {
if( jsonObj !== null && typeof jsonObj == "object" ) {
Object.entries(jsonObj).forEach(([key, value]) => {
// key is either an array index or object key
traverse(value);
});
}
else {
// jsonObj is a number or string
}
}
JObject jo = JObject.Parse(json);
Dictionary<string, List<string>> dict =
jo.Descendants()
.OfType<JProperty>()
.Where(jp => jp.Value is JValue ||
(jp.Value is JArray && jp.Value.Children().All(jt => jt is JValue)))
.Select(jp => new
{
Path = Regex.Replace(jp.Path, @"\[\d+\]", "").Replace(".", " / "),
Value = jp.Value is JValue
? (string)jp.Value
: string.Join(", ", jp.Value.Children().Select(jt => (string)jt))
})
.GroupBy(a => a.Path)
.ToDictionary(g => g.Key, g => g.Select(a => a.Value).ToList());
从JObject
创建一个字典,如下所示:
Dictionary<string, List<string>> dict =
将子体向下筛选为仅属性(键值对):
现在我们有了想要的属性,我们需要根据需求从每个属性中提取路径和值。我们将把它们选择到一个临时匿名对象中,以便以后更容易对它们进行进一步处理
.Select(jp => new
{
要使用斜杠创建路径,我们可以使用JProperty
上方便的Path
属性。这将返回一个点分隔的路径,例如This.File.Line[0]。嵌套的,这与您要查找的非常接近。但是,我们需要去掉数组下标(例如[0]
)并将点替换为斜线:
Path = Regex.Replace(jp.Path, @"\[\d+\]", "").Replace(".", " / "),
对于值部分,我们所做的取决于值是一个基元还是一个基元数组。如果它只是一个简单的基元,我们将其值作为字符串获取;如果它是一个数组,我们将其所有子项(作为字符串)合并到一个逗号分隔的列表中:
Value = jp.Value is JValue
? (string)jp.Value
: string.Join(", ", jp.Value.Children().Select(jt => (string)jt))
}
由于我们消除了数组下标,现在有可能出现重复键。我们希望能够将所有内容放入字典,因此我们需要将具有相同路径的值组合在一起:
.GroupBy(a => a.Path)
一旦有了这些组,我们就可以通过将值放入每个键(路径)的列表中,将所有内容转换为字典:
此处的工作演示:使用(作业对象),您可以将JSON展平到字典中,如下所示:
{
"This": {
"Is": {
"A": [
"json",
"file"
],
"Another": {
"JSON": "File"
}
},
"File": {
"Is": 4,
"Line": [
{
"Nested": "JSON"
},
{
"Nested2:": "JSON2"
}
]
}
}
}
function traverse(jsonObj) {
if( jsonObj !== null && typeof jsonObj == "object" ) {
Object.entries(jsonObj).forEach(([key, value]) => {
// key is either an array index or object key
traverse(value);
});
}
else {
// jsonObj is a number or string
}
}
JObject jo = JObject.Parse(json);
Dictionary<string, List<string>> dict =
jo.Descendants()
.OfType<JProperty>()
.Where(jp => jp.Value is JValue ||
(jp.Value is JArray && jp.Value.Children().All(jt => jt is JValue)))
.Select(jp => new
{
Path = Regex.Replace(jp.Path, @"\[\d+\]", "").Replace(".", " / "),
Value = jp.Value is JValue
? (string)jp.Value
: string.Join(", ", jp.Value.Children().Select(jt => (string)jt))
})
.GroupBy(a => a.Path)
.ToDictionary(g => g.Key, g => g.Select(a => a.Value).ToList());
从作业对象创建词典
<