将嵌套 JSON 转换为简单 JSON

Posted

技术标签:

【中文标题】将嵌套 JSON 转换为简单 JSON【英文标题】:Convert nested JSON to simple JSON 【发布时间】:2017-06-01 06:31:02 【问题描述】:

我正在尝试通过递归遍历将嵌套的 json 转换为简单的 json。 (输入json的结构未知)

例如,我想要这样的json


    "FirstName": "Rahul",
    "LastName": "B",
    "EmpType": 
        "RID": 2,
        "Title": "Full Time"
    ,
    "CTC": "3.5",
    "Exp": "1",
    "ComplexObj": 
        "RID": 3,
        "Title": 
            "Test": "RID",
            "TWO": 
                "Test": 12
            
        
    

要转换成这样的东西


    "FirstName": "Rahul",
    "LastName": "B",
    "EmpType__RID": 2,
    "EmpType__Title": "Full Time",
    "CTC": "3.5",
    "Exp": "1",
    "ComplexObj__RID": 3,
    "ComplexObj__Title__Test": "RID",
    "ComplexObj__Title__TWO__Test": 12

嵌套对象中的每个字段都将更改为代表其实际路径的键。

这是我到目前为止所做的。

    public static void ConvertNestedJsonToSimpleJson(JObject jobject, ref JObject jobjectRef, string currentNodeName = "", string rootPath = "")
    
        string propName = "";
        if (currentNodeName.Equals(rootPath))
        
            propName = currentNodeName;
        
        else
        
            propName = (rootPath == "" && currentNodeName == "") ? rootPath + "" + currentNodeName : rootPath + "__" + currentNodeName;
        

        foreach (JProperty jprop in jobject.Properties())
        
            if (jprop.Children<JObject>().Count() == 0)
            
                jobjectRef.Add(propName == "" ? jprop.Name : propName + "__" + jprop.Name, jprop.Value);
            
            else
            
                currentNodeName = jprop.Name;
                rootPath = rootPath == "" ? jprop.Name : rootPath;
                ConvertNestedJsonToSimpleJson(JObject.Parse(jprop.Value.ToString()), ref jobjectRef, currentNodeName, rootPath);
            
        
    

得到错误的结果


    "FirstName": "Rahul",
    "LastName": "B",
    "EmpType__RID": 2,
    "EmpType__Title": "Full Time",
    "CTC": "3.5",
    "Exp": "1",
    "EmpType__ComplexObj__RID": 3,
    "EmpType__Title__Test": "RID",
    "EmpType__two__Test": 12

将感谢任何有关更正我的代码的帮助,或任何其他存档方法。

【问题讨论】:

您在使用 Visual Studio 吗?如果您将流程附加到您的程序中,您应该能够在逐步完成时准确地看到问题所在 rootPath = rootPath == "" ? jprop.Name : rootPath; 应用程序第一次执行这行代码后条件永远为假 【参考方案1】: 您不需要每次都将属性的值转换为字符串然后再次解析 - 只需将其转换为 JObject 您不需要复杂的条件逻辑来生成属性名称 - 只需使用这个:prefix + jprop.Name + "__"

代码:

public static void FlattenJson(JObject node, JObject result, string prefix = "")

    foreach (var jprop in node.Properties())
    
        if (jprop.Children<JObject>().Count() == 0)
        
            result.Add(prefix + jprop.Name, jprop.Value);
        
        else
        
            FlattenJson((JObject)jprop.Value, $"prefixjprop.Name__", result);
        
    

你可以这样称呼它:

var node = JObject.Parse(/* the input string */);
var result = new JObject();
FlattenJson(node, result);

【讨论】:

只是一个提示:prefix + jprop.Name + "__" 更简洁的方式是 $"prefix jprop.Name__" @Tinwor 我不确定在这种情况下它是否更简洁,但它肯定更简洁。 很棒的代码!!非常适合从任何 json 制作数据表,也可以展平数组: if (jprop.Value.GetType() != typeof(JArray)) ... else result.Add(prefix + "arr_" + jprop.Name, string .Join(",",jprop.Value));【参考方案2】:

您的问题在rootPath = rootPath == "" ? jprop.Name : rootPath; 行。当您第一次遇到 EmpType 时,您正在更改 rootPath,这意味着当您处理 ComplexObj 时,您的 rootPath 是错误的。我相信你的意图只是改变你传递给递归函数的内容。

尽管没有必要将 root 和 currentnode 作为两个单独的项目来跟踪。最好只在代码中跟踪给定节点的当前前缀,看起来更像这样:

public static void ConvertNestedJsonToSimpleJson(JObject input, JObject output, string prefix = "")

    foreach (JProperty jprop in input.Properties())
    
        var name = prefix==""?jprop.Name:String.Format("0__1", prefix,jprop.Name);
        if (jprop.Children<JObject>().Count() == 0)
        
            output.Add(name, jprop.Value);
        
        else
        
            ConvertNestedJsonToSimpleJson((JObject)jprop.Value, output, name);
        
    

这现在给了我输出:


  "FirstName": "Rahul",
  "LastName": "B",
  "EmpType__RID": 2,
  "EmpType__Title": "Full Time",
  "CTC": "3.5",
  "Exp": "1",
  "ComplexObj__RID": 3,
  "ComplexObj__Title__Test": "RID",
  "ComplexObj__Title__TWO__Test": 12

看起来正确。

【讨论】:

感谢您指出错误。它适用于 2 级嵌套,输出 json 中的最后一个字段应该是 "ComplexObj__Title__TWO__Test": 12 啊,是的。看着它,我认为它是因为递归在它的工作方式上有点混乱(根和当前节点被传递)。我强烈怀疑对这段代码的修复最终会看起来像 Botond 对您的代码的出色简洁重写,所以我现在将向您推荐他的答案。 现在用更简单的工作代码更新了我的答案。它与 Botond 的不太一样,但非常相似。【参考方案3】:

你能用 linq 做这样的事情吗

var jsonObj = jobject.select(x => new CustomJson 
   FirstName = x.FirstName,
   LastName = x.LastName,
   EmpTypeId = x.EmpType.Id,
   Title = x.EmpType.Title
   etc etc
);

【讨论】:

是的,我可以这样做,但我的输入 json 动态结构是未知的。抱歉之前没有提到,编辑了我的帖子。 好的,抱歉我现在不知道怎么回答。

以上是关于将嵌套 JSON 转换为简单 JSON的主要内容,如果未能解决你的问题,请参考以下文章

使用 Python 将多个关系表转换为嵌套 JSON 格式

将嵌套对象的JSON转换为Pandas Dataframe

如何使用 xlsx npm 库将嵌套的 json 对象转换为 excel 表?

将嵌套 JSON 转换为平面 JSON

将嵌套 JSON 转换为数据框

将 Pandas 数据框转换为嵌套 JSON