Как десериализовать JSON с двойными именами свойств в одном и том же объекте

У меня есть строка JSON, которую я ожидаю содержать дублирующиеся ключи, с которыми я не могу довести JSON.NET.

Мне было интересно, знает ли кто-нибудь лучший способ (может быть, использовать JsonConverter ?), Чтобы заставить JSON.NET изменить JObject JObjects в JArrays когда он видит повторяющиеся имена ключей?

 // For example: This gives me a JObject with a single "JProperty\JObject" child. var obj = JsonConvert.DeserializeObject("{ \"HiThere\":1}"); // This throws: // System.ArgumentException : Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject. obj = JsonConvert.DeserializeObject("{ \"HiThere\":1, \"HiThere\":2, \"HiThere\":3 }"); 

Фактический JSON, который я пытаюсь десериализовать, намного сложнее, и дубликаты вложены на несколько уровней. Но приведенный выше код демонстрирует, почему он терпит неудачу для меня.

Я понимаю, что JSON неверен, поэтому я спрашиваю, есть ли у JSON.NET способ обойти это. Для аргументации, скажем, у меня нет контроля над JSON. Я действительно использую определенный тип для родительского объекта, но конкретное свойство, которое имеет проблемы, будет либо строкой, либо другим вложенным объектом JSON. По этой причине тип свойства failing является «объектом».

Интересный вопрос. JObject время я JObject с этим и обнаружил, что, хотя JObject не может содержать свойства с повторяющимися именами, JsonTextReader используемый для заполнения его во время десериализации, не имеет такого ограничения. (Это имеет смысл, если вы думаете об этом: это читатель, ориентированный только на будущее, он не имеет отношения к тому, что он читал в прошлом). Вооружившись этими знаниями, я сделал попытку написать код, который заполнит иерархию JTokens, при необходимости преобразуя значения свойств в JArrays, если в конкретном объекте JObject встречается дублирующее имя свойства. Поскольку я не знаю вашего фактического JSON и требований, вам может потребоваться внести некоторые корректировки, но с чего-то начать, по крайней мере.

