将嵌套 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的主要内容,如果未能解决你的问题,请参考以下文章