jq:测试键是否在预定义键列表中
jq: Testing if a key is in a list of predefined keys
我有一个案例需要解析 JSON 中引用的 JSON。
我知道哪些 optional 属性将包含带引号的 JSON 而哪些不包含。
因此,我想检查属性键是否在可能的键列表中。我已经有以下内容:
# attributes "a" and "b" contain quoted JSON
echo '{"a":"{\"x\":1}","y":2}' |
jq -c '
def is_json($o): ["a","b"] | (map(select(. == $o)) | length) > 0;
with_entries(if is_json(.key) then .value = (.value|fromjson) else . end)
'
这已经产生了所需的输出:{"a":{"x":1},"y":2}
。然而,属性名称的检查看起来很笨拙,因为 jq
提供了很多内置函数,例如 has
、in
、contains
、inside
等
问题:是否有更好的方法来检查属性键是否在给定列表中?
编辑:这是当前的解决方案,基于 peak 的回答。
#!/bin/bash
to_array_string() { echo "$*" | awk -v OFS='","' 'NF > 0 {=; print "\""[=11=]"\""}'; }
to_json_array_string() { echo "["`to_array_string "$@"`"]"; }
parse_json_jq() { jq -c "
reduce keys[] as $key
(.; if any((`to_array_string "$@"`); . == $key) and .[$key] != null then .[$key] |= fromjson else . end)
";}
可以通过三种方式改进您的程序:
- (效率)避免创建不必要的数组(在
is_json
中);
- (efficiency) 使用 "short-circuit" 语义来避免
不必要的迭代;
- (效率)避免 construction/deconstruction 涉及 with_entries;
在大多数情况下,我认为您会同意这里提供的替代方案更简单、更简洁或更具可读性。
如果您有jq 1.5或更高版本,主要改进
可以使用 any/2:
def is_json($o): any( ("a","b"); . == $o );
with_entries(if is_json(.key) then .value |= fromjson else . end)
另请注意在您使用“=”的地方使用了“|=”。
如果你的jq没有any/2
,那么你可以使用下面的
定义,尽管它缺少短路语义:
def any(s): reduce s as $i (false; . == true or $i);
最后,为了避免使用 with_entries
,您可以使用 reduce
并完全消除 is_json
:
reduce keys[] as $key
(.; if any(("a","b"); . == $key) then .[$key] |= fromjson else . end)
我有一个案例需要解析 JSON 中引用的 JSON。 我知道哪些 optional 属性将包含带引号的 JSON 而哪些不包含。 因此,我想检查属性键是否在可能的键列表中。我已经有以下内容:
# attributes "a" and "b" contain quoted JSON
echo '{"a":"{\"x\":1}","y":2}' |
jq -c '
def is_json($o): ["a","b"] | (map(select(. == $o)) | length) > 0;
with_entries(if is_json(.key) then .value = (.value|fromjson) else . end)
'
这已经产生了所需的输出:{"a":{"x":1},"y":2}
。然而,属性名称的检查看起来很笨拙,因为 jq
提供了很多内置函数,例如 has
、in
、contains
、inside
等
问题:是否有更好的方法来检查属性键是否在给定列表中?
编辑:这是当前的解决方案,基于 peak 的回答。
#!/bin/bash
to_array_string() { echo "$*" | awk -v OFS='","' 'NF > 0 {=; print "\""[=11=]"\""}'; }
to_json_array_string() { echo "["`to_array_string "$@"`"]"; }
parse_json_jq() { jq -c "
reduce keys[] as $key
(.; if any((`to_array_string "$@"`); . == $key) and .[$key] != null then .[$key] |= fromjson else . end)
";}
可以通过三种方式改进您的程序:
- (效率)避免创建不必要的数组(在
is_json
中); - (efficiency) 使用 "short-circuit" 语义来避免 不必要的迭代;
- (效率)避免 construction/deconstruction 涉及 with_entries;
在大多数情况下,我认为您会同意这里提供的替代方案更简单、更简洁或更具可读性。
如果您有jq 1.5或更高版本,主要改进 可以使用 any/2:
def is_json($o): any( ("a","b"); . == $o );
with_entries(if is_json(.key) then .value |= fromjson else . end)
另请注意在您使用“=”的地方使用了“|=”。
如果你的jq没有any/2
,那么你可以使用下面的
定义,尽管它缺少短路语义:
def any(s): reduce s as $i (false; . == true or $i);
最后,为了避免使用 with_entries
,您可以使用 reduce
并完全消除 is_json
:
reduce keys[] as $key
(.; if any(("a","b"); . == $key) then .[$key] |= fromjson else . end)