我有2个具有以下结构的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脚本也可以。 任何帮助,将不胜感激!
答案 0 :(得分:0)
这是一种实现方法:
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
命令输入参数说明:
--slurp
/-s
:不必为输入中的每个JSON对象运行过滤器,而是将整个输入流读入一个大数组,然后仅运行过滤器一次。
-f filename
/--from-file filename
:像awk的-f选项一样,从文件而不是从命令行读取过滤器。您还可以使用“#”发表评论。
This jqplay snippet通过提供对象列表而不是多个对象来模拟-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": [...]}
的值,.
是中间字典/对象,包含{{1 }}和值是类似"Plugin X"
的对象。
由于if-then-else有点长,我将其移至辅助过滤器$plugin
中。这种过滤器有两件事:mergePlugin
和.
。
这将产生:
$plugin
这几乎是最终结果,除了现在有可以废弃的不必要的{
"Plugin A": {
"Name": "Plugin A",
"Installation": [
{
"Version": "1.0",
"Server": "abc"
},
{
"Version": "1.1",
"Server": "xyz"
}
]
},
...
}
包装器和缺少的{"Plugin A": {...}}
包装器之外。
改进思路:
我敢肯定您可以做些比...更聪明的事情
{"Plugins": [...]}
对于这最后一部分,它确实起作用。
我还认为实际合并可以比if-then-else短。