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

时间:2016-09-02 12:11:09

标签: c# json.net

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

我可以轻松阅读第一个属性名称

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

但我无法找到任何退回或倒退读者的方法。

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

如果这是不可能的,或者有没有办法只读取对象的属性名称而不解析每个属性的内容?我想避免两次阅读整个东西只是为了检查一个属性。

2 个答案:

答案 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

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

答案 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.

这样,您可以像我对herethere所做的那样两次解析数据

在Newtonsoft.Json的帮助下,我终于使用了JToken.ReadFrom(reader),然后从那里开始了我的工作。参见this code

JToken token = JToken.ReadFrom(reader);
var left = token.ToObject<TLeft>(serializer);
var right = token.ToObject<TRight>(serializer);