json - 需要过滤值包含特定子字符串的所有键/值对
问题描述
我尝试为包含值“;自版本”的所有“描述”键过滤 JSON 文件,以打印它们的路径和该值中包含的版本。我在 bash 脚本中完成所有这些工作。
我正在过滤的 JSON 来自 API,并且在不同路径上具有“描述”键。
这是服务器 JSON 的摘录
到目前为止,我使用 curl 从服务器获取 JSON 并将其通过管道传递给 jq 应用以下过滤器以获取包含其描述中的值的所有路径的列表:
curl $api | jq 'paths(objects and (.description|index("; Since version")))'
这将返回一个列表,其中包含指向包含搜索值的端点的路径,如下所示:
[
"paths",
"/v4/user/profileAttributes/{key}",
"delete"
]
[
"paths",
"/v4/users/{user_id}/last_admin_rooms",
"get"
]
[
"definitions",
"GeneralSettings",
"properties",
"s3TagsEnabled"
]
当适应我搜索的字符串而不是整个列表时,我发现此过滤器返回看似随机的“描述”键/值对的值。不幸的是,我不太了解整个过滤器,因为作者没有在他的帖子中解释它。适应时
curl -s -N $api | jq '. as $in
| reduce paths(type == "string" and test("; Since version")) as $path ({};
($in|getpath($path)) as $x
| if ($path[-1]|type) == "string"
then .[$path[-1]] = $x
else .[$path[-2]|tostring] += [$x]
end )'
返回
{
"description": "Some_Text_We_Dont_Care_About; Since version 4.10.2 Some_More_Text_We_Dont_Care_About"
}
如果第二个过滤器将返回所有条目而不是(接缝随机的)条目,我将能够将两个过滤后的响应拼接在一起。我在这里发布了两个过滤器,因为也许有人知道如何以更清洁的方式进行操作。
理想情况下,最终结果将返回一个包含如下条目的列表:
{
"path": "
[
"paths",
"/v4/users/{user_id}/last_admin_rooms",
"get"
]"
",
"version": {
"description": "Some_Text_We_Dont_Care_About; Since version 4.10.2 Some_More_Text_We_Dont_Care_About"
}
}
这是输入内容的摘录/示例:
{
"info": {4 items},
"host": "some_hostname",
"basePath": "/api",
"tags": [19 items],
"paths": {
"/v4/config/info/defaults": {
"get": {
"tags": [
"config"
],
"summary": "Get default values",
"description": "SomeText; Since version 4.6.0 SomeMoreText",
"operationId": "getSystemDefaultsInfo",
"produces": [
"application/json;charset=UTF-8"
],
}
}
"/v4/config/info/general": {
"get": {
"tags": [
"config"
],
"summary": "Get general values",
"description": "SomeText; Since version 4.6.0 SomeMoreText",
"operationId": "getSystemDefaultsInfo",
"produces": [
"application/json;charset=UTF-8"
],
}
}
"definitions": {
"GeneralSettings": {
"type": "object",
"properties": {
"cryptoEnabled": {
"type": "boolean",
"description": "Activation status of encryption"
},
"s3TagsEnabled": {
"type": "boolean",
"description": "Defines if S3 tags are enabled; Since version 4.9.0 NEW"
},
"sharePasswordSmsEnabled": {
"type": "boolean",
"description": "Allow sending of share passwords via SMS"
}
}
}
}
}
解决方案
让我为您提供一个替代解决方案 - 使用基于步行路径的 unix 实用程序jtc
:
根据您想要的输出,jtc
查询将如下所示:
bash $ <file.json jtc -w'[description]:<.*; Since version.*>R: [-1] <act>k [-1] <path>k [-1] <pathname>k' -T'{ "path": [ {{pathname}}, {{path}}, {{act}}], "version": { "description": {{$0}}} }'
{
"path": [
"paths",
"/v4/config/info/defaults",
"get"
],
"version": {
"description": "SomeText; Since version 4.6.0 SomeMoreText"
}
}
{
"path": [
"paths",
"/v4/config/info/general",
"get"
],
"version": {
"description": "SomeText; Since version 4.6.0 SomeMoreText"
}
}
{
"path": [
"GeneralSettings",
"properties",
"s3TagsEnabled"
],
"version": {
"description": "Defines if S3 tags are enabled; Since version 4.9.0 NEW"
}
}
bash $
鉴于您的 Json 是不规则的(步行description
要求),但不确定是否需要查看最后一个对象。如果您不需要它,那么了解 JSON 的结构很容易增强查询以排除像最后一个那样的误报匹配。
编辑:说明:
-T
选项提供了一个 Json 模板,如果 walk 成功,则在{{..}}
每次 walk ( ) 结束时从命名空间中插入模板项(括在双花括号中)。-w
现在 walk-path ( -w
) 是遍历源 JSON 的方式:jtc
让 Json 自由地上下行走(使用下标[..]
)并执行递归搜索<..>
。虽然有些项目是directives
- 它们不进行任何搜索/匹配,而是应用某些操作(此符号中的单字母后缀<..>S
定义它是搜索还是指令)
让我在这里分解一下(顺便说一句,链接中描述了所有词位):
[description]:<.*; Since version.*>R:
- 对包含 的 JSON 字符串执行 RE 搜索; Since version
,但由于 RE 拼写匹配整个此类字符串(请注意.*
在 RE 表达式的开头和结尾处)。现在附加标签[description]:
确保这种 RE 匹配只会发生在带有附加标签的那些字符串中(而不是任何其他字符串)。:
在词位(又名量词)的末尾指示查找所有此类事件(搜索和与 Python 表示法兼容的下标中的量词)。[-1]<act>k
-[-1]
寻址找到的条目的父节点(来自上一个遍历步骤),并<act>k
记住命名空间中条目的标签act
(用于以后的模板插值) - 搜索词素末尾的后缀定义它是搜索还是指令(在这种情况k
是提取标签并在命名空间中记忆的指令)- 步行路径的重置是相同的:
[-1]<path>k
将从最后找到的条目(它又是第一步中找到的条目的父条目)寻址父级,并将在名称空间中记住其名称下的标签(键)path
(名称是任意的jtc
) [-1]<pathname>k'
- 做几乎相同的事情,然后步行结束(好吧,对于给定的迭代 - 如果你记得第一个步行词素是迭代的 - 它找到每个出现)然后应用模板插值,从而产生打印项目。
您可以轻松地使用查询(删除每个词位或添加您的词素,看看步行是如何工作的) - 我编辑了词位路径,将每个词位与空格分开。
PS> 披露:我是jtc
工具的创造者
推荐阅读
- python - Creating a json parsing function with Python
- python - How to get Chrome Native Messaging example to work with Python script on Mac
- python - 用多个元素交换 Python 中的元组列表
- kubernetes - 其他主机无法访问 Pod
- html - 如何在 Angular 中使用模板引用动态呈现 ng-template
- javascript - How to inject promise array inside observable array
- python - 使用来自另一个 Dataframe 的 iloc 更新 pandas DataFrame
- python-3.x - Is there a way that an exe file does not open command prompt if I use os.system in my .pyw code?
- javascript - Google Maps adjusting to include users and address
- excel - Path/File Access error for LoginForm.show