Go操作JSONPath.md

2022/6/13 Go

# JSONPath

相信作为测试的大家,都熟悉JSONPath的用法,我这边就简短说明下。

简单的说,JSONPath就是JSON的查询语法,我们都知道,在xml里面有XPATH给大家选择具体的路径,比如:

<student>
  <name>woody</name>
</student>
1
2
3

我们可以用/student/name获取到对应的学生名称,那JSONPath也是JSON数据的一种取值手段,它与XPATH比较相似。

尤其是我们不需要获取所有JSON数据的时候,比如我有一个学生数组,我只想取每个学生的名字,这种时候在我们无法写代码去遍历数组并获取名字的时候,JSONPath就给我们带来了莫大的帮助。

# 背景

我们在做接口测试的时候,经常会需要对报文的一些数据进行替换,也要忽略一部分字段,比如时间戳字段。

# JSONPath语法

JSONPath的语法比较简单,基本上看下面的表就可以了解一些常用的用法:

XPath JsonPath 说明
/ $ 文档根元素
. @ 当前元素
/ .或[] 匹配下级元素
.. N/A 匹配上级元素,JsonPath不支持此操作符
// .. 递归匹配所有子元素
* * 通配符,匹配下级元素
@ N/A 匹配属性,JsonPath不支持此操作符
[] [] 下标运算符,根据索引获取元素,XPath索引从1开始,JsonPath索引从0开始
| [,] 连接操作符,将多个结果拼接成数组返回,可以使用索引或别名
N/A [start :end :step] 数据切片操作,XPath不支持
[] ?() 过滤表达式
N/A () 脚本表达式,使用底层脚本引擎,XPath不支持
() N/A 分组JsonPath不支持

上述数据来自Apifox官网。

# Go中的JSONPath

我找了go里面star最多的库: https://github.com/oliveagle/jsonpath (opens new window)

(不过并不是官方的实现,有轮子用我们就直接用吧)

下面我们来看一看一个具体的例子吧~

# 安装jsonpath库

go get github.com/oliveagle/jsonpath
1

# 解析图书馆的第二本书

假设我们有一个JSON数据,里面存放了很多本书,我现在要找到其中第二本的具体数据,其它我都不需要。

{
    "store": {
        "book": [
            {
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
            },
            {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
            },
            {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
            },
            {
                "category": "fiction",
                "author": "J. R. R. Tolkien",
                "title": "The Lord of the Rings",
                "isbn": "0-395-19395-8",
                "price": 22.99
            }
        ],
        "bicycle": {
            "color": "red",
            "price": 19.95
        }
    },
    "expensive": 10
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

按照JSONPath文档给出的,我们应该这样写:

$.store.book[0]
1

我们就用这个库试试看!~

package main

import (
	"encoding/json"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/oliveagle/jsonpath"
	"log"
)

func main() {
	var jsonData interface{}
	data := `{
    "store": {
        "book": [
            {
                "category": "reference",
                "author": "Nigel Rees",
                "title": "Sayings of the Century",
                "price": 8.95
            },
            {
                "category": "fiction",
                "author": "Evelyn Waugh",
                "title": "Sword of Honour",
                "price": 12.99
            },
            {
                "category": "fiction",
                "author": "Herman Melville",
                "title": "Moby Dick",
                "isbn": "0-553-21311-3",
                "price": 8.99
            },
            {
                "category": "fiction",
                "author": "J. R. R. Tolkien",
                "title": "The Lord of the Rings",
                "isbn": "0-395-19395-8",
                "price": 22.99
            }
        ],
        "bicycle": {
            "color": "red",
            "price": 19.95
        }
    },
    "expensive": 10
}`
	json.Unmarshal([]byte(data), &jsonData)
	lookup, err := jsonpath.JsonPathLookup(jsonData, "$.store.book[1]")
	if err != nil {
		log.Panic("解析jsonpath失败")
	}
	fmt.Println(lookup)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

我们来看看运行结果:

其实demo很简单,我们需要先把json(字符串)转为Go里面的对象,interface{}即可。接着通过JSONPath解析对应的Go对象(这个由此库实现),需要注意的是返回结果也是interface{},为了通用。

# 筛选出所有图书的名字

$.store.book[*].title
1

上述代码我们只需要把JSONPath替换为上述代码即可,我们来看看效果:

# 结语

JSONPath还有很多妙用,本文只是给大家介绍下关于Go使用JSONPath的方法,不过由于这个库还不是太完善,所以有一些高级用法还不支持,我们可以看看作者给出的表格: