1

文章开篇

Python的魅力,犹如星河璀璨,无尽无边;人生苦短、我用Python!


JSONPath的简介

JSONPath是一种用于在JSON数据中查找和操作数据的表达式语言
它提供了一种简洁而灵活的方式,可以在复杂的JSON结构中快速定位和提取所需的数据
JSONPath可以在各种编程语言和工具中使用,例如在JavaScript、Python、Java等语言中都有对应的库或工具支持。
通过使用JSONPath,可以方便地从JSON数据中提取特定部分,进行进一步的处理和分析;


JSONPath的语法

JsonPath语法图


1.过滤器

在Python中,JSONPath的过滤器功能是一种强大的机制,它允许开发者以声明式的方式精确地筛选和定位JSON数据中的特定元素。
过滤器通过逻辑表达式来实现,这些表达式基于JSONPath语法,提供了对数组和对象元素的细粒度访问;
基于各种条件来过滤JSON数据,例如根据属性值是否大于、小于或等于某个值,或者是否等于某个特定的字符串;
可以使用单个条件来过滤数据,例如[?(@.age > 18)],这将选择所有年龄大于18岁的对象;
可以使用逻辑运算符&&(与)和||(或)来组合多个条件,从而构建更复杂的过滤表达式;
例如,[?(@.price < 10 && @.category == ‘fiction’)]将选择价格低于10且类别为’fiction’的对象;
JSONPath过滤器对字符串的处理非常严谨。
在过滤器表达式中,所有的字符串都必须用单引号包围,以确保字符串的正确解析。例如,[?(@.color == ‘blue’)]将选择所有颜色属性为’blue’的对象;

运算符


2.函数

虽然JsonPath表达式本身主要用于提取和过滤JSON数据,但通常在某些情境下,可能希望在表达式执行后对其结果进行进一步的处理。
但是,Python中的jsonpath库不直接支持在表达式执行后进行调用。这意味着,如果需要对JsonPath查询结果进行进一步的操作,需要在Python代码中显式地处理这些结果。
函数


JSONPath的验证

可以在**http://jsonpath.com/站点**进行验证JSONPath的执行效果。

站点图


JSONPath的安装

jsonpath模块属于Python第三方库,需要额外下载安装,命令如下:

pip install jsonpath
pip install jsonpath-ng  # 后面会使用ng模块封装一个工具类

JSONPath的使用

函数原型:def jsonpath(obj, expr, result_type=‘VALUE’, debug=0, use_eval=True)
函数参数释义:

  • **obj:**实际需要处理的json数据
  • **expr:**jsonpath表达式
  • **result_type:**返回结果的类型,默认为’Value’表示返回数据的值,'IPATH’表示返回数据的键
  • **debug:**是否开启调试模式 默认为0 关闭 ,非0都表示开启
  • **use_eval:**debug=1时,配合调试

示例数据
jd = {
    "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
}

示例代码

from jsonpath import jsonpath

# 返回书店中所有图书的作者
print(jsonpath(jd, "$.store.book[*].author"))   # ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien']
print(jsonpath(jd, "$..author"))    # ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien']

# 返回书店中所有的东西,不仅包括书,还有其他的物品
print(jsonpath(jd, "$.store.*"))    # [[{'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}], {'color': 'red', 'price': 19.95}]

# 返回书店中所有物品的价格
print(jsonpath(jd, "$.store..price"))   # [8.95, 12.99, 8.99, 22.99, 19.95]

# 第三本图书
print(jsonpath(jd, "$..book[2]"))   # [{'category': 'fiction', 'author': 'Herman Melville', 'title': 'Moby Dick', 'isbn': '0-553-21311-3', 'price': 8.99}]

# 倒数第二本书
print(jsonpath(jd, "$..book[-2:-1]"))   # [{'category': 'fiction', 'author': 'Herman Melville', 'title': 'Moby Dick', 'isbn': '0-553-21311-3', 'price': 8.99}]

# 前两本书
print(jsonpath(jd, "$..book[0,1]")) # [{'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}]

# 从索引 0(含)到索引 2(不含)的所有图书
print(jsonpath(jd, "$..book[:2]"))  # [{'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}]

# 从索引 1(含)到索引 2(不含)的所有图书
print(jsonpath(jd, "$..book[1:2]")) # [{'category': 'fiction', 'author': 'Evelyn Waugh', 'title': 'Sword of Honour', 'price': 12.99}]

# 最后两本书
print(jsonpath(jd, "$..book[-2:]")) # [{'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}]