Вот код:

 public static JToken DeserializeAndCombineDuplicates(JsonTextReader reader) { if (reader.TokenType == JsonToken.None) { reader.Read(); } if (reader.TokenType == JsonToken.StartObject) { reader.Read(); JObject obj = new JObject(); while (reader.TokenType != JsonToken.EndObject) { string propName = (string)reader.Value; reader.Read(); JToken newValue = DeserializeAndCombineDuplicates(reader); JToken existingValue = obj[propName]; if (existingValue == null) { obj.Add(new JProperty(propName, newValue)); } else if (existingValue.Type == JTokenType.Array) { CombineWithArray((JArray)existingValue, newValue); } else // Convert existing non-array property value to an array { JProperty prop = (JProperty)existingValue.Parent; JArray array = new JArray(); prop.Value = array; array.Add(existingValue); CombineWithArray(array, newValue); } reader.Read(); } return obj; } if (reader.TokenType == JsonToken.StartArray) { reader.Read(); JArray array = new JArray(); while (reader.TokenType != JsonToken.EndArray) { array.Add(DeserializeAndCombineDuplicates(reader)); reader.Read(); } return array; } return new JValue(reader.Value); } private static void CombineWithArray(JArray array, JToken value) { if (value.Type == JTokenType.Array) { foreach (JToken child in value.Children()) array.Add(child); } else { array.Add(value); } } 

И вот демо:

 class Program { static void Main(string[] args) { string json = @" { ""Foo"" : 1, ""Foo"" : [2], ""Foo"" : [3, 4], ""Bar"" : { ""X"" : [ ""A"", ""B"" ] }, ""Bar"" : { ""X"" : ""C"", ""X"" : ""D"" }, }"; using (StringReader sr = new StringReader(json)) using (JsonTextReader reader = new JsonTextReader(sr)) { JToken token = DeserializeAndCombineDuplicates(reader); Dump(token, ""); } } private static void Dump(JToken token, string indent) { Console.Write(indent); if (token == null) { Console.WriteLine("null"); return; } Console.Write(token.Type); if (token is JProperty) Console.Write(" (name=" + ((JProperty)token).Name + ")"); else if (token is JValue) Console.Write(" (value=" + token.ToString() + ")"); Console.WriteLine(); if (token.HasValues) foreach (JToken child in token.Children()) Dump(child, indent + " "); } } 

Вывод:

 Object Property (name=Foo) Array Integer (value=1) Integer (value=2) Integer (value=3) Integer (value=4) Property (name=Bar) Array Object Property (name=X) Array String (value=A) String (value=B) Object Property (name=X) Array String (value=C) String (value=D) 

Брайан Роджерс – Вот вспомогательная функция JsonConverter, которую я написал. Я изменил его на основе ваших комментариев о том, как JsonTextReader является просто передовым читателем, не заботятся о повторяющихся значениях.

 private static object GetObject(JsonReader reader) { switch (reader.TokenType) { case JsonToken.StartObject: { var dictionary = new Dictionary(); while (reader.Read() && (reader.TokenType != JsonToken.EndObject)) { if (reader.TokenType != JsonToken.PropertyName) throw new InvalidOperationException("Unknown JObject conversion state"); string propertyName = (string) reader.Value; reader.Read(); object propertyValue = GetObject(reader); object existingValue; if (dictionary.TryGetValue(propertyName, out existingValue)) { if (existingValue is List) { var list = existingValue as List; list.Add(propertyValue); } else { var list = new List {existingValue, propertyValue}; dictionary[propertyName] = list; } } else { dictionary.Add(propertyName, propertyValue); } } return dictionary; } case JsonToken.StartArray: { var list = new List(); while (reader.Read() && (reader.TokenType != JsonToken.EndArray)) { object propertyValue = GetObject(reader); list.Add(propertyValue); } return list; } default: { return reader.Value; } } } 

Вы не должны использовать общий тип объекта, он должен быть более конкретным типом.

Тем не менее, вы ошибаетесь, что это проблема rmain

У тебя есть :

 "{ \"HiThere\":1, \"HiThere\":2, \"HiThere\":3 }" 

Но это должно быть:

 "{"HiTheres": [{\"HiThere\":1}, {\"HiThere\":2}, {\"HiThere\":3} ]}" 

Или

 "{ \"HiThereOne\":1, \"HiThereTwo\":2, \"HiThereThree\":3 }" 

Вы json – это один объект с тремя полями с одинаковым именем («HiThere»). Какой из них не будет работать.

Json, который я показал, дает: массив (HiTheres) из трех объектов, каждый с полем объекта HiThere Or One с тремя полями с разными именами. (HiThereOne, HiThereTwo, «HiThereThree»)

Взгляните на http://jsoneditoronline.org/index.html И http://json.org/

  • Исключение «Исключительная привязка к реляционной ссылке» с JSON.Net
  • Сериализация / десериализация пользовательской коллекции с дополнительными свойствами с помощью Json.Net
  • Deserialize специфическое перечисление в system.enum в Json.Net
  • Java: объект для байта и байт для конвертера объектов (для Tokyo Cabinet)
  • Json Сериализация Java, которая работает с GWT
  • Использование JSON.NET для возврата ActionResult
  • Как сериализовать lambda?
  • Сериализовать статический class?
  • Ошибка JSON.NET Локальный цикл привязки для типа
  • jackson не десериализует общий список, который он сериализовал
  • Как использовать пользовательский Serializer с Jackson?
  • Interesting Posts

    «& S » указывает на непрерывные символы в строке std ::?

    Android обнаружит, что нажатие клавиши «Готово» для клавиатуры OnScreen

    MySQL table -> Можете ли вы вернуть одну и ту же строку несколько раз, в том же запросе?

    Как зарегистрировать что-то в Rails в независимом файле журнала?

    Как установить значок приложения Mac в Xcode?

    обнаружена ошибка segfault в R

    Могу ли я создать представление с параметром в MySQL?

    Максимальная емкость жесткого диска, которую можно использовать в ноутбуке

    Параметры запуска Firefox

    Как сохранить Список в Settings.Default?

    Static vs функции / переменные classа в classах Swift?

    Какой самый быстрый способ подсчитать количество каждого символа в файле?

    Debian: обновление списков пакетов с помощью apt-offline, –simulate непонятно для apt-get update

    Как объединить использование API членства с собственными данными, связанными с приложением?

    Прозрачность CSS3 + gradleиент

    Давайте будем гением компьютера.