1

I am trying to deserialize a JSON file which elements are in the following format:

{"include\\fooo\\Gell.h": {
    "parents": [
        "include\\rfg\\ExplorableMa.h"
    ],
    "children": [
        "include\\rfg\\IEditable.h",
        "include\\rfg\\IExplorable.h",
        "Bar"
    ]
}}

There may be 1 or more elements following each other in the JSON file. I tried using the System.Runtime.Serialization.Json namespace, but I did not have much success with this code:

[DataContract]
class Vertex
{
    [DataMember] public string Path { get; set; }
}

using (Stream stream = File.OpenRead(@"file.json"))
{
    var serializer = new DataContractJsonSerializer(typeof(Vertex[]));
    Vertex[] verteces = (Vertex[])serializer.ReadObject(stream);
    // the array is not valid at this point
}

The code above is supposed to fill the array with a single vertex and its path equal to "include\\fooo\\Gell.h" in this specific case to start. What is the correct way to deserialize such a JSON file?

ASh
  • 34,632
  • 9
  • 60
  • 82
Nick
  • 10,309
  • 21
  • 97
  • 201
  • 1
    Have you heard of `Json.net`? – Blue Feb 23 '18 at 21:05
  • @dbc I edited the json, now it is valid. – Nick Feb 23 '18 at 21:08
  • @FrankerZ No, I didn't. I would prefer to not use 3rd party libraries. How come does it have to be so difficult to parse JSON in .Net? Such a standard format. – Nick Feb 23 '18 at 21:09
  • Why not use a well supported 3rd party library? And why are you trying to deserialize to a Vertex array? And why doesn't your object you're to deserialize match the JSON stucture? I see no Path property in your JSON. – mason Feb 23 '18 at 21:13
  • @mason what would be the name of the property in the Vertex class considering that each element can have a different name? – Nick Feb 23 '18 at 21:14
  • 1
    Use Newtonsoft.Json. It is a 3d party, it is an Asp.Net mvc core dependency though. Worth to be considered reliable. – Ivan Zaruba Feb 23 '18 at 21:15
  • The name is the least your worries. The JSON and the class you're deserializing to are wildly different. You'd need a class that has a Parents property and a children property. Each of those would likely be an array of strings. You really need to think about how the object should be represented in C# instead of just making up a random class and hoping it will serialize/deserialize. You're saying "why is it so difficult to parse JSON in .NET" when the reality is you're making it difficult. – mason Feb 23 '18 at 21:17
  • Have a look at [json2csharp](http://json2csharp.com/) which does a passable job of generating an appropriate C# class based on some JSON. – mason Feb 23 '18 at 21:18
  • @mason having parents and children properties are not sufficient, that name is the problem, how do I represent it in the Vertex class? – Nick Feb 23 '18 at 21:19
  • Which version of .Net are you using? If you are using .Net 4.5 you can deserialize to a dictionary with `DataContractJsonSerializer` by setting `UseSimpleDictionaryFormat = true` as shown [here](https://stackoverflow.com/a/27223290/3744182). If not it will be very difficult to use `DataContractJsonSerializer`. Either way [tag:json.net] could be a better choice. – dbc Feb 23 '18 at 21:23
  • @dbc How would I deserialize it with json.net? – Nick Feb 23 '18 at 21:28

2 Answers2

2

Using Json.Net you could deserialize your file in this way (or similar):

using System.Collections.Generic;
using System.Windows;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

class Vertex
{
    [JsonExtensionData]
    public IDictionary<string, JToken> _additionalData;
}

var content = File.ReadAllText(@"file.json");
var d = JsonConvert.DeserializeObject<Vertex>(content);

Have a look at these examples: http://james.newtonking.com/archive/2013/05/08/json-net-5-0-release-5-defaultsettings-and-extension-data

gliderkite
  • 8,828
  • 6
  • 44
  • 80
0

Firstly, note that your root JSON container is an object, not an array. The JSON standard specifies the following types of container:

  • The array which an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).

    Most JSON serializers map .Net enumerables to JSON arrays.

  • The object which is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace).

    Most JSON serializers map dictionaries and non-enumerable, non-primitive types to JSON objects.

Thus you will need to deserialize to a different type, one which maps to an object with custom, variable property names that have values with fixed schema. Most serializers support to Dictionary<string, TValue> in such situations.

First define the following type:

public class VertexData
{
    public List<string> parents { get; set; }
    public List<string> children { get; set; }
}

Then, using you can deserialize to a Dictionary<string, VertexData> as follows as long as you are using .Net 4.5 or later as explained in this answer:

var serializer = new DataContractJsonSerializer(typeof(Dictionary<string, VertexData>)) { UseSimpleDictionaryFormat = true };
var vertices = (Dictionary<string, VertexData>)serializer.ReadObject(stream);
var paths = vertices.Keys.ToList();

If you would prefer to use you can deserialize to the same Dictionary<string, VertexData> as follows:

using (var reader = new StreamReader(stream))
using (var jsonReader = new JsonTextReader(reader))
{
    var vertices = JsonSerializer.CreateDefault().Deserialize<Dictionary<string, VertexData>>(jsonReader);
    var paths = vertices.Keys.ToList();
}

And finally with :

using (var reader = new StreamReader(stream))
{
    var jsonString = reader.ReadToEnd();

    var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    var vertices = serializer.Deserialize<Dictionary<string, VertexData>>(jsonString);
    var paths = vertices.Keys.ToList();
}
dbc
  • 104,963
  • 20
  • 228
  • 340