0

I have a json like this:

[
    { "Province1" : [
            { "name" : "city-1" },
            { "name" : "city-2" }
        ]
    },
    { "Province2" : [
            { "name" : "city-1" },
            { "name" : "city-2" }
        ]
    }
]

I want to deserialize it using NewtonsoftJson. I have tried this but the result is null:

public class City {
    public string Name { get; set; }
}

var cities = JsonConvert.DeserializeObject<IEnumerable<KeyValuePair<string, List<City>>>(File.ReadAllText(@"jsonPath"));

How should I dersialize it to a class?

0009laH
  • 1,960
  • 13
  • 27
  • can you modify JSON-structure? Seems like you should use an array of `Province` instead of using indices like `Province2`. Or do you allwqys ever have only those two provinces? – MakePeaceGreatAgain Aug 17 '20 at 07:48
  • You should dersialize to a class, Yes, You can also dersialize to JObject and navigate inside properties – AnGG Aug 17 '20 at 07:49
  • @HimBromBeere I cannot modify structure and my json structure is exact like this. No I have more than two provinces. – Arsalan Valoojerdi Aug 17 '20 at 07:51
  • This *JSON* is flawed. Tts using a ***munted** *array* when it should likely be a *dictionary*. The person who wrote this *schema* should consider their career choices. Your best approach is to just navigate the *JSON* with a `JObject`, and *project* it to a `Dictionary` – TheGeneral Aug 17 '20 at 07:54
  • https://stackoverflow.com/questions/44433732/dynamically-change-the-json-property-name-and-serialize/44435284 – Mihir Dave Aug 17 '20 at 08:19

3 Answers3

3

After fiddling around with it a bit, I've come up with this structure to deserialize it

class MyDeserializer
{
    public static void Deserialize()
    {
        var json = "[{\"Province1\" : [{\"name\" : \"city-1\" }, {\"name\" : \"city-2\" }] }, {\"Province2\" : [{ \"name\" : \"city-1\" }, { \"name\" : \"city-2\" }] } ]";

        var cities = JsonConvert.DeserializeObject<List<Dictionary<string, List<City>>>>(json);

        Console.WriteLine(cities[0]["Province1"][0].Name);
    }
}

class City
{
    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }
}

That gives you a dictionary for each province which seems a little unintuitive. But that's how your JSON is structured. If you want to combine all the dictionaries into one, you can do it like this

    var cities = JsonConvert.DeserializeObject<List<Dictionary<string, List<City>>>>(json).SelectMany(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value);
    Console.WriteLine(cities["Province1"][0].Name);
Hans Kilian
  • 18,948
  • 1
  • 26
  • 35
1

I think your structure should be like this :

[
    { "Name": "Province1",
        "Cities": [
            { "name": "city-1" },
            { "name": "city-2" }
        ]
    },
    { "Name": "Province2",
        "Cities": [
            { "name": "city-1" },
            { "name": "city-2" }
        ]
    }
]

And to deserilize it :

namespace ConsoleApp2 {
    public class Province {
        public string Name { get; set; }
        public List<City> Cities { get; set; }
    }

    public class City {
        public string Name { get; set; }
    }

    public class ConsoleApp2 {
        public static void Main(string[] args) {
            List<Province> provinces = JsonConvert.DeserializeObject<List<Province>>(File.ReadAllText("province.json"));
        }
    }
}
0009laH
  • 1,960
  • 13
  • 27
AnGG
  • 679
  • 3
  • 9
1

There is probably a more elegant solution to this, however this will give you a dictionary of province name with an array of city name Dictionary<string,string[]>

var dict = JArray
        .Parse(input)
        .Cast<JObject>()
        .Select(x => x.Properties().First())
        .ToDictionary(
           x => x.Name, 
           x => x.Values().Values().Select(x => x.First.ToString()).ToArray());
TheGeneral
  • 79,002
  • 9
  • 103
  • 141