如何递归合并继承的json数组元素? [英] How to recursively merge inherited json array elements?
本文介绍了如何递归合并继承的json数组元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有一个名为CMakePresets.json
的json文件,它是cmake-preset文件:
{
"configurePresets": [
{
"name": "default",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/_build/${presetName}",
"cacheVariables": {
"YIO_DEV": "1",
"BUILD_TESTING": "1"
}
},
{
"name": "debug",
"inherits": "default",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release",
"inherits": "default",
"binaryDir": "${sourceDir}/_build/Debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "arm",
"inherits": "debug",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/Toolchain/arm-none-eabi-gcc.cmake"
}
}
]
}
我希望与*
元素递归合并,这些元素为特定条目name
继承自身。我有一个名称为arm
的节点,并希望得到具有解析继承的结果json对象。父元素的名称存储在每个元素的.inherits
中。arm
继承的debug
继承的default
。
我可以在Remove a key:value from an JSON object using jq和this answer的帮助下编写我认为可以工作的bash外壳循环:
input=arm
# extract one element
g() { jq --arg name "$1" '.configurePresets[] | select(.name == $name)' CMakePresets.json; };
# get arm element
acc=$(g "$input");
# If .inherits field exists
while i=$(<<<"$acc" jq -r .inherits) && [[ -n "$i" && "$i" != "null" ]]; do
# remove it from input
a=$(<<<"$acc" jq 'del(.inherits)');
# get parent element
b=$(g "$i");
# merge parent with current
acc=$(printf "%s
" "$b" "$a" | jq -s 'reduce .[] as $item ({}; . * $item)');
done;
echo "$acc"
输出,我认为这是arm
的预期输出:
{
"name": "arm",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/_build/${presetName}",
"cacheVariables": {
"YIO_DEV": "1",
"BUILD_TESTING": "1",
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/Toolchain/arm-none-eabi-gcc.cmake"
}
}
但我想用jq
来写。我试过了,jq
语言对我来说不是很直观。例如,我可以为两个人(即,可数)元素:
< CMakePresets.json jq --arg name "arm" '
def g(n): .configurePresets[] | select(.name == n);
g($name) * (g($name) | .inherits) as $name2 | g($name2)
'
但我不知道怎么做reduce .[] as $item ({}; . * $item)
当$item
真的是g($name)
,这取决于最后的g($name) | .inherits
。我试着阅读jq manual并学习变量和循环,但jq
有非常不同的语法。我尝试使用while
,但这只是一个语法错误,我不理解,也不知道如何修复。我猜while
和until
可能不在这里,因为它们在前面的循环输出上操作,而元素总是从根开始。
$ < CMakePresets.json jq --arg name "arm" 'def g(n): .configurePresets[] | select(.name == n);
while(g($name) | .inherits as $name; g($name))
'
jq: error: syntax error, unexpected ';', expecting '|' (Unix shell quoting issues?) at <top-level>, line 2:
while(g($name) | .inherits as $name; g($name))
jq: 1 compile error
如何用jq
语言编写这样的循环?
推荐答案
假设继承层次结构不包含循环,如本例所示,我们可以将问题分解为以下几个部分:
# Use an inner function of arity 0 to take advantage of jq's TCO
def inherits_from($dict):
def from:
if .name == "default" then .
else $dict[.inherits] as $next
| ., ($next | from)
end;
from;
def chain($start):
INDEX(.configurePresets[]; .name) as $dict
| $dict[$start] | inherits_from($dict);
reduce chain("arm") as $x (null;
($x.cacheVariables + .cacheVariables) as $cv
| $x + .
| .cacheVariables = $cv)
| del(.inherits)
这将有效地产生所需的输出。
上述解决方案公式的一个优点是,可以轻松地对其进行修改以处理循环依赖。
使用recurse/1
inherits_from/1
也可以使用内置函数recurse/1
定义:
def inherits_from($dict):
recurse( select(.name != "default") | $dict[.inherits]) ;
或者更有趣的是:
def inherits_from($dict):
recurse( select(.inherits) | $dict[.inherits]) ;
使用*
使用*
组合对象的开销很高,因为它的递归语义通常不是必需的,就是不需要的。然而,
如果使用*
组合对象在这里是可以接受的,则上述内容可以简化为:
def inherits_from($dict):
recurse( select(.inherits) | $dict[.inherits]) ;
INDEX(.configurePresets[]; .name) as $dict
| $dict["arm"]
| reduce inherits_from($dict) as $x ({}; $x * .)
| del(.inherits)
这篇关于如何递归合并继承的json数组元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文