我有两个具有以下结构的JSON文件
File1.json
{
"Plugins": [
{
"Name": "Plugin A",
"Installation": [
{
"Version": "1.0",
"Server" : "abc"
}
]
},
{
"Name": "Plugin B",
"Installation": [
{
"Version": "2.0",
"Server" : "abc"
}
]
},
{
"Name": "Plugin C",
"Installation": [
{
"Version": "2.0",
"Server" : "abc"
}
]
}
]
}File2.json
{
"Plugins": [
{
"Name": "Plugin A",
"Installation": [
{
"Version": "1.1",
"Server" : "xyz"
}
]
},
{
"Name": "Plugin B",
"Installation": [
{
"Version": "2.0",
"Server" : "xyz"
}
]
},
]
}我想把它们合并,得到这样的输出
{
"Plugins": [
{
"Name": "Plugin A",
"Installation": [
{
"Version": "1.0",
"Server" : "abc"
},
{
"Version": "1.1",
"Server" : "xyz"
}
]
},
{
"Name": "Plugin B",
"Installation": [
{
"Version": "2.0",
"Server" : "abc"
},
{
"Version": "2.0",
"Server" : "xyz"
}
]
},
{
"Name": "Plugin C",
"Installation": [
{
"Version": "2.0",
"Server" : "abc"
}
]
}
]
}这两个JSON文件具有完全相同的结构,但仅在文件中的内容方面有所不同。我主要考虑使用jq实用工具。Shell或jenkins-groovy脚本也可以。任何帮助都将不胜感激!
发布于 2019-11-29 13:30:04
有一种方法可以做到:
def mergePlugin($plugin):
if .[$plugin.Name]
then .[$plugin.Name].Installation += $plugin.Installation
else .[$plugin.Name] = $plugin
end;
{
"Plugins": (
map(.Plugins)
| add
| reduce .[] as $plugin ({}; mergePlugin($plugin))
| to_entries | map(.value)
)
}运行此命令:
jq -s -f mergePlugins.jq File*.json命令-ine论点解释如下:
--slurp/-s:与其为输入中的每个JSON对象运行过滤器,不如将整个输入流读入一个大数组中,只运行一次过滤器。-f filename/--from-file filename:从文件而不是命令行读取过滤器,比如awk的-f选项。您还可以使用´#´进行注释。
这个jqplay片段通过提供对象列表作为输入而不是多个对象来模拟-s。
下面是解决方案的工作原理:jq -s '.' File*.json提供了一个{"Plugins": [...]}对象列表。由于对[...]部件感兴趣,jq -s 'map(.Plugins)' File*.json提供了以下列表(每个文件一个):
[
[
{
"Name": "Plugin A",
...
},
{
"Name": "Plugin B",
...
},
{
"Name": "Plugin C",
...
}
],
[
{
"Name": "Plugin A",
...
},
{
"Name": "Plugin B",
...
}
]
]我们可以使用jq -s 'map(.Plugins) | add' File*.json折叠一层嵌套列表。
[
{
"Name": "Plugin A",
...
},
{
"Name": "Plugin B",
...
},
...
]对于下一部分,由于我希望将所有的"Name": "Plugin X"合并在一起,所以我认为一个字典/对象(键是"Plugin X" )将是一个很好的数据结构,因为对于每个插件,如果我以前是否遇到它,我可以做一个固定时间的查找。
我使用reduce构建了这个字典
reduce .[] as $plugin ({}; ...some expression using '.' and '$plugin'...){}是这个对象的初始值,$plugin是每个{"Name": "Plugin X", "Installation": [...]}值,而.是中间字典/对象,包含键是"Plugin X",值是$plugin-like对象。
因为如果-然后这个过滤器有两样东西:.和$plugin。
这就产生了:
{
"Plugin A": {
"Name": "Plugin A",
"Installation": [
{
"Version": "1.0",
"Server": "abc"
},
{
"Version": "1.1",
"Server": "xyz"
}
]
},
...
}这几乎是最后的结果,只是有一个不必要的{"Plugin A": {...}}包装器现在可以废弃,还有一个缺少的{"Plugins": [...]}包装器需要重新添加。
改进的想法:
{ "Plugins": ( ... | to\_entries | map(.value) ) }
这是最后一部分,但它完成了任务。https://stackoverflow.com/questions/59104389
复制相似问题