Home > Software engineering >  Deserialize JSON with unknown value name and get said name in C#
Deserialize JSON with unknown value name and get said name in C#

Time:11-17

I'm trying to deserialize a JSON response from an API and get the NAME of what in this example is "af" (country code of Afghanistan) inside "iso", but the name of the field will be different everytime based on the country code, how can i read the name of the field and retrieve each country code in the api response? thanks!

Example response:

{
   "afghanistan":{
      "iso":{
         "af":1
      },
      "prefix":{
         " 93":1
      },
      "text_en":"Afghanistan",
      "text_ru":"Афганистан",
      "virtual21":{
         "activation":1
      },
      "virtual23":{
         "activation":1
      },
      "virtual29":{
         "activation":1
      },
      "virtual30":{
         "activation":1
      },
      "virtual31":{
         "activation":1
      },
      "virtual32":{
         "activation":1
      },
      "virtual4":{
         "activation":1
      }
   }
}

This goes on for a very large list of countries

this is how i am currently deserializing:

  var response = JsonConvert.DeserializeObject<Dictionary<string, ResponseFields>>(json);

And this is the VS-generated ResponseFields class:

public class ResponseFields
{
    public Iso iso { get; set; }
    public Prefix prefix { get; set; }
    public string text_en { get; set; }
    public string text_ru { get; set; }
    public Virtual21 virtual21 { get; set; }
    public Virtual23 virtual23 { get; set; }
    public Virtual29 virtual29 { get; set; }
    public Virtual30 virtual30 { get; set; }
    public Virtual31 virtual31 { get; set; }
    public Virtual32 virtual32 { get; set; }
    public Virtual4 virtual4 { get; set; }
}

public class Iso
{
    public int af { get; set; }
}

public class Prefix
{
    public int _93 { get; set; }
}

public class Virtual21
{
    public int activation { get; set; }
}

public class Virtual23
{
    public int activation { get; set; }
}

public class Virtual29
{
    public int activation { get; set; }
}

public class Virtual30
{
    public int activation { get; set; }
}

public class Virtual31
{
    public int activation { get; set; }
}

public class Virtual32
{
    public int activation { get; set; }
}

public class Virtual4
{
    public int activation { get; set; }
}

Printing to console as follows:

foreach (var field in response)
      {
        Console.WriteLine($"Name: {(field.Key)} \nCode: {field.Value.iso}");


    }

Produces:

Name: afghanistan
Code: Iso
Name: albania
Code: Iso
Name: algeria
Code: Iso

vs Expected output:

Name: afghanistan
Code: af
Name: albania
Code: al
...

this is the closest post on SO i could manage to pull from google

CodePudding user response:

you can accomplish your task in one line

var countries = JObject.Parse(json).Properties()
                                       .Select(jo => new
                                       {
                                         name = jo.Name,
                                         code = ((JObject)jo.Value["iso"]).Properties().First().Name
                                       }).ToList();

CodePudding user response:

Is iso guaranteed to only have the single property? If so, you can just read the children by index instead of name.

CodePudding user response:

You can use Dictionary<string, int> to represent the Iso too (as you do with the root):

public class ResponseFields
{
    // ...
    public Dictionary<string, int> Iso { get; set; }
    // ...
}

And output line can be:

Console.WriteLine($"Name: {(field.Key)} \nCode: {field.Value.Iso.Keys.FirstOrDefault()}");

CodePudding user response:

Solution without using predefined types but navigating the object structure.

string input = @"
    {
       ""afghanistan"":{
          ""iso"":{
             ""af"":1
          },
          ""prefix"":{
             "" 93"":1
          },
          ""text_en"":""Afghanistan"",
          ""text_ru"":""Афганистан"",
          ""virtual21"":{
             ""activation"":1
          },
          ""virtual23"":{
             ""activation"":1
          },
          ""virtual29"":{
             ""activation"":1
          },
          ""virtual30"":{
             ""activation"":1
          },
          ""virtual31"":{
             ""activation"":1
          },
          ""virtual32"":{
             ""activation"":1
          },
          ""virtual4"":{
             ""activation"":1
          }
       },
      ""albania"":{
          ""iso"":{
             ""al"":1
          },
          ""prefix"":{
             "" 98"":1
          },
          ""text_en"":""Albania"",
          ""virtual21"":{
             ""activation"":1
          },
          ""virtual23"":{
             ""activation"":1
          },
          ""virtual29"":{
             ""activation"":1
          },
          ""virtual30"":{
             ""activation"":1
          },
          ""virtual31"":{
             ""activation"":1
          },
          ""virtual32"":{
             ""activation"":1
          },
          ""virtual4"":{
             ""activation"":1
          }
       }
    }
";

JObject o = JObject.Parse(input);

// Foreach property of the root
foreach(JProperty country in o.Children())
{
    // Country name is name of the property
    string countryName = country.Name;

    // Get ISO Node below the country node
    JToken? iso = country.SelectToken("$..iso");

    // Get First property within iso Node
    JProperty? code = iso?.Value<JObject>()?.Properties().First();

    // Get Name of property
    string isoCode = code?.Name ?? "";

    Console.WriteLine($"Name: {countryName} \nCode: {isoCode}");
}
  • Related