用 jq 在 JSON 结构中更深地转换键名
Transforming the name of key deeper in the JSON structure with jq
我关注json:
{
"vertices": [
{
"__cp": "foo",
"__type": "metric",
"__eid": "foobar",
"name": "Undertow Metrics~Sessions Created",
"_id": 45056,
"_type": "vertex"
},
...
]
"edges": [
...
我想实现这种格式:
{
"nodes": [
{
"cp": "foo",
"type": "metric",
"label": "metric: Undertow Metrics~Sessions Created",
"name": "Undertow Metrics~Sessions Created",
"id": 45056
},
...
]
"edges": [
...
到目前为止我能够创建这个表达式:
jq '{nodes: .vertices} | del(.nodes[]."_type", .nodes[]."__eid")'
即将 'vertices' 重命名为 'nodes' 并删除 '_type' 和 '__eid',如何重命名嵌套在 JSON 中的键?
如果使用 with_entries(filter)
,您可以更改对象的属性名称。这会将对象转换为 key/value 对的数组,并对这些对应用过滤器并转换回对象。因此,您只想将这些对象的键更新为您的新名称。
根据您使用的 jq 版本,下一部分可能会很棘手。直到 jq 1.5 才引入字符串替换。如果可用,您可以这样做:
{
nodes: .vertices | map(with_entries(
.key |= sub("^_+"; "")
)),
edges
}
否则,如果您使用的是 jq 1.4,则必须手动删除它们。递归函数可以帮助解决这个问题,因为下划线的数量不同。
def ltrimall(str): str as $str |
if startswith($str)
then ltrimstr($str) | ltrimall(str)
else .
end;
{
nodes: .vertices | map(with_entries(
.key |= ltrimall("_")
)),
edges
}
以下程序适用于 jq 1.4 或 jq 1.5。
它使用 walk/1 从任何键中删除前导下划线,无论它出现在输入 JSON.
中的什么位置
此处提供的 ltrim 版本使用 recurse/1 以提高效率和可移植性,但也可以使用任何合适的替代品。
def ltrim(c):
reduce recurse( if .[0:1] == c then .[1:] else null end) as $x
(null; $x);
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
.vertices = .nodes
| del(.nodes)
| (.vertices |= walk(
if type == "object"
then with_entries( .key |= ltrim("_") )
else .
end ))
从你的示例数据来看,你似乎打算进行很多小操作,所以我会把事情分成这样的阶段:
.nodes = .vertices # \ first take care of renaming
| del(.vertices) # / .vertices to .nodes
| .nodes = [
.nodes[] # \ then scan each node
| . as $n # /
| del(._type, .__eid) # \ whatever key-specific tweaks like
| .label = "metric: \(.name)" # / calculating .label you want can go here
| reduce keys[] as $k ( # \
{}; # | final reduce to handle renaming
.[$k | sub("^_+";"")] = $n[$k] # | any keys that start with _
) # /
]
我关注json:
{
"vertices": [
{
"__cp": "foo",
"__type": "metric",
"__eid": "foobar",
"name": "Undertow Metrics~Sessions Created",
"_id": 45056,
"_type": "vertex"
},
...
]
"edges": [
...
我想实现这种格式:
{
"nodes": [
{
"cp": "foo",
"type": "metric",
"label": "metric: Undertow Metrics~Sessions Created",
"name": "Undertow Metrics~Sessions Created",
"id": 45056
},
...
]
"edges": [
...
到目前为止我能够创建这个表达式:
jq '{nodes: .vertices} | del(.nodes[]."_type", .nodes[]."__eid")'
即将 'vertices' 重命名为 'nodes' 并删除 '_type' 和 '__eid',如何重命名嵌套在 JSON 中的键?
如果使用 with_entries(filter)
,您可以更改对象的属性名称。这会将对象转换为 key/value 对的数组,并对这些对应用过滤器并转换回对象。因此,您只想将这些对象的键更新为您的新名称。
根据您使用的 jq 版本,下一部分可能会很棘手。直到 jq 1.5 才引入字符串替换。如果可用,您可以这样做:
{
nodes: .vertices | map(with_entries(
.key |= sub("^_+"; "")
)),
edges
}
否则,如果您使用的是 jq 1.4,则必须手动删除它们。递归函数可以帮助解决这个问题,因为下划线的数量不同。
def ltrimall(str): str as $str |
if startswith($str)
then ltrimstr($str) | ltrimall(str)
else .
end;
{
nodes: .vertices | map(with_entries(
.key |= ltrimall("_")
)),
edges
}
以下程序适用于 jq 1.4 或 jq 1.5。 它使用 walk/1 从任何键中删除前导下划线,无论它出现在输入 JSON.
中的什么位置此处提供的 ltrim 版本使用 recurse/1 以提高效率和可移植性,但也可以使用任何合适的替代品。
def ltrim(c):
reduce recurse( if .[0:1] == c then .[1:] else null end) as $x
(null; $x);
# Apply f to composite entities recursively, and to atoms
def walk(f):
. as $in
| if type == "object" then
reduce keys[] as $key
( {}; . + { ($key): ($in[$key] | walk(f)) } ) | f
elif type == "array" then map( walk(f) ) | f
else f
end;
.vertices = .nodes
| del(.nodes)
| (.vertices |= walk(
if type == "object"
then with_entries( .key |= ltrim("_") )
else .
end ))
从你的示例数据来看,你似乎打算进行很多小操作,所以我会把事情分成这样的阶段:
.nodes = .vertices # \ first take care of renaming
| del(.vertices) # / .vertices to .nodes
| .nodes = [
.nodes[] # \ then scan each node
| . as $n # /
| del(._type, .__eid) # \ whatever key-specific tweaks like
| .label = "metric: \(.name)" # / calculating .label you want can go here
| reduce keys[] as $k ( # \
{}; # | final reduce to handle renaming
.[$k | sub("^_+";"")] = $n[$k] # | any keys that start with _
) # /
]