我希望我已经清楚地表达了我的问题。需要帮助来查询和解析使用JQ的多个json文件,其中每个文件的结构是非线性的。应用程序生成如下示例所示的配置数据。每个文件可以有零个或多个DualEndPoint或Local对象。我需要能够在" user“属性中查询特定用户,并插入新密码以便重新提交回api。对于DualEndPoints,嵌套的对象名称是可变的,因此在查找"User“属性时不能对这些值进行编码。
如果找到特定用户的匹配项,则返回整个结构,其中只插入了该用户的新密码。在本例中,查询user1将返回整个PROFILE1和PROFILE2,但不会返回PROFILE3,因为它不包含user1凭据。
{
"PROFILE1": {
"Type": "ConnectionProfile:FileTransfer:DualEndPoint",
"WorkloadAutomationUsers": [
"*"
],
"VerifyBytes": true,
"TargetAgent": "sqlrptvmjhbpr01",
"TargetCTM": "Production",
"Endpoint:Src:Local_0": {
"Type": "Endpoint:Src:Local",
"User": "user1",
"Port": "0",
"OsType": "Windows",
"HostName": "Local",
"Password": "*****",
"HomeDirectory": "/user1homedir"
},
"Endpoint:Dest:SFTP_1": {
"Type": "Endpoint:Dest:SFTP",
"User": "user2",
"HostName": "server2",
"Password": "*****",
"HomeDirectory": "/user2homedir"
}
},
"PROFILE2": {
"Type": "ConnectionProfile:FileTransfer:Local",
"WorkloadAutomationUsers": [
"*"
],
"VerifyBytes": true,
"User": "user1",
"VerifyDestination": true,
"OsType": "Windows",
"HostName": "Local",
"Password": "*****",
"TargetAgent": "server1",
"TargetCTM": "Production"
},
"PROFILE3": {
"Type": "ConnectionProfile:FileTransfer:Local",
"WorkloadAutomationUsers": [
"*"
],
"VerifyBytes": true,
"User": "user3",
"OsType": "Windows",
"HostName": "Local",
"Password": "*****",
"HomeDirectory": "/user3hoemdir",
"TargetAgent": "server2",
"TargetCTM": "Production"
}
}发布于 2020-01-20 21:35:01
在jq 1.6中,您可以使用以下内容:
jq --arg newPwd "newPassword" \
'walk(if type == "object" and .User == "user1" then .password |= $newPwd else . end)
| map_values(select(.. | select(type == "object") and .User == "user1"))' 这将递归您的JSON输入,并将具有User : "user1"键/值对的对象的password字段设置为您想要的值。
你可以使用try it here。
在以前的版本中,您可以使用以下等效项:
jq --arg newPwd "newPassword" \
'def rec :
if type == "object" and .User == "user1" then
.password = $newPwd
elif type == "object" then
map_values(rec)
elif type == "array" then
map(rec)
else
.
end
;
rec | map_values(select(.. | select(type == "object") and .User == "user1"))'你可以使用try it here。
发布于 2020-01-21 16:09:55
在以下针对所述问题的解决方案中,有两个步骤。第一步使用with_entries选择相关的“配置文件”对象,第二步使用walk更新密码。参数化所有东西都很容易,所以为了简单起见,让我们假设(就像在Q中一样)用户是"user1":
with_entries(select( .value
| any(paths(. == "user1");
.[-1] == "User" )))
| walk( if type == "object" and .User == "user1" and has("Password")
then .Password = "newpassword"
else .end)这里使用any会让事情变得有点复杂,但这是为了提高效率。
关于walk/1的说明
如果您的jq没有walk/1,那么现在将是更新您的jq的好时机,但如果没有选择,只需搜索其def (搜索词: jq def walk builtin.jq)并将其复制到您的jq程序的开头。
发布于 2020-01-20 21:58:49
欢迎使用StackOverflow!
完整的示例不是一个有效的JSON对象,也没有试图解决这个问题,也没有一个期望的结果应该是什么样子的示例。因此,下面的答案带有一些猜测。如果将示例修剪成一个去除了所有杂乱的minimal, reproducible example,则可能会大大增加获得好答案的几率。
例如,"TargetAgent": "sqlrptvmjhbpr01"似乎是不相关的信息。这一行的唯一效果是增加了读者的认知负荷,试图破译它是否与问题任务相关,而事实似乎并非如此。
每个文件可以有零个或多个DualEndPoint或Local对象。
您并没有确切地说明DualEndPoint或Local对象是什么。
因为文本DualEndPoint只出现在
"Type": "ConnectionProfile:FileTransfer:DualEndPoint"我假设DualEndPoint对象包含一个键-值对,其格式为
"Type": "...:DualEndPoint"Local对象是相同的,但是用Local替换了DualEndPoint。如果这种解释是正确的,那么您的第一个代码片段中的两个不同嵌套级别(这就是我所理解的“非线性”部分)中的Local对象将有三个示例。
Local对象的一个示例是:
{
"Type": "Endpoint:Src:Local",
"User": "user1",
"Port": "0",
"OsType": "Windows",
"HostName": "Local",
"Password": "newpassword",
"HomeDirectory": "/user1homedir"
}没有任何类似的对象的例子,尽管包含"User“属性,但不应该被更新。因此,为了回答这个问题,这些类型的对象之间的区别也是完全不必要的?
我需要能够在" user“属性中查询特定用户,并插入新密码以重新提交回接口。
因此,您的主要问题的一个子问题可能是使用新密码更新对象(如果它是正确的User )。假设你已经将对象的范围缩小到这样一个对象,程序的一个子部分可能如下所示:
$ jq 'if .User == "user1" then .Password = "derp" else . end' local1.json
{
"Type": "Endpoint:Src:Local",
"User": "user1",
"Port": "0",
"OsType": "Windows",
"HostName": "Local",
"Password": "derp",
"HomeDirectory": "/user1homedir"
}对于DualEndPoints,嵌套的对象名称是可变的,因此在查找“
”属性时不能对这些值进行编码。
因此,这听起来像是您想要任意递归查找具有"User“属性的对象。jq的一些递归组合器是..,更通用的recurse,在这个上下文中似乎更合适的是walk
$ jq 'walk(if type == "object" and .User == "user1"
then .Password = "derp"
else . end)' full.json(这也是Aaron发布的,除了他使用|=,而我使用=。)
请看他的jqplay示例或this jqplay example。
如果找到特定用户的匹配项,则返回整个结构,其中只插入了该用户的新密码。在本例中,查询user1将返回整个PROFILE1和PROFILE2,但不会返回PROFILE3,因为它不包含user1凭据。
这听起来像是我们使用的表达式中的一个额外条件:
$ jq 'walk(if type == "object" and has("User")
then (if .User == "user1"
then .Password = "derp"
else null end)
else . end)' full.json这看起来几乎可以工作(请参见this jqplay example),除了它将"foo": null值保留为遍历的结果。这是已经递归到包含"User“属性的对象中的副产品,这使得很难表达应该删除父键-值对。
要解决这个问题,我们需要在walk/1的过滤器中向前看,或者创建一个占位符,然后从父对象的角度再次遍历。后面的两种策略如下所示:
$ jq 'walk(if type == "object" and has("User")
then (if .User == "user1" then .Password = "derp" else "wat" end)
else . end)
| walk(if type == "object"
then with_entries(select(.value != "wat"))
else . end)' full.json这似乎是可行的。参见this jqplay example。
https://stackoverflow.com/questions/59823154
复制相似问题