0%

JsonPath:过滤表达式中@的使用

过滤表达式中的@

JsonPath 中过滤表达式的语法是 [?(<expression>)] ,而 @ 代表过滤表达中当前处理的节点对象。

上示例先:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# jsonpath_ng v1.6.1  
from jsonpath_ng.ext import parse

json_data = {
    "store": {
        "book": [
            {"category""fiction""author""J. R. R. Tolkien""title""The Lord of the Rings""price"22.99},
            {"category""fiction""author""J  K. Rowling""title""Harry Potter""price"19.99},
            {"category""nonfiction""author""Robert C. Martin""title""Clean Code""price"14.95}
        ]
    }
}

jsonpath_expr = parse("$.store.book[?(@.author == 'Robert C. Martin')].price")
result = [match.value for match in jsonpath_expr.find(json_data)]
print(result)

上面的示例代码中,@.author == 'Robert C. Martin' 使用作者过滤书籍,并获取价格。

@ 通常不是必需的,可以等价省略:

1
2
$.store.book[?(@.author == 'Robert C. Martin')]
$.store.book[?(author == 'Robert C. Martin')]

独立使用的@

需要另外说明的是,@ 可以不使用在过滤表达式中,它可以独立使用。

我们来看下下面的示例:

1
2
3
4
$.store.book[*].author  
$.store.book[*][author]
$.store.book[*].@.author
$.store.book[*].(@.author)

JsonPath 同时支持 . 导航和 [] 导航,所以前两种访问所有书籍作者的写法是正确的。

因此,在 author 加上 @. 指明是取当前书籍节点的作者,理论也是正确的,只是有点冗余。上面示例中,后两种就是带 @ 的写法,也是正确的。

需要注意的是,带 @ 的写法不允许出现在 [] 导航中,即 $.store.book[*][@.author] 是非法的。

必须的@

@ 很多场景下是冗余的,但不代表它总是可以省略。在进行属性拼接时,@ 就不能省略。比如:

1
$.store.book[*].(@.author + ' - ' + @.title)

上面是将书籍作者和标题拼接起来。这里的 @ 是必须的,如果省略为 $.store.book[*].(author + ' - ' + title) 解析程序就会认为是在进行常量字符串的拼接,而不是在取节点数据。这将得到意外的结果:['author - title', 'author - title', 'author - title']

关于解析环境的说明

笔者试过很多 JsonPath 在线解析工具,大多不支持过滤表达式。

以上的 JsonPath 解析都是在 jsonpath_ng v1.6.1 版本下进行的测试。需要注意的是,解析函数 parse() 是从 jsonpath_ng.ext 中导入的,不要使用 jsonpath_ng 中的那个——因为,它不支持过滤条件式和某些运算,比如字符串拼接😂。