使用 JsonReader 时有没有办法倒带或后退?

Zol*_*ási 5 c# json.net

我试图从 JSON 对象输入流中读取第一个属性名称,然后根据其值,也许“倒带”并读取整个对象。

我可以轻松读取第一个属性名称,例如

JsonReader reader = ...;
while (reader.Read()) {
  if (reader.TokenType == JsonToken.PropertyName) {
    // this is the first property
    break;
  }
}
Run Code Online (Sandbox Code Playgroud)

但我看不出有任何方法可以让读者后退或倒带。

虽然我知道底层流可能不支持较低级别的搜索,但我希望我们已经读取的 JSON 令牌可以以某种方式倒回并重新解析。

如果这是不可能的,或者有什么方法可以只读取对象的属性名称而不解析每个属性的内容?我想避免仅仅为了检查一处房产而阅读整个内容两次。

cub*_*e45 6

我对 System.Text.Json 有同样的问题,这导致我来到这里,我找到了一个解决方案,我想我应该在这里分享答案。

正如 Levi Broderick在这里所建议的,newUtf8JsonReader是一个结构体,这意味着它可以随意复制。

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.
Run Code Online (Sandbox Code Playgroud)

这样,您就可以像我在这里那里那样解析数据两次

通过 Newtonsoft.Json,我最终使用了JToken.ReadFrom(reader),然后从那里开始我的工作。看这段代码

JToken token = JToken.ReadFrom(reader);
var left = token.ToObject<TLeft>(serializer);
var right = token.ToObject<TRight>(serializer);
Run Code Online (Sandbox Code Playgroud)


Bri*_*ers 3

No. 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

resultCode
message
searchTerms
count
items
Run Code Online (Sandbox Code Playgroud)

小提琴: https: //dotnetfiddle.net/qfejWk