2015-04-06 7 views
1

Я прочитал пару подобных вопросов, но не нашел ни одного связанного с JObject. Вот проблема: У меня есть поток с каскадными объектов JSON, то есть:Загрузка нескольких связанных объектов JSON из потока

{"key1":"value1"}{"key2":"value2"}{"key3":"value3"} 

Теперь я хочу, чтобы читать эти объекты один за другим в JObject. Вот как я пытался сделать это:

public class JsonStreamReader : JsonTextReader 
{ 
    public JsonStreamReader(Stream s) : base(new StreamReader(s)) {} 
} 

private void LoadJson(Stream s) 
{ 
    var r = new JsonStreamReader(s) { SupportMultipleContent = true }; 
    var obj = JObject.Load(r); 
    // ... get data from JObject ... 
} 

Проблема здесь состоит в том, что JObject.Load() считывает все доступные данные из потока, но разбирает только первый объект и отбрасывает все остальные. Как мне с этим справиться?

И только в случае XY-проблемы (зачем мне это нужно): Я хочу передавать сообщения JSON через поток TCP. Поскольку я использую необработанный поток TCP, мне нужно знать размер сообщения, чтобы прочитать его. Я решил написать небольшой заголовок с size и message type перед каждым сообщением, поэтому я могу прочитать заголовок в небольшой буфер, получить размер следующего сообщения, а затем прочитать его полностью.

+0

Есть ли способ, которым вы можете обернуть ваши объекты JSON в массив и запятую - отделить их? – krillgar

+0

@krillgar, чтобы это был единственный объект? – nitrocaster

+0

Разве это буквальный json? Большинство API с таким форматом данных предоставляют объектам json новую строку с разделителями, поэтому правильный способ ее обработки состоит в том, чтобы читать ее по строкам, передавая каждый в JObject.Load (может потребоваться другой метод), а не пытаться сделать все это однажды. – evanmcdonnal

ответ

0

ОК, я просто поставляю свой ответ на основе предположений, сделанных моим предыдущим опытом, использующим API-интерфейсы json streaming, которые всегда поставляли объекты с разделителями строк.

private void LoadJson(StreamReader sr) 
{ 
    string token = null; 
    List<JObject> items = new List<JObject>(); 
    while (token = sr.Readline() != null) 
    { 
      var obj = JsonConvert.DeserializeObject<JObject>(token); 
      items.Add(obj); 
    } 
} 

Основы; 1) передать поток, прекратить возиться с ним; 2) прочитать каждую строку в цикле while и 3) десериализовать каждый токен отдельно, объединить их в свой код, json.NET не может сделать это для вас, когда предоставленный json не является коллекция.

Вот некоторые другие идеи, потому что я бы, вероятно, справился с этим по-другому, если бы это был мой код. Либо укажите объект для использования, а не JObject, или, если этот json на самом деле является тем, что вы потребляете, а не надуманным примером, тогда я бы просто использовал Dictionary<string,string> и добавлял в него ключ и значение прямо там, где я добавляю список Я использовал в своем примере. Это было бы как var obj = JsonConvert.DeserializeObject<JObject>(token); , а затем myDict.Add(obj.SelectToken("key"), obj.SelectToken("value")). Или, если это вызовет дублирование ключевых слов, вы можете использовать List<KeyValuePair<string, string>> и сделать JsonConvert.DeserializeObject<KeyValuePair<string, string>>(token);.

Просто некоторые идеи, облегчающие работу с данными, все это вопрос мнения. Что касается десериализации, ключ состоит в том, чтобы обрабатывать каждый токен один за другим. Этот ответ не является «действительным json», однако каждая строка. Вам нужно прочесть его по строкам.

Я лично презираю JObject реализации. На мой взгляд, если вы можете определить схему для json в момент написания кода, вы никогда не должны использовать JObject. Вы отказываетесь от читаемости и безопасности типов (в лучшем случае), сохраняя несколько строк кода, которые потребуются, чтобы объявить класс или структуру для вашей модели. В принципе, ваш JSON статичен, поэтому он лучше всего подходит для лечения. Способ, которым я его вижу JObject, отображается только в json.NET, поэтому вы можете принимать решения о том, как обрабатывать json, формат которого неизвестен автору во время компиляции.

+0

Как символы новой строки (внутри строки) обрабатываются при работе с новой версией JSON с новой строкой? – nitrocaster

+0

@nitrocaster Я не думаю, что они есть, поэтому вы можете получить только один объект из этого вызова 'Load'. «newline limited JSON» - это не какой-то четко определенный формат, который имеет стандарты вокруг него, поскольку я указал, что ответ технически недействителен json. Если вы скопируете и вставьте ответ в json validator, он правильно скажет вам, что он недействителен. Если вы знакомы с json-схемами (http://json-schema.org/), вы также увидите, что нет способа определить схему для этого json. Каждая строка является допустимым json blob, документ в целом недействителен. – evanmcdonnal

+0

Объекты json, которые я собираюсь передать, содержат многострочные строки. Как мне это обработать? – nitrocaster

3

Вы можете сделать это, установив SupportMultipleContent на JsonReader к истине:

Read Multiple Fragments With JsonReader

Если есть проблема с использованием JObject.Load с этой установкой, то используйте вместо JsonConvert.DeserializeObject.

+0

Идеальное решение, за исключением одного: читатель считывает все доступные данные из потока. Я хочу, чтобы он читал только один объект (так что позиция потока была бы исходной позицией + длиной объекта чтения) из-за двух причин: 1] могут быть части объектов, которые еще не были полностью получены; 2] следующие объекты предназначены для чтения другими уровнями протокола обмена сообщениями. – nitrocaster

Смежные вопросы