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 路径与数组一起使用。有什么建议吗?
您链接到的代码中发生的事情是它读取标记直到遇到对象,然后从该对象加载 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 路径选择器,如果你枚举缓慢,你将保持流打开更长时间,但你的峰值内存使用率会低得多。
希望对您有所帮助。
我遇到一个问题,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 路径与数组一起使用。有什么建议吗?
您链接到的代码中发生的事情是它读取标记直到遇到对象,然后从该对象加载 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 路径选择器,如果你枚举缓慢,你将保持流打开更长时间,但你的峰值内存使用率会低得多。
希望对您有所帮助。