Десериализовать JSON с неизвестным именем значения и получить указанное имя на С#

Я пытаюсь десериализовать ответ JSON от API и получить ИМЯ того, что в этом примере является «af» (код страны Афганистана) внутри «iso», но имя поля будет каждый раз отличаться в зависимости от страны code, как я могу прочитать название поля и получить код каждой страны в ответе API? Спасибо!

Пример ответа:

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

Это продолжается для очень большого списка стран

вот как я сейчас десериализую:

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

А это сгенерированный VS класс ResponseFields:

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

Печать на консоль следующим образом:

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


    }

Производит:

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

против ожидаемого результата:

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

это самый близкий пост на SO, который мне удалось получить из google

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
73
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Гарантировано ли, что iso имеет только одно свойство? Если это так, вы можете просто прочитать дочерние элементы по индексу вместо имени.

Вы также можете использовать Dictionary<string, int> для представления Iso (как и с корнем):

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

И выходная строка может быть:

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

Понятия не имею, почему этот совершенно правильный ответ будет отклонен. Иногда самый простой ответ — определить конкретный класс модели json. Хотя вы также можете решить проблему, определив собственный преобразователь для класса Iso.

Jeremy Lakeman 17.11.2022 03:58

Решение без использования предопределенных типов, но с навигацией по структуре объекта.

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}");
}
Ответ принят как подходящий

вы можете выполнить свою задачу в одну строку

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

Ваш ответ настолько прост, но эффективен, что я почти разочаровался на первый взгляд из-за бесполезного количества головных уборов, в которые я вложил себя зря ... явный признак того, что мне еще многому нужно научиться! Большое спасибо!

juryvorpopen 17.11.2022 06:20

Другие вопросы по теме