How to convert array of file paths to hierarchical JSON structure

I am trying to create a JSON of a machine directory structure given an array of all its files and paths.

The array looks something like this:

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

      

The target JSON I'm targeting looks something like this:

{
   ".":
   {
        "file":
        {
            "name":"fileInRoot.xml"
        },
        "proc":
        {
            "file":
            {
                "name":"fileInProc.xml"
            },
            "15":
            {
                "file":
                {
                    "name":"fileIn15.xml"
                },
                "task":
                {
                    "file":
                    {
                        "name":"fileInTask.xml"
                    },
                    "15":
                    {
                        "file":
                        {
                            "name":"fileInTask.xml"
                        },
                        "mounts":
                        {
                            "file":
                            {
                                "name":"fileInMounts.xml"
                            }
                        },
                        "mountsInfo":
                        {
                            "file":
                            {
                                "name":"fileInMountsInfo.xml"
                            }
                        },
                        "clear_refs":
                        {
                            "file":
                            {
                                "name":"fileInClear_Refs.xml"
                            }
                        }                   
                    }
                }
            },
            "14":
            {
                "file":
                {
                    "name":"fileIn14.xml"
                },
                "task":
                {
                    "file":
                    {
                        "name":"fileInTask.xml"
                    },
                    "loginUid":
                    {
                        "file":
                        {
                            "name":"fileInloginUid.xml"
                        }                   
                    },
                    "sessionid":
                    {
                        "file":
                        {
                            "name":"fileInsessionid.xml"
                        }                   
                    },
                    "coreDump_filter":
                    {
                        "file":
                        {
                            "name":"fileIncoreDump_filter.xml"
                        }                   
                    },
                    "io":
                    {
                        "file":
                        {
                            "name":"fileInIo.xml"
                        }                   
                    }
                }
            }
        }
    }
}

      

I want to create a JSON file that allows a custom JSON component to navigate this directory structure. I'm trying to use classes Directory

, File

and Path

, but perhaps the best way is to use the java.serializor (?) Class to build the JSON as I go through the array, parsing its directories and files, how do I go?

+3


source to share


1 answer


I think I would approach this problem by breaking it down into two parts. First, we need a way to parse the array of directory / file paths and place it in a hierarchical structure. Secondly, we need to take this structure and turn it into JSON. (I was not completely sure about your question which serializer you wanted to use, so for this answer, I am assuming Json.Net is ok.)

In the first part, I would create a class Dir

that has a name, a dictionary of child directories (for simple searches), and a set of files. We can make a method in this class that will parse a separate path and either find or add the appropriate child objects.

class Dir
{
    public string Name { get; set; }
    public Dictionary<string, Dir> Dirs { get; set; }
    public HashSet<string> Files { get; set; }

    public Dir(string name)
    {
        Name = name;
        Dirs = new Dictionary<string, Dir>();
        Files = new HashSet<string>();
    }

    public Dir FindOrCreate(string path, bool mightBeFile = true)
    {
        int i = path.IndexOf('/');
        if (i > -1)
        {
            Dir dir = FindOrCreate(path.Substring(0, i), false);
            return dir.FindOrCreate(path.Substring(i + 1), true);
        }

        if (path == "") return this;

        // if the name is at the end of a path and contains a "." 
        // we assume it is a file (unless it is "." by itself)
        if (mightBeFile && path != "." && path.Contains("."))
        {
            Files.Add(path);
            return this;
        }

        Dir child;
        if (Dirs.ContainsKey(path))
        {
            child = Dirs[path];
        }
        else
        {
            child = new Dir(path);
            Dirs.Add(path, child);
        }
        return child;
    }
}

      

Using this class, we can easily loop through the loop dirArray

given in your question and create a directory hierarchy:

Dir root = new Dir("");
foreach (string dir in dirArray)
{
    root.FindOrCreate(dir);
}

      

So, at the moment root

now has the entire directory hierarchy. If you'd like, you can simply serialize this object directly from Json.Net to get a sane JSON structure. However, this will be a little more verbose than what you described in your question. Here is the JSON to be released:

{
  "Name": "",
  "Dirs": {
    ".": {
      "Name": ".",
      "Dirs": {
        "proc": {
          "Name": "proc",
          "Dirs": {
            "15": {
              "Name": "15",
              "Dirs": {
                "task": {
                  "Name": "task",
                  "Dirs": {
                    "15": {
                      "Name": "15",
                      "Dirs": {
                        "exe": {
                          "Name": "exe",
                          "Dirs": {},
                          "Files": []
                        },
                        "mounts": {
                          "Name": "mounts",
                          "Dirs": {},
                          "Files": [
                            "mounts.xml"
                          ]
                        },
                        "mountinfo": {
                          "Name": "mountinfo",
                          "Dirs": {},
                          "Files": [
                            "mountinfo.xml",
                            "moremountinfo.xml"
                          ]
                        },
                        "clear_refs": {
                          "Name": "clear_refs",
                          "Dirs": {},
                          "Files": [
                            "clear_ref.xml"
                          ]
                        }
                      },
                      "Files": []
                    }
                  },
                  "Files": []
                }
              },
              "Files": []
            },
            "14": {
              "Name": "14",
              "Dirs": {
                "loginuid": {
                  "Name": "loginuid",
                  "Dirs": {},
                  "Files": [
                    "loginuid.xml"
                  ]
                },
                "sessionid": {
                  "Name": "sessionid",
                  "Dirs": {},
                  "Files": [
                    "sessionid.xml"
                  ]
                },
                "coredump_filter": {
                  "Name": "coredump_filter",
                  "Dirs": {},
                  "Files": [
                    "coredump_filter.xml"
                  ]
                },
                "io": {
                  "Name": "io",
                  "Dirs": {},
                  "Files": [
                    "io.xml"
                  ]
                }
              },
              "Files": []
            }
          },
          "Files": []
        }
      },
      "Files": []
    }
  },
  "Files": []
}

      



To get the JSON you are aiming for, we need a class JsonConverter

:

class DirConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Dir));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Dir dir = (Dir)value;
        JObject obj = new JObject();
        if (dir.Files.Count > 0)
        {
            JArray files = new JArray();
            foreach (string name in dir.Files)
            {
                files.Add(new JValue(name));
            }
            obj.Add("list_of_files", files);
        }
        foreach (var kvp in dir.Dirs)
        {
            obj.Add(kvp.Key, JToken.FromObject(kvp.Value, serializer));
        }
        obj.WriteTo(writer);
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

      

We can serialize the directory hierarchy using this converter like this:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new DirConverter());
settings.Formatting = Formatting.Indented;

string json = JsonConvert.SerializeObject(root, settings);

      

Here is the result. Note that I changed the file properties in the original JSON to arrays and renamed it to "list_of_files" to accommodate multiple files in a directory for your comments. I also assume there will never be an actual directory called "list_of_files". If possible, you will need to change the file array name to something else that will not clash with any of your directory names. (If you encounter an error that says " Can not add property list_of_files to Newtonsoft.Json.Linq.JObject. Property with the same name already exists on object

", then you have a directory somewhere in your data named "list_of_files".)

{
  ".": {
    "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"
          ]
        }
      }
    }
  }
}

      

Fiddle: https://dotnetfiddle.net/ConJiu

+8


source







All Articles