我遇到一个问题,当使用JsonTextReader一次加载令牌(.Load)与使用ReadFrom加载整个JSON时,JsonPath的工作方式不同。这是一个例子: JSON:Path =" [*]。person"方法= SelectTokens(路径)
[
{
"person": {
"personid": 123456
}
},
{
"person": {
"personid": 798
}
}
]
使用.ReadFrom时,它会返回正确的2个元素。如果我使用.Load,它将返回0个元素。但是,如果我将路径更改为" person ",则.ReadFrom会返回0个元素,而.Load会返回2个元素。
作为修复,我可以更改路径,以便它可以删除第一个"。"即 path = substring(path.index("。")+ 1); 然而,这感觉更像是一个黑客而不是一个正确的修复。当然,我还需要确保JSON是一个数组,但在我的大多数情况下,它都是。
最后,我正在尝试学习如何在一次加载令牌时使用JSON Path和数组。有什么建议吗?
答案 0 :(得分:1)
您链接到的代码中发生的事情是,它会在遇到对象之前读取令牌,然后从该对象加载一个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路径选择器的海量文件时,这种方法很有用,如果你慢慢枚举,你会保持流打开的时间更长,但你的峰值内存使用率要低得多。
我希望这会有所帮助。