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

时间:2014-11-03 15:21:44

标签: c# json json.net

我的部分代码将机器的文件路径序列化为JSON,格式如下。我正在努力采用这个JSON并将文件路径重新组合在一起。我正在使用Newtonsoft JSON lib;我发现它非常适合构建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. 如何在运行时定义动态变量时使用动态变量?
  3. 修改

    抱歉,我的原始JSON格式错误,因此它无法使用user12864提供的answer。我收到了错误:Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.

    这是fiddle,显示我到目前为止的位置。

3 个答案:

答案 0 :(得分:2)

这应该准确地给出你正在寻找的东西;只需使用JObject创建JObject.Parse并将其传递给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

处小提琴

答案 1 :(得分:2)

@user12864在他的回答中有正确的想法,但需要调整代码以解释每个目录可以有一个文件数组而不是单个&#34;文件&#34;对象(你真的应该在最初的问题中提到过)。这是一个更新的方法来处理:

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

答案 2 :(得分:0)

<强>更新


在您澄清了以下要求之后,这是一个修订后的答案:

  

JavaScript Object Notation构建在服务器上,由用户通过分层树接口组件进行编辑。这可以非常容易地抓取。

因此,从本质上讲,您使用的是一个组件,您希望在该组件中构建从组件派生的简单JavaScript Object Notation。您的用户界面将是未知的,因此我会做出一些假设。

构建我们的对象:

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

您只需将此核心功能与您的实施相关联即可。这种方法粗糙,相当简陋,绝对需要改进生产。但是,这应该让你开始:

  • 序列化服务器上​​的数据。
  • 反序列化服务器数据。
  • 操纵物体。

希望这对你更好。