我试图从JSON对象输入流中读取第一个属性名称,然后根据其值,可能"倒带"并阅读整个对象。
我可以轻松阅读第一个属性名称
JsonReader reader = ...;
while (reader.Read()) {
if (reader.TokenType == JsonToken.PropertyName) {
// this is the first property
break;
}
}
但我无法找到任何退回或倒退读者的方法。
虽然我理解底层流可能不支持较低级别的搜索,但我希望我们已经读过的JSON令牌可以以某种方式重新解析和重新解析。
如果这是不可能的,或者有没有办法只读取对象的属性名称而不解析每个属性的内容?我想避免两次阅读整个东西只是为了检查一个属性。
答案 0 :(得分:2)
没有。 JsonReader
是一位前瞻性读者。如果没有从头开始完全重新调整,就无法“倒带”或寻找早期阶段。如果您希望能够查看之前的信息,那么您需要在阅读时将其存储到变量中。
JsonReader
确实提供了Skip
方法,可用于跳过特定令牌的子节点。因此,如果您读取了您不感兴趣的属性的名称,并且下一个标记是对象或数组的开头,则可以使用Skip
直接移动到该对象或数组的结束标记
下面是一个简单的示例,它使用此技术只读取JSON对象的根属性名称,但跳过所有值。
string json = @"
{
""resultCode"": 200,
""message"": ""OK"",
""searchTerms"": [
{
""attribute"": ""keywords"",
""operator"": ""contains"",
""values"": [ ""ipsum"" ]
}
],
""count"": 2,
""items"": [
{
""id"": 1,
""name"": ""foo"",
""sizes"": [ ""small"", ""meduim"", ""large"" ],
""description"": ""Lorem ipsum dolor sit amet""
},
{
""id"": 2,
""name"": ""bar"",
""sizes"": [ ""tiny"", ""huge"" ],
""description"": ""Neque porro quisquam est qui dolorem ipsum""
}
]
}";
using (StringReader sr = new StringReader(json))
using (JsonTextReader reader = new JsonTextReader(sr))
{
while (reader.Read())
{
if (reader.TokenType == JsonToken.PropertyName)
{
string propName = (string)reader.Value;
Console.WriteLine(propName);
// advance to property value
reader.Read();
// if the value is an object or array, skip over its children
if (reader.TokenType == JsonToken.StartObject ||
reader.TokenType == JsonToken.StartArray)
reader.Skip();
}
}
}
输出:
resultCode
message
searchTerms
count
items
答案 1 :(得分:0)
我对System.Text.Json有相同的问题,导致我来到这里,并且找到了解决方案,我认为我应该在这里分享答案。
根据Levi Broderick here的建议,新的Utf8JsonReader
是一个结构,这意味着可以随意复制它。
Utf8JsonReader reader2 = reader;
reader2.Read();// ... Do stuff with the copy of the reader
// Here the initial reader didn't change and is still where you left it.
这样,您可以像我对here或there所做的那样两次解析数据
在Newtonsoft.Json的帮助下,我终于使用了JToken.ReadFrom(reader)
,然后从那里开始了我的工作。参见this code
JToken token = JToken.ReadFrom(reader);
var left = token.ToObject<TLeft>(serializer);
var right = token.ToObject<TRight>(serializer);