如何在JSONPath中根据数组中对象的内容进行过滤?
我正在尝试创建一个JSONPath(RFC 9525)表达式,用来根据未命名的JSON对象内部字段来过滤结果,正如花括号 {} 所示。在这种情况下,数组条目是 udm=="50"。
我的JSON数据如下所示:
{
"0": [
[
"Why are we here",
{
"zi": "AI Mode",
"zf": 27,
"zp": {
"udm": "50"
}
}
],
[
"world cup standing",
{
"zf": 27
}
],
[
"test",
{
"zf": 27,
"zp": {
"udm": "2"
},
"zi": "Images"
}
]
]
}
并且我想要的结果看起来像这样:
[
"Why are we here",
{
"zi": "AI Mode",
"zf": 27,
"zp": {
"udm": "50"
}
}
]
我尝试过的方法:
如果我排除过滤条件,就能选到正确的数据层级。
$["0"][*][*]
[
"Why are we here",
{
"zi": "AI Mode",
"zf": 27,
"zp": {
"udm": "50"
}
},
"world cup standing",
{
"zf": 27
},
"test",
{
"zf": 27,
"zp": {
"udm": "2"
},
"zi": "Images"
}
]
我可以过滤JSON对象内部的数据,但它不会让我获得对象外部的数据。
$..[[email protected]=="50"]
[
{
"zi": "AI Mode",
"zf": 27,
"zp": {
"udm": "50"
}
}
]
我以为可以在过滤器中使用像 * 或 .. 这样的通配符来表示JSON对象,但 JSONPath Evaluator 给出语法错误。
$..[?@*.zp.udm=="50"]
$..[?@[*].zp.udm=="50"]
$..[?@.*.zp.udm=="50"]
$..[[email protected]=="50"]
如何编写一个JSONPath表达式,在过滤未命名对象内部的数据的同时返回未命名对象外部的数据?
编辑:为便于理解,我正在为Google的 AI相关自动完成建议,以及 uBlock Origin 与AdGuard制作一个过滤器,它们使用的是修改版本的JSONPath。它们的语法基于RFC 9525,但并非完全等同于它。为了保留当前答案,我将保持问题的原文。
解决方案
这确实有点棘手,在线评估器的输出也可能产生误导。你需要记住以下几点:
- JSONPath查询总是返回一个 匹配项列表,即使只有一个匹配。
这意味着如果没有匹配项(结果为空),它会给你 []。如果只有一个匹配项,则以 [1st-match] 返回,依此类推。
因此,如果你应用这个JSONPath表达式 $["0"],去获取与键 "0" 相关联的值,你得到的结果如下:
[
[
[
"Why are we here",
{
"zi": "AI Mode",
"zf": 27,
"zp": {
"udm": "50"
}
}
],
[
"world cup standing",
{
"zf": 27
}
],
[
"test",
{
"zf": 27,
"zp": {
"udm": "2"
},
"zi": "Images"
}
]
]
]
请注意,评估器会额外添加最外层的一对括号 [...],因为这是前文所述的标准做法。它不是来自你原始文档的。
你想要在这条路径上进一步向下导航,找到一个子元素,使得:
- 需要匹配具有某种元素模式的子元素,这可以通过过滤运算符
?实现 - 每个子元素都是一个数组,表示为
@,作为“当前数组元素” - 在该当前数组元素的第二个子元素(基于从0 开始)也就是
@[1]上,我希望匹配的子元素具有一个键,其键名为zp,该键对应的值再包含一个键名为udm的值,其值为"50"。因此:[?@[1].zp.udm=="50"] - 把它追加到前面的结果上,我们得到:
$["0"][?@[1].zp.udm=="50"]
我们得到的结果如下:
[
[
"Why are we here",
{
"zi": "AI Mode",
"zf": 27,
"zp": {
"udm": "50"
}
}
]
]
就JSONPath表达式能做到的程度而言,我们已经达到目标,但评测器会再次自动添加一对额外的括号 [...],不过这并不是实际数据本身。调用该结果的程序(无论用JavaScript、C#还是其他语言编写)有责任检查结果,并查看结果列表中是否至少有一个元素。如果没有,则表示没有匹配项;如果有,则在你自己的代码中获取列表中的第一个元素。你将得到如下结果:
[
"Why are we here",
{
"zi": "AI Mode",
"zf": 27,
"zp": {
"udm": "50"
}
}
]
这正是你想要的。
总结
- JSONPath表达式:
$["0"][?@[1].zp.udm=="50"] - 程序应检查结果列表的长度
- 如果长度 > 0,则将其第一个元素作为实际结果