JMESPath(发音为“james路径”)允许您声明式地指定如何从 JSON 文档中提取元素。
例如,给定此文档:
{"foo": {"bar": "baz"}}
jmespath 表达式 foo.bar 将返回“baz”。
JMESPath 还支持:
引用列表中的元素。给定数据:
{"foo": {"bar": ["one", "two"]}}
表达式:foo.bar[0] 将返回“one”。您还可以使用 * 语法引用列表中的所有项目:
{"foo": {"bar": [{"name": "one"}, {"name": "two"}]}}
表达式:foo.bar[*].name 将返回 ["one", "two"]。还支持负数索引(-1 指向列表的最后一个元素)。给定上述数据,表达式 foo.bar[-1].name 将返回 "two"。
* 也可用于哈希类型:
{"foo": {"bar": {"name": "one"}, "baz": {"name": "two"}}}
表达式:foo.*.name 将返回 ["one", "two"]。
您可以使用以下命令从 pypi 安装 JMESPath:
pip install jmespath jmespath.py 库有两个函数可用于操作 Python 数据结构。您可以使用 search 函数,并向其提供 jmespath 表达式和数据:
>>> import jmespath
>>> path = jmespath.search('foo.bar', {'foo': {'bar': 'baz'}})
'baz'与 re 模块类似,您可以使用 compile 函数来编译 JMESPath 表达式,并使用此解析后的表达式执行重复搜索:
>>> import jmespath
>>> expression = jmespath.compile('foo.bar')
>>> expression.search({'foo': {'bar': 'baz'}})
'baz'
>>> expression.search({'foo': {'bar': 'other'}})
'other'如果您将相同的 jmespath 表达式用于搜索多个文档,这将非常有用。这避免了每次搜索新文档时都必须重新解析 JMESPath 表达式。
您可以提供 jmespath.Options 的实例来控制 JMESPath 表达式的评估方式。使用 Options 实例最常见的情况是,如果您希望字典键的输出是有序的。为此,您可以使用以下任一选项:
>>> import jmespath
>>> jmespath.search('{a: a, b: b}',
... mydata,
... jmespath.Options(dict_cls=collections.OrderedDict))
>>> import jmespath
>>> parsed = jmespath.compile('{a: a, b: b}')
>>> parsed.search(mydata,
... jmespath.Options(dict_cls=collections.OrderedDict))JMESPath 语言有许多内置函数,但也可以添加自己的自定义函数。请注意,jmespath.py 中的自定义函数支持是实验性的,API 可能会根据反馈进行更改。
如果您有一个有用的自定义函数,可以考虑将其提交到 jmespath.site 并提议将其添加到 JMESPath 语言中。 您可以在此处提交提案。
要创建自定义函数:
- 创建一个
jmespath.functions.Functions的子类。 - 创建一个名为
_func_<your function name>的方法。 - 应用
jmespath.functions.signature装饰器,该装饰器指示了函数参数的预期类型。 - 在
jmespath.Options对象中提供您子类的实例。
以下是一些示例:
import jmespath
from jmespath import functions
# 1. 创建 functions.Functions 的子类。
# functions.Functions 基类具有逻辑,
# 该逻辑会内省其所有方法,并自动
# 将您的自定义函数注册到其函数表中。
class CustomFunctions(functions.Functions):
# 2 和 3. 创建一个以 _func_ 开头的函数
# 并使用 @signature 装饰它,该装饰器指示了其
# 预期类型。
# 在这个例子中,我们正在创建一个名为“unique_letters”的 jmespath 函数
# 该函数接受一个参数
# 预期类型为“string”。
@functions.signature({'types': ['string']})
def _func_unique_letters(self, s):
# 给定一个字符串 s,返回一个排序的
# 唯一的字母字符串:'ccbbadd' -> 'abcd'
return ''.join(sorted(set(s)))
# 另一个例子。这正在创建一个
# 名为“my_add”的 jmespath 函数,该函数需要
# 两个参数,两者都应该是数字类型。
@functions.signature({'types': ['number']}, {'types': ['number']})
def _func_my_add(self, x, y):
return x + y
# 4. 在 Options 对象中提供您子类的实例。
options = jmespath.Options(custom_functions=CustomFunctions())
# 将此值提供给 jmespath.search:
# 这将打印 3
print(
jmespath.search(
'my_add(`1`, `2`)', {}, options=options)
)
# 这将打印“abcd”
print(
jmespath.search(
'foo.bar | unique_letters(@)',
{'foo': {'bar': 'ccbbadd'}},
options=options)
)同样,如果您提出了有用的函数,您认为它们符合 JMESPath 语言(并且可以实现到所有 JMESPath 库中,而不仅仅是 Python),请在jmespath.site告知我们。
如果您想了解更多关于 JMESPath 语言的信息,可以查看JMESPath 教程。还可以查看JMESPath 示例页面,了解更复杂的 jmespath 查询示例。
语法根据RFC4234的描述,使用 ABNF 指定。您可以在此处找到最新的JMESPath 语法。
您可以在此处阅读完整的JMESPath 规范。
除了 jmespath 模块的单元测试外,还有一个 tests/compliance 目录,其中包含带有测试用例的 .json 文件。这使得其他实现可以验证它们是否产生了正确的输出。每个 json 文件按功能分组。
如果您想聊天或有任何疑问,请加入我们的Gitter 频道。