将嵌套的JSON转换为简单的JSON

时间:2022-01-21 00:17:06

I'm trying to convert a nested json to simple json by recursively traversing. (Structure of input json is unknown)

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

for example, I want json like this

例如,我想要像这样的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
            }
        }
    }
}

to be converted something like this

要转换成这样的东西

{
    "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
}

each fields in nested object will be changed to key which represents its actual path.

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

this is what I have done so far.

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

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

and getting wrong result

并得到错误的结果

{
    "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
}

will appreciate any help on correcting my code, or any other approach to archive this.

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

3 个解决方案

#1


4  

  • You don't need to convert the value of the property to string and then parse it again every time - just cast it to JObject
  • 您不需要将属性的值转换为字符串,然后每次再次解析它 - 只需将其转换为JObject

  • You don't need the complicated conditional logic to generate the name of the property - just use this: prefix + jprop.Name + "__"
  • 您不需要复杂的条件逻辑来生成属性的名称 - 只需使用:prefix + jprop.Name +“__”

The code:

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, $"{prefix}{jprop.Name}__", result);
        }
    }
}

You can call it like this:

你可以这样称呼它:

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

#2


4  

Your problem is in the line rootPath = rootPath == "" ? jprop.Name : rootPath;. You are changing the rootPath when you first come across EmpType which means when you process ComplexObj your rootPath is wrong. What I believe you intended is just to change what you were passing into the recursive function.

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

As it is though it is unnecessary to keep track of root and currentnode as two separate items. Better would be to just track the current prefix for a given node in code that looks more like this:

虽然没有必要将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);
        }
    }
}

This now gives me the output:

现在这给了我输出:

{
  "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
}

which looks correct.

看起来是正确的。

#3


1  

Could you do something like this using linq

你能用linq做这样的事吗?

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

#1


4  

  • You don't need to convert the value of the property to string and then parse it again every time - just cast it to JObject
  • 您不需要将属性的值转换为字符串,然后每次再次解析它 - 只需将其转换为JObject

  • You don't need the complicated conditional logic to generate the name of the property - just use this: prefix + jprop.Name + "__"
  • 您不需要复杂的条件逻辑来生成属性的名称 - 只需使用:prefix + jprop.Name +“__”

The code:

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, $"{prefix}{jprop.Name}__", result);
        }
    }
}

You can call it like this:

你可以这样称呼它:

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

#2


4  

Your problem is in the line rootPath = rootPath == "" ? jprop.Name : rootPath;. You are changing the rootPath when you first come across EmpType which means when you process ComplexObj your rootPath is wrong. What I believe you intended is just to change what you were passing into the recursive function.

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

As it is though it is unnecessary to keep track of root and currentnode as two separate items. Better would be to just track the current prefix for a given node in code that looks more like this:

虽然没有必要将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);
        }
    }
}

This now gives me the output:

现在这给了我输出:

{
  "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
}

which looks correct.

看起来是正确的。

#3


1  

Could you do something like this using linq

你能用linq做这样的事吗?

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