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

问题描述:

我的代码的一部分以下面的格式将计算机的文件路径序列化为JSON。我正在努力接受这个JSON,并重新将文件路径重新组合在一起。我正在使用Newtonsoft 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" 
} 

我的努力,我far--的deserialised JSON成一个动态的变量,但我不知道如何处理两个问题:

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

编辑

对不起,我原来的JSON格式是错误的,所以它不会与user12864提供的answer工作。我收到一个错误:Unable to cast object of type 'Newtonsoft.Json.Linq.JArray' to type 'Newtonsoft.Json.Linq.JObject'.

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

+0

我可以建议你放弃所有的层次和而只是将每个路径存储为完整的路径? .NET中的'Path' API应足以确定代码的层次结构。整个事情会更容易处理,并且由此产生的JSON将更具可读性。 – mason 2014-11-03 15:39:08

+0

但是,如果我拥有的是json,我需要从中获得路径。也许我误解你的评论? json首先的原因是允许UI消费者以可导航的方式显示路径。我现在编写的代码是要了解他们选择保留哪些路径,UI将编辑json并发送回去,为了执行某些任务,我需要解构为路径。 – Fearghal 2014-11-03 15:39:50

+0

我在说你应该改变你的格式。只要它是一个JSON数组文件,不要以分层的方式存储它。 – mason 2014-11-03 15:42:06

@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

+0

那就是布莱恩。这是绝妙的,在示例json上学到的教训,那是我的错。你直接了解问题(尽管我),并且如此雄辩地解决它。 thx再次先生。我等了几个小时,所以我可以添加一个赏金,然后标记为已解决。 – Fearghal 2014-11-05 10:25:13

更新:


这里是一个修改后的答案,你明确你的要求后:

The JavaScript Object Notation is built on the server, edited by user through a hierarchical tree interface component. That can be crawled incredibly easy.

因此,在本质您使用的组件,其中你希望建立简单从组件派生的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' 
} 

你只需要这一核心功能关联到你的实现。这种方法很粗糙,相当简陋,肯定需要改进生产。然而,这应该让你开始:

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

希望这对你更好。

+0

不是它的一个由用户在分层树接口组件中编辑的json(构建在服务器上)。因为用户可能会删除json的任何节点(我使用json来允许轻松导航),所以我需要能够抓取它的每个部分。该例子涵盖了它可能的样子。 – Fearghal 2014-11-03 17:39:57

+0

我已经为你修改了我的答案。 – Greg 2014-11-03 18:56:02

这应该给你正在寻找什么;只需创建一个JObjectJObject.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

+0

Fantatsic,我得到一个错误,但是:无法转换'Newtonsoft.Json.Linq.JValue'类型的对象键入'Newtonsoft.Json.Linq。JObject' – Fearghal 2014-11-03 16:10:30

+0

这种错误和其他类似的错误将发生在JSON上,并不完全匹配预期的布局。我在你发布的确切JSON文本上测试了这个确切的代码,并且没有错误。 – user12864 2014-11-03 16:19:45

+0

好的,我想我去搜索这个问题 – Fearghal 2014-11-03 16:27:46