如何反序列化对象结构未知的 JSON 对象
本文关键字:对象 JSON 未知 结构 反序列化 | 更新日期: 2023-09-27 18:29:06
我的部分代码以以下格式将机器的文件路径序列化为JSON。我正在努力采用这个 JSON 并将文件路径重新组合在一起。 我正在使用牛顿软件 JSON 库;我发现它非常适合构建 JSON。如您所见,我的 JSON 具有嵌套对象。
我拥有的 JSON:
{
".": {
"proc": {
"15": {
"task": {
"15": {
"exe": {},
"mounts": {
"list_of_files": [
"mounts.xml"
]
},
"mountinfo": {
"list_of_files": [
"mountinfo.xml"
]
},
"clear_refs": {
"list_of_files": [
"clear_ref.xml"
]
}
}
}
},
"14": {
"loginuid": {
"list_of_files": [
"loginuid.xml"
]
},
"sessionid": {
"list_of_files": [
"sessionid.xml"
]
},
"coredump_filter": {
"list_of_files": [
"coredump_filter.xml"
]
},
"io": {
"list_of_files": [
"io.xml"
]
}
}
}
}
}
我想从中生成的数组。
string[] dirArray = {
"./proc/15/task/15/exe",
"./proc/15/task/15/mounts/mounts.xml",
"./proc/15/task/15/mountinfo/mountinfo.xml",
"./proc/15/task/15/clear_refs/clear_ref.xml",
"./proc/14/loginuid/loginuid.xml",
"./proc/14/sessionid/sessionid.xml",
"./proc/14/coredump_filter/coredump_filter.xml",
"./proc/14/io/io.xml"
}
到目前为止,我的努力 - 我将JSON反序列化为动态变量,但我不确定如何处理两个问题:
- 我的JSON格式未知,我不知道对象有多深,我该如何处理?
- 在运行时定义动态变量时,如何使用动态变量?
编辑
抱歉,我原来的 JSON 格式是错误的,因此它不适用于 user12864 提供的答案。 我收到错误:Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.
这是一个小提琴,显示了我目前所处的位置。
@user12864在他的答案中有正确的想法,但代码需要调整以考虑到每个目录可以有一个文件数组而不是单个"文件"对象的事实(你真的应该在你的问题中提到它最初(。 以下是处理该问题的更新方法:
private static void AddToFileList(JObject jo, List<string> list, string prefix)
{
foreach (var kvp in jo)
{
if (kvp.Key == "list_of_files")
{
foreach (string name in (JArray)kvp.Value)
{
list.Add(prefix + name);
}
}
else
{
JObject dir = (JObject)kvp.Value;
if (dir.Count == 0)
{
list.Add(prefix + kvp.Key);
}
else
{
AddToFileList(dir, list, prefix + kvp.Key + "/");
}
}
}
}
完整演示:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
class Program
{
static void Main(string[] args)
{
string json = @"
{
""."": {
""proc"": {
""15"": {
""task"": {
""15"": {
""exe"": {},
""mounts"": {
""list_of_files"": [
""mounts.xml""
]
},
""mountinfo"": {
""list_of_files"": [
""mountinfo.xml""
]
},
""clear_refs"": {
""list_of_files"": [
""clear_ref.xml""
]
}
}
}
},
""14"": {
""loginuid"": {
""list_of_files"": [
""loginuid.xml""
]
},
""sessionid"": {
""list_of_files"": [
""sessionid.xml""
]
},
""coredump_filter"": {
""list_of_files"": [
""coredump_filter.xml""
]
},
""io"": {
""list_of_files"": [
""io.xml""
]
}
}
}
}
}";
JObject jo = JObject.Parse(json);
foreach (string path in CreateFileList(jo))
{
Console.WriteLine(path);
}
}
private static List<string> CreateFileList(JObject jo)
{
List<string> ret = new List<string>();
AddToFileList(jo, ret, "");
return ret;
}
private static void AddToFileList(JObject jo, List<string> list, string prefix)
{
foreach (var kvp in jo)
{
if (kvp.Key == "list_of_files")
{
foreach (string name in (JArray)kvp.Value)
{
list.Add(prefix + name);
}
}
else
{
JObject dir = (JObject)kvp.Value;
if (dir.Count == 0)
{
list.Add(prefix + kvp.Key);
}
else
{
AddToFileList(dir, list, prefix + kvp.Key + "/");
}
}
}
}
}
输出:
./proc/15/task/15/exe
./proc/15/task/15/mounts/mounts.xml
./proc/15/task/15/mountinfo/mountinfo.xml
./proc/15/task/15/clear_refs/clear_ref.xml
./proc/14/loginuid/loginuid.xml
./proc/14/sessionid/sessionid.xml
./proc/14/coredump_filter/coredump_filter.xml
./proc/14/io/io.xml
小提琴:https://dotnetfiddle.net/r8CkI2
这应该准确地给出您正在寻找的内容; 只需创建一个带有JObject.Parse
JObject
并将其传递给CreateFileList
。 它不会以任何好的方式处理格式错误的 JSON。
static List<string> CreateFileList(JObject j)
{
List<string> ret = new List<string>();
AddToFileList(j, ret, "");
return ret;
}
static void AddToFileList(JObject j, List<string> dest, string prefix)
{
if (prefix.Length != 0)
prefix = prefix + '/';
foreach (var kvp in j)
{
var jnext = (JObject)kvp.Value;
if (kvp.Key == "file")
dest.Add(prefix + (string)jnext["name"]);
else
AddToFileList(jnext, dest, prefix + kvp.Key);
}
}
摆弄 https://dotnetfiddle.net/dQQ4tI
更新:
以下是在您明确以下要求后修订的答案:
JavaScript 对象表示法构建在服务器上,由用户通过分层树接口组件进行编辑。这可以非常容易地爬行。
所以本质上你利用了一个组件,你希望在其中构建从组件派生的简单的JavaScript对象符号。您的用户界面将是未知的,所以我会做一些假设。
构建我们的对象:
public class XmlPath
{
public string Location { get; set; }
}
XmlPath
将代表我们的对象。 这将是基本的汽车属性。
向对象添加内容:
private List<XmlPath> AddXmlPath(List<string> location)
{
List<XmlPath> content = new List<XmlPath>();
foreach(string item in location)
content.Add(new XmlPath() { Location = item });
return content;
}
这将是非常简单的方法,它将占用大量用户数据List<string>
并将它们添加到您的XmlPath
对象中。
从我们的对象中删除内容:
private List<XmlPath> RemoveXmlPath(List<XmlPath> root, string location)
{
root.Remove(new XmlPath() { Location = location });
return root;
}
这两种方法真的不需要,我只是在演示和展示你如何做。 此外,它将概述意图,以便您更容易实现。 请注意,这是非常粗糙的方法。
将我们的对象序列化/反序列化为 JavaScript 异议表示法:
JavaScriptSerializer serializer = new JavaScriptSerializer();
var xmlPath = AddXmlPath(List<string> location);
var result = serializer.Serialize(xmlPath);
var deserialize = serializer.Deserialize(List<XmlPath>>(result);
我们的内容现在通过一个基本循环公开:
foreach(XmlPath item in deserialize)
{
// Exposed Model via 'item.Location'
}
您只需将此核心功能与您的实现相关联。 这种方法很粗糙,相当简陋,肯定需要改进才能生产。 但是,这应该可以让您开始:
- 序列化服务器上的数据。
- 反序列化服务器数据。
- 操作对象。
希望这对你更好。