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
- You don't need the complicated conditional logic to generate the name of the property - just use this:
prefix + jprop.Name + "__"
您不需要将属性的值转换为字符串,然后每次再次解析它 - 只需将其转换为JObject
您不需要复杂的条件逻辑来生成属性的名称 - 只需使用: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
- You don't need the complicated conditional logic to generate the name of the property - just use this:
prefix + jprop.Name + "__"
您不需要将属性的值转换为字符串,然后每次再次解析它 - 只需将其转换为JObject
您不需要复杂的条件逻辑来生成属性的名称 - 只需使用: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
});