jsonpath 教程

jsonpath[1] 是一种解析 json 数据的技术,主要用来快速提取 json 数据当中的某部分内容。

先来看一个例子。

某个接口返回了一个 json 数据,现在需要把 json 数据当中的 city 值提取出来。

{
  "firstName": "John",
  "lastName" : "doe",
  "age"      : 26,
  "address"  : {
    "streetAddress": "naist street",
    "city"         : "Nara",
    "postalCode"   : "630-0192"
  },
  "phoneNumbers": [
    {
      "type"  : "iPhone",
      "number": "0123-4567-8888"
    },
    {
      "type"  : "home",
      "number": "0123-4567-8910"
    }
  ]
}

如果使用 jsonpath 技术,可以先写好 jsonpath 表达式:

$.address.city

然后通过在线jsonpath解析网站可以得到结果,所有匹配的结果会存在一个元组当中。

["Nara"]

jsonpath 语法

JSONPath 描述 示例
$ 根目录对象,提取所有 $
. 或者 [] 子元素 .age.age 、[age] 、$['age']
.. 子孙元素 $..number
[0] 或者 .0 索引 phoneNumbers[0]
[0:2:step] 切片 phoneNumbers[0:2]
[0,1] 联合、或者 phoneNumbers[0,1]
* 通配符 address.* 、address[*]
@ 当前对象或元素,通过和 () 一起使用 phoneNumbers[(@.length-2)]
?() 过滤表达式 phoneNumbers[?(@.type=="iPhone")]

分别来看看这些表达式的结果吧:

  • $..number, 提取所有 key 为 number 的值
image-20210128212826936.png
  • phoneNumbers[0] 或者 phoneNumbers.0 ,获取 phoneNumbers 下面的数组第一个元素, jsonpath 的索引是从 0 开始的。
image-20210128213120003
  • phoneNumbers[0].type 或者 phoneNumbers.0.type
image-20210128213306149
  • phoneNumbers[0:2] 或者 phoneNumbers.0:2, 结尾位置不包含在内。
image-20210128213518524.png
  • phoneNumbers[0:2].number 或者 phoneNumbers.0:2.number
image-20210128213757154.png
  • phoneNumbers[0,1].number 或者 phoneNumbers.0,1.number
image-20210128213838081.png
  • address.* 或者 address[*]
image-20210128214026200

注意和 address 区分哦:

[
  {
    "streetAddress": "naist street",
    "city": "Nara",
    "postalCode": "630-0192"
  }
]
  • phoneNumbers[(@.length-2)] 获取phoneNumbers 下面的元组长度 - 2 的元素,等价于 phoneNumbers[0]
image-20210128214206603
  • 对于数组,可以使用过滤。过滤 phoneNumbers[?(@.type=="iPhone")]
image-20210128214258326
  • 正则表达式。phoneNumbers[?(@.type =~ "^h.*")]
image-20210128214446109.png

jsonpath-ng

jsonpath-ng[2] 是 python 解析 json 数据的一个库。融合了 jsonpath-rwjsonpath-rw-ext 的用法,支持正则等扩展操作。

from jsonpath_ng.ext import parse

s =  {"phoneNumbers": [
    {
      "type"  : "iPhone",
      "number": "0123-4567-8888"
    },
    {
      "type"  : "home",
      "number": "0123-4567-8910"
    }
  ]
}

# 使用正则表达式匹配 home
parser = parse('phoneNumbers[?(@.type =~ "^h.*")]')
resp = parser.find(s)

  1. https://goessner.net/articles/JsonPath/ ↩︎

  2. https://pypi.org/project/jsonpath-ng/ ↩︎