# 从索引 2(含)到最后的所有书籍
print(jsonpath(jd, "$..book[2:]"))  # [{'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}]

# 所有带有 ISBN 编号的图书
print(jsonpath(jd, "$..book[?(@.isbn)]"))   # [{'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}]

# 返回店内价格等于10元的所有图书
print(jsonpath(jd, "$.store.book[?(@.price == 10)]"))   # False

# 返回店内价格小于10元的所有图书
print(jsonpath(jd, "$.store.book[?(@.price < 10)]"))    # [{'category': 'reference', 'author': 'Nigel Rees', 'title': 'Sayings of the Century', 'price': 8.95}, {'category': 'fiction', 'author': 'Herman Melville', 'title': 'Moby Dick', 'isbn': '0-553-21311-3', 'price': 8.99}]
print(jsonpath(jd, "$..book[?(@.price <= 10)]"))        # [{'category': 'reference', 'author': 'Nigel Rees', 'title': 'Sayings of the Century', 'price': 8.95}, {'category': 'fiction', 'author': 'Herman Melville', 'title': 'Moby Dick', 'isbn': '0-553-21311-3', 'price': 8.99}]

# 所有与正则表达式匹配的书籍(忽略大小写)
print(jsonpath(jd, "$..book[?(@.author =~ /.*REES/i)]"))    # False

# 把一切东西都返回
print(jsonpath(jd, "$..*")) # [{'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}}, 10, [{'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}], {'color': 'red', 'price': 19.95}, {'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}, 'reference', 'Nigel Rees', 'Sayings of the Century', 8.95, 'fiction', 'Evelyn Waugh', 'Sword of Honour', 12.99, 'fiction', 'Herman Melville', 'Moby Dick', '0-553-21311-3', 8.99, 'fiction', 'J. R. R. Tolkien', 'The Lord of the Rings', '0-395-19395-8', 22.99, 'red', 19.95]



真实工具类封装


from jsonpath_ng import jsonpath, parse


class JsonPathUtil:
    def __init__(self, data):
        self.data = data

    def find(self, path):
        """查询所有匹配项"""
        jsonpath_expr = parse(path)
        return [match.value for match in jsonpath_expr.find(self.data)]

    def find_first(self, path):
        """查询单个匹配项"""
        matches = self.find(path)
        if matches:
            return matches[0]
        return None

    def update(self, path, value):
        """手动更新匹配项的值"""
        jsonpath_expr = parse(path)
        matches = jsonpath_expr.find(self.data)
        if not matches:
            return False  # 未找到匹配项
        # 假设只更新第一个匹配项
        parent = matches[0].context.value
        if isinstance(parent, list):
            parent[matches[0].path.fields[0]] = value
        elif isinstance(parent, dict):
            parent[matches[0].path.fields[0]] = value
        return True

    def delete(self, path):
        """手动删除匹配项"""
        jsonpath_expr = parse(path)
        matches = jsonpath_expr.find(self.data)
        if not matches:
            return False  # 未找到匹配项
        # 假设只删除第一个匹配项
        parent = matches[0].context.value
        if isinstance(parent, list):
            del parent[matches[0].path.fields[0]]
        elif isinstance(parent, dict):
            del parent[matches[0].path.fields[0]]
        return True


# 示例使用
if __name__ == "__main__":
    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
                 }
            ],
            "bicycle": {
                "color": "red",
                "price": 19.95
            }
        }
    }

    util = JsonPathUtil(data)

    # 查询所有书的作者
    print("Authors:", util.find("$.store.book[*].author"))

    # 查询第一本书的价格
    print("First book price:", util.find_first("$.store.book[0].price"))

    # 尝试更新第一本书的价格
    if util.update("$.store.book[0].price", 9.99):
        print("Updated first book price:", data['store']['book'][0]['price'])

    # 尝试删除自行车的颜色
    if util.delete("$.store.bicycle.color"):
        print("Deleted bicycle color:", data['store']['bicycle'])


总结

JsonPath是Python中用于处理JSON数据的强大工具,它提供了一种简洁明了的查询语言,能够轻松提取和过滤JSON数据中的信息了;
无论是处理简单的键值对还是复杂的嵌套结构,JsonPath都能快速准确地完成任务。
此外,JsonPath还可与其他Python库结合,实现更丰富的数据处理功能。
广泛应用于数据提取、API测试、数据清洗等领域,是Python数据处理工具箱中不可或缺的一部分。

Logo

一站式 AI 云服务平台

更多推荐