0

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

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

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

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

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

完整代码

完整的 JSON

4

1 回答 1

1

您链接到的代码中发生的是它读取令牌直到遇到对象,然后JToken从该对象加载 a ,该对象提前读取到该对象的末尾。所以你最终得到的是JToken根数组中的每个项目。然后,您可以为每个JToken呼叫:

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

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

这相当于"[*].person"对整个解析的 JSON 执行 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 路径选择器,如果您缓慢枚举,您将保持流打开的时间更长,但您的峰值内存使用量会低得多。

我希望这有帮助。

于 2017-01-13T22:31:32.610 回答