У меня большая проблема с десериализацией моего JSON в объект. Его нужно десериализовать, чтобы IList<KeyValuePair<string, object>>
проблема в том, что в ключах есть пробелы.
"spec": {
"SOMETHING WITH SPACES" : "10"
etc.
...
}
public class SomeObject
{
...
public IList<KeyValuePair<string, object>> spec{ get; set; }
...
}
Код десериализации:
var sr = new ServiceStack.Text.JsonSerializer<SomeObject>();
var esResult = sr.DeserializeFromString(responseJson);
responseJson
— это GET от ElasticSearch.
То, что я получаю в своем поле, равно нулю.
Если у меня есть ключ без пробелов, он нормально десериализуется, и я получаю свой IList<KeyValuePair<string, object>>
Почему бы просто не использовать Dictionary<string, object>
вместо IList<KeyValuePair<string, object>>
?
Обычно интерфейсы вызывают проблемы при сериализации. Вероятно, у сериализатора нет возможности узнать, где взять реализацию IList
, которая у вас есть. Если сериализатор добавляет больше информации о w.r.t. реализация в сериализованном представлении может быть использована для десериализации, но это то, что обычно не происходит в мире JSON. Попробуйте изменить это только на List
, а не на IList
.
Я не могу использовать Dictionary, потому что этот объект используется в нескольких местах, таких как List<KVP>. Изменение IList на List не работает, но спасибо за предложение.
Пожалуйста, смотрите мой ответ о том, как анализировать с помощью словаря и по-прежнему получать нужный вам список.
Я предполагаю, что ваш сериализатор JSON создает некоторые проблемы. Я бы рекомендовал использовать Newtonsoft.Json (в NuGet) Я пробовал следующий код, и он отлично работает:
var o1 = new SomeObject() { spec = new List<KeyValuePair<string, object>>() };
o1.spec.Add(new KeyValuePair<string, object>("test with spaces", 10));
var r1 = Newtonsoft.Json.JsonConvert.SerializeObject(o1);
Console.WriteLine(r1);
var o2 = Newtonsoft.Json.JsonConvert.DeserializeObject<SomeObject>(r1);
var r2 = Newtonsoft.Json.JsonConvert.SerializeObject(o2);
Console.WriteLine(r2);
Результат
{"spec":[{"Key":"test with spaces","Value":10}]}
{"spec":[{"Key":"test with spaces","Value":10}]}
Нулевых значений нет, все работает нормально.
Обновлено: я на самом деле не вижу причин, почему пробелы вообще должны быть проблемой. Они просто часть строки.
Обратите внимание, что JSON, который вы создаете, а затем анализируете, содержит [ ]
, тогда как OP не имеет [ ]
в своем JSON.
Newtonsoft.Json сохраняет выходные данные со словами Key и Value. У меня есть много индексов в elasticsearch, сохраненных с помощью ServiceStack json, и они выглядят немного иначе.
Вы правы, это совсем другое. Я бы порекомендовал, как Кунал Мукерджи, опубликовать полный пример json-файла, чтобы лучше понять, как он отформатирован.
Если вы не возражаете против использования Newtonsoft.Json:
const string json = @"{""spec"": { ""SOMETHING WITH SPACES"" : ""10"", ""SOMETHING WITH MORE SPACES"" : ""20"" }}";
dynamic data = JsonConvert.DeserializeObject(json);
Dictionary<string, string> list = data["spec"].ToObject<Dictionary<string, string>>();
foreach (var item in list)
{
Console.WriteLine(item.Key + ", " + item.Value);
}
Здесь нельзя использовать IList
или List
, потому что в исходном JSON нет [ ]
, что является обязательным условием, если вы хотите разобрать такую коллекцию. Другими словами, без [ ]
вы не сможете разобрать коллекцию, по крайней мере, не пройдя через множество обручей.
Вместо этого вам нужно использовать словарь, как уже было предложено в комментариях.
Примечание. Я использовал Newtonsoft JsonConvert, потому что вы не указали, какой у вас синтаксический анализатор, но это не должно иметь большого значения для моих аргументов.
Рабочий код:
var json = "{ \"spec\": { \"SOMETHING WITH SPACES\" : \"10\" } }";
var someObj = JsonConvert.DeserializeObject<SomeObject>(json);
public class SomeObject
{
public Dictionary<string, object> spec{ get; set; }
}
После этого вы можете привести свойство spec
к IEnumerable
и перебрать все, что было найдено:
foreach (var pair in someObj.spec as IEnumerable<KeyValuePair<string, object>>)
{
Console.WriteLine(pair.Key + " -> " + pair.Value);
}
Или даже преобразовать его в список:
var list = someObj.spec.ToList();
foreach (var pair in list)
{
Console.WriteLine(pair.Key + " -> " + pair.Value);
}
Скрипт .NET: https://dotnetfiddle.net/15l2R3
Я должен использовать List<KeyValuePair<string, object>>
, потому что в моей спецификации могут быть ключи с одинаковыми именами.
В этом случае см. эта страница о наличии JSON с повторяющимися ключами. В нем говорится: «(Синтаксический анализатор может выбрать) вернуть все пары ключ-значение или даже отклонить JSON с ошибкой синтаксического анализа, и все эти варианты поведения будут действительными. Тем не менее, большинство популярных реализаций... следуют правило взятия только последней пары ключ-значение». Я не знаю каких-либо парсеров, которые справляются с этим, сохраняя все дубликаты, и вам может быть трудно найти его.
опубликовать весь json