JsonPath 与 JsonTextReader:一次标记

JsonPath with JsonTextReader: Token at a Time

我遇到一个问题,JsonPath 在使用 JsonTextReader 一次加载令牌 (.Load) 与使用 ReadFrom 加载整个 JSON 时工作方式不同。这是一个例子: JSON: Path="[*].person" Method=SelectTokens(path)

 [
  {
    "person": {
      "personid": 123456
    }
  },
  {
    "person": {
      "personid": 798
    }
  }
]

使用 .ReadFrom 时,它将 return 正确的 2 个元素。但是,如果我使用 .Load,它将 return 0 个元素。但是,如果我将路径更改为“person”,.ReadFrom returns 0 个元素,而 .Load returns 2 个元素。

作为解决方法,我可以更改路径,以便删除第一个“.”。即 path = substring(path.index(".")+1); 然而,这感觉更像是一种 hack 而不是正确的修复。当然,我还需要确保 JSON 是一个数组,但在我的大多数情况下,它会是。

所以最后,我正在尝试学习如何在一次加载令牌时将 JSON 路径与数组一起使用。有什么建议吗?

Full Code

Full JSON

您链接到的代码中发生的事情是它读取标记直到遇到对象,然后从该对象加载 JToken,它会提前读取到该对象的末尾。 所以你最终得到的是根数组中每个项目的 JToken 。然后,您可以为每个 JToken 调用:

token.SelectTokens("person").OfType<JObject>()

因为您知道 属性 包含一个对象。

这相当于在整个解析的 JSON.

上执行 "[*].person" JsonPath

希望我已经正确理解了您的问题。如果没有,请告诉我 =)

更新:

根据您的评论,我了解您的需求。你可以做的是创建一个这样的方法:

public IEnumerable<JToken> GetTokensByPath(TextReader tr, string path)
{
    // do our best to convert the path to a RegEx
    var regex = new Regex(path.Replace("[*]", @"\[[0-9]*\]"));
    using (var reader = new JsonTextReader(tr))
    {
        while (reader.Read())
        {
            if (regex.IsMatch(reader.Path))
                yield return JToken.Load(reader);
        }
    }
}

我正在根据 JSON 路径输入匹配路径,但我们需要尝试处理所有各种 JSON 路径语法,目前我只支持 *。 当你有一个大文件时,这种方法很有用,有一个深 JSON 路径选择器,如果你枚举缓慢,你将保持流打开更长时间,但你的峰值内存使用率会低得多。

希望对您有所帮助。