Search code examples
c#arraysjsongetjson

How to parse JSON object with another object childen with C#


I need the name of property of a property's object :

here is my code:

JSON example:

 {
"dados":      [{"codigo_localidade":"1",
"localidade":"Adamantina",
"nome_localidade_pai":"Regi\u00e3o de Governo de Adamantina",
"codigo_variavel":"2",
"variavel":"Cr\u00e9dito Rural Agricultura",
"unidade":"(Em reais de 2015)",
"periodo":"1985\/1989-2011",
"ano":{"2010":"194.140.750"}
}

My C# CODE to parse my JSON:

  var resultObjects = AllChildren(JObject.Parse(cidadesSON))
                     .First(c => c.Type == JTokenType.Array && c.Path.Contains("dados"))
                     .Children<JObject>();

                    List<Cidade> cidades = new List<Cidade>();
                    Cidade item;
//fetch my array 
                    foreach (JObject result in resultObjects)
                    {
                        item = new Cidade();
                        item.localidade =(string)result["localidade"];
                        item.nome_localidad_pai =    (string)result["nome_localidade_pai"];
                        item.populacao = (string)result["ano"]["2010"];

                        //my problem
                        item.ano = ((JObject)result.["ano"]).Property("2010").Name;

                     cidades.Add(item);

                    }



                    grvCandidatos.DataSource = cidades;
                    grvCandidatos.CssClass = "table table-hover ";
                    grvCandidatos.DataBind();

This is the method to get the object

private static IEnumerable<JToken> AllChildren(JToken json)
        {
            foreach (var c in json.Children())
            {
                yield return c;
                foreach (var cc in AllChildren(c))
                {
                    yield return cc;
                }
            }
        }

If necessary, here is my Model class:

public class Cidade
        {
            public string localidade { get; set; }
            public string populacao { get; set; }
            public string nome_localidad_pai { get; set; }
            public string ano { get; set; }

        }

If somebody could help i would be very thankful.

(Sorry about my english.)


Solution

  • TL;DR

    The problem with your code is that we don't know what's the type of the ano property. You could map that property to a Dictionary<string,object> and and get the actual ano by accessing the Key property of the Dictionary. See below an example of how you can do this:

    Assuming you can use 3rd party libraries in your program, you can pretty much reduce all your code to this by adding Json.Net into your project:

    "Dado" class

    public class Dado
    {
        public string localidade { get; set; }
        public string populacao { get; set; }
        public string nome_localidad_pai { get; set; }
    
        [JsonConverter(typeof(AnoConverter))]
        public string ano { get; set; }
    }
    

    "Root" class

    public class RootObject
    {
        public List<Dado> dados { get; set; }
    }
    

    Then, you can create a custom JsonConverter to manipulate the deserialization of your json:

    public class AnoConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            throw new NotImplementedException();
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            //This deserialize the Ano into a Dictionary,
            //and returns the Key that contains the actual Year you want
    
            var ano  = serializer.Deserialize<Dictionary<string, object>>(reader);
    
            //I'm assuming that there will be always one year here.
            return ano.FirstOrDefault().Key;
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    Now in your program, just do this to deserialize your json into your strongly typed class:

    //Just reading the json from a file, nothing new here...
    string json = String.Empty;
    using (StreamReader r = new StreamReader("example.json"))
    {
        json = r.ReadToEnd();
    }
    
    //Deserialize in json into a "RootObject"
    var list = JsonConvert.DeserializeObject<RootObject>(json);
    

    This will give you a result like this: enter image description here

    Note You can do the same process of creating a custom JsonConverter for your populacao field but instead of accessing the Key, you access the value. Same logic. I haven't done it on purpose so you can do it yourself and learn :)