如何反序列化对象结构未知的 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反序列化为动态变量,但我不确定如何处理两个问题:

  1. 我的JSON格式未知,我不知道对象有多深,我该如何处理?
  2. 在运行时定义动态变量时,如何使用动态变量?

编辑

抱歉,我原来的 JSON 格式是错误的,因此它不适用于 user12864 提供的答案。 我收到错误:Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.

这是一个小提琴,显示了我目前所处的位置。

如何反序列化对象结构未知的 JSON 对象

@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'
}

您只需将此核心功能与您的实现相关联。 这种方法很粗糙,相当简陋,肯定需要改进才能生产。 但是,这应该可以让您开始:

  • 序列化服务器上的数据。
  • 反序列化服务器数据。
  • 操作对象。

希望这对你更好。