在 Newtonsoft.Json.Linq 中使用 Jobject 解析多个对象
Parsing multiple objects using Jobject in 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);
您拥有的是一系列 JSON 根对象,它们连接在一起成为一个流。如 Read Multiple Fragments With JsonReader such a stream can be deserialized by setting 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);
}
}
}
接下来,使用 code-generation 实用程序,例如 http://json2csharp.com/,为单个 JSON 根对象生成 c# 类,如下所示:
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()
来 select 每个对象内嵌套的所有 "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();
更新的示例 fiddle 显示了两个选项。
我正在尝试将 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);
您拥有的是一系列 JSON 根对象,它们连接在一起成为一个流。如 Read Multiple Fragments With JsonReader such a stream can be deserialized by setting 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);
}
}
}
接下来,使用 code-generation 实用程序,例如 http://json2csharp.com/,为单个 JSON 根对象生成 c# 类,如下所示:
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()
来 select 每个对象内嵌套的所有 "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();
更新的示例 fiddle 显示了两个选项。