C# 遍历JSON文件,并在C中用斜杠将其展平#

C# 遍历JSON文件,并在C中用斜杠将其展平#,c#,json,nested,json.net,C#,Json,Nested,Json.net,我是JSON新手,我正在尝试用斜杠将一个大的JSON文件展平,斜杠将每个级别分开。在此基础上,我尝试将值设置为单个int或字符串,或字符串列表(用逗号分隔)。 例如,如果JSON看起来像这样: { "This": { "Is": { "A": [ "json", "file" ], "Another"

我是JSON新手,我正在尝试用斜杠将一个大的JSON文件展平,斜杠将每个级别分开。在此基础上,我尝试将值设置为单个int或字符串,或字符串列表(用逗号分隔)。 例如,如果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());
它将变平为:

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());
    
  • 作业对象创建
    词典
    <