摘要
我有一个工作的jq过滤器,它正确地解析了三个不同的名称和有效负载对象,并将它们转换成所需的输出格式。问题是,我必须显式地表示每个对象路径,因为我看不到在对象标识符中找到一种表示替换的方法。
我希望过滤器更加灵活,这样它就可以显示从containers到任何以Packages开头的包管理器的数据结构。不过,我需要整个结构,而不仅仅是终端节点。
我认为我需要的是用替换或通配符来表示对象标识符,例如:
.capabilities.*.payload?.capabilities.([apk, dpkg, rpm]).payload?我意识到上述任何一个都不是有效的jq语法,这就是问题的原因。我在下面包含了一个具有有效JSON的测试语料库,我当前的jq过滤器列在下面的一节中。
最小JSON文件
这是我的测试语料库,存储在当前目录中的minimal.json中。
{
"containers": {
"3dc76c82e566a116e5b64bc91a0b6220c71db7052f68317ebbe90521db55bf36": {
"container_name": "/apache-46869",
"capabilities": {
"apk": {
"title": "Packages (APK)"
},
"dpkg": {
"title": "Packages (DPKG)",
"payload": {
"apt": "1.0.9.8.4",
"libnghttp2-14": "1.18.1-1"
}
},
"rpm": {
"title": "Packages (RPM)"
}
}
},
"474047a1fe238e39fa1917aff0c93154624bbf159d321d49d5e685302589ab51": {
"container_name": "/nginx-alpine-46869",
"capabilities": {
"apk": {
"title": "Packages (APK)",
"payload": {
".nginx-rundeps": "0",
"apk-tools": "2.6.8-r2"
}
},
"dpkg": {
"title": "Packages (DPKG)"
},
"rpm": {
"title": "Packages (RPM)"
}
}
},
"d7dcd90791240d78022941cf054a6b474f5329acd79aa15b58dc342f95a8ce33": {
"container_name": "/apache-alpine-46869",
"capabilities": {
"apk": {
"title": "Packages (APK)",
"payload": {
".httpd-rundeps": "0",
"apk-tools": "2.6.8-r2",
"apr": "1.5.2-r1",
"apr-util": "1.5.4-r2"
}
},
"dpkg": {
"title": "Packages (DPKG)"
},
"rpm": {
"title": "Packages (RPM)"
}
}
}
}
}显式jq滤波器
这是我的当前过滤器,它可以工作,但显式地定义了每个可选对象标识符-索引。
jq '
[ .containers[] | {
name: .container_name, package_inventory: {
apk: .capabilities.apk.payload?,
dpkg: .capabilities.dpkg.payload?,
rpm: .capabilities.rpm.payload?
}
}]
' minimal.json预期产出
我当前的输出(如下所示)是正确的。目标不是修复输出,而是使过滤器更加灵活。
{ "name":"/apache-46869","package_inventory":{ "apk":null,"dpkg":{ "apt":"1.0.9.8.4","libnghttp2-14":"1.18.1-1“},"rpm":null },{ "name":”nginx-高寒-46869“,"package_inventory":{ "apk":{“.name”:"0","apk-tools":"2.6.8-r2“},"dpkg":null,"rpm":null },{ "name":”/apache-高寒-46869“,"package_inventory":{ "apk":{“.package_inventory”:"0","apk-tools":"2.6.8-r2","apr":"1.5.2-r1","apr-util":"1.5.4-r2“},"dpkg":null,"rpm":null }
发布于 2017-05-06 17:17:08
诀窍是定义一个助手函数。例如,如果您写道:
def payloads(keys): . as $in
| reduce keys[] as $key ({}; .[$key] = ($in|.[$key].payload?) );然后,您的查询变成:
.containers[] | {
name: .container_name,
package_inventory: (.capabilities | payloads( ["apk","dpkg","rpm"] ))
}当然,其他变体也是可能的。例如,您可以将payloads定义为一个arity-2函数,从而传递“功能”。
使用JSON对象指定密钥
下面是payloads/1的一个变体,说明(a)如何避免reduce,(b)如何通过将JSON对象作为模板来指定键:
def payloads_at(object):
. as $in
| object as $object
| ({}
| [($object|keys_unsorted[]) as $key
| .[$key] = ($in|.[$key].payload?) ])
| add;可以这样调用: payloads_at( {apk,dpkg,rpm} ),或者如果您希望动态确定密钥:
(.capabilities | payloads_at( . ) )发布于 2017-05-06 19:46:50
这个助手函数可能更接近您要寻找的内容:
def star(pre; template; post):
pre as $object
| ({} | [($object|template|keys_unsorted[]) as $key | .[$key] = ($object | .[$key] | post) ])
| add;用法
明确的关键名称列表:
star(.capabilities; {apk,dpkg,rpm}; .payload).capabilities的密钥:
star(.capabilities; .; .payload)示例:
.containers[] | {
name: .container_name,
package_inventory: star(.capabilities; .; .payload)
}https://stackoverflow.com/questions/43822906
复制相似问题