Разбор нескольких объектов с помощью Jobject в Newtonsoft.Json.Linq

Я пытаюсь разобрать результат из речи Google в текстовый API. Ответ json:

{"result":[]}
{"result":[
          {"alternative":[
                         {"transcript":"hello Google how are you     feeling","confidence":0.96274596},
                         {"transcript":"hello Google how are you today","confidence":0.97388196},
                         {"transcript":"hello Google how are you picking","confidence":0.97388196},
                         {"transcript":"hello Google how are you kidding","confidence":0.97388196}
                         ]
         ,"final":true}]
,"result_index":0
}

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

              StreamReader SR_Response = new StreamReader(HWR_Response.GetResponseStream());
              Console.WriteLine(SR_Response.ReadToEnd()+SR_Response.ToString());
              String json_response = SR_Response.ReadToEnd() + SR_Response.ToString();
              JObject joo = JObject.Parse(json_response);
              JArray ja = (JArray)joo["result"];

                        foreach (JObject o in ja)
                        {
                            JArray ja2 = (JArray)o["alternative"];
                            foreach (JObject h in ja2)
                            {
                                Console.WriteLine(h["transcript"]);
                            }
                        }

Следующее решение, которое я попытался использовать для десериализации кода объекта:

                string responseFromServer = (SR_Response.ReadToEnd());
                String[] jsons = responseFromServer.Split('\n');
                String text = "";
                foreach (String j in jsons)
                {
                    dynamic jsonObject = JsonConvert.DeserializeObject(j);
                    if (jsonObject == null || jsonObject.result.Count <= 0)
                    {
                        continue;
                    }
                    Console.WriteLine((string)jsonObject["result"]["alternative"][0]["transcript"]);
                    text = jsonObject.result[0].alternative[0].transcript;
                }
                Console.WriteLine("MESSAGE : "+text); 

person DIGIT    schedule 03.02.2017    source источник
comment
Этот ответ предназначен для одного вызова API? два раза ответ?   -  person BWA    schedule 03.02.2017
comment
Что это, String json_response = SR_Response.ReadToEnd() + SR_Response.ToString(); Кроме того, ваш второй код работает в цикле, кажется, разбитым на новые строки. Покажите нам точный пример Json, который вы десериализуете, и фактический полный код вместе с полученным результатом.   -  person ColinM    schedule 03.02.2017
comment
Вы читаете поток один раз со своим вызовом Console.WriteLine(): Console.WriteLine(SR_Response.ReadToEnd()+SR_Response.ToString());. Потом тут же пытаешься прочитать еще раз: String json_response = SR_Response.ReadToEnd() + SR_Response.ToString();. Это не может работать, вам нужно прочитать поток только один раз.   -  person dbc    schedule 03.02.2017
comment
Предполагая, что вы исправили чтение потока, это выглядит как дубликат Разбор большого файла json в .NET или Сериализация и десериализация json с разделителями строк. Хитрость заключается в том, чтобы установить JsonTextReader.SupportMultipleContent = true   -  person dbc    schedule 03.02.2017
comment
@ColinM SR_Response.ReadToEnd() предназначен только для чтения ответа от объекта json в строковом формате, и вот мой полный код ссылка   -  person DIGIT    schedule 03.02.2017
comment
Мне нужно проанализировать текст внутри стенограммы привет, Google, как ты себя чувствуешь, поэтому в настоящее время они не выводятся, но Console.WriteLine(SR_Response.ReadToEnd()+SR_Response.ToStri‌​ng()); распечатывают ответ json, который он написал сверху   -  person DIGIT    schedule 03.02.2017


Ответы (1)


У вас есть ряд корневых объектов JSON, объединенных в один поток. Как объясняется в разделе Чтение нескольких фрагментов с помощью JsonReader, такой поток можно десериализовать. установив JsonReader.SupportMultipleContent = true. Таким образом, чтобы десериализовать ваш поток, вы должны сначала ввести следующие методы расширения:

public static class JsonExtensions
{
    public static IEnumerable<T> DeserializeObjects<T>(Stream stream, JsonSerializerSettings settings = null)
    {
        var reader = new StreamReader(stream); // Caller should dispose
        return DeserializeObjects<T>(reader, settings);
    }

    public static IEnumerable<T> DeserializeObjects<T>(TextReader textReader, JsonSerializerSettings settings = null)
    {
        var ser = JsonSerializer.CreateDefault(settings);
        var reader = new JsonTextReader(textReader); // Caller should dispose

        reader.SupportMultipleContent = true;

        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.None || reader.TokenType == JsonToken.Undefined || reader.TokenType == JsonToken.Comment)
                continue;
            yield return ser.Deserialize<T>(reader);
        }
    }
}

Затем с помощью утилиты генерации кода, такой как http://json2csharp.com/, создайте классы C# для одного Корневой объект JSON, например:

public class Alternative
{
    public string transcript { get; set; }
    public double confidence { get; set; }
}

public class Result
{
    public List<Alternative> alternative { get; set; }
    public bool final { get; set; }
}

public class RootObject
{
    public List<Result> result { get; set; }
    public int result_index { get; set; }
}

И десериализовать следующим образом:

List<RootObject> results;
using (var stream = HWR_Response.GetResonseStream())
{
    results = JsonExtensions.DeserializeObjects<RootObject>(stream).ToList();
}

Сделав это, вы можете использовать стандартные методы программирования C#, такие как Linq для перечислите значения transcript, например:

var transcripts = results
    .SelectMany(r => r.result)
    .SelectMany(r => r.alternative)
    .Select(a => a.transcript)
    .ToList();

Если вы не хотите определять фиксированную модель данных для своей коллекции JSON, вы можете десериализовать непосредственно список JObject следующим образом:

List<JObject> objs;
using (var stream = HWR_Response.GetResonseStream())
{
    objs = JsonExtensions.DeserializeObjects<JObject>(stream).ToList();
}

Затем вы можете использовать SelectTokens() для выбора значений всех "transcript" свойств. вложенный в каждый объект:

var transcripts = objs
    // The following uses the JSONPath recursive descent operator ".." to pick out all properties named "transcript".
    .SelectMany(o => o.SelectTokens("..transcript")) 
    .Select(t => t.ToString())
    .ToList();

Обновлен образец скрипки, показывающий оба варианта.

person dbc    schedule 03.02.2017
comment
Предоставьте любой код извлечения текста/значения из стенограммы в связи с упомянутым вами подходом к десериализации, чтобы я мог получить только строку внутри стенограммы, такую ​​как привет, Google, как ты себя чувствуешь - person DIGIT; 03.02.2017