使用 jmespath 从 dict 中提取嵌套数组
Extract nested arrays from dict using jmespath
我有这个字典数组,其中包含来自 acme_certificate
的 Ansible 输出的数组,用于 DNS 挑战({{ le_challenges.results | json_query('[].challenge_data_dns') }}
):
[
{
"_acme-challenge.foo.example.de": [
"<token1>"
],
"_acme-challenge.bar.example.de": [
"<token2>",
"<token3>"
]
},
{
"_acme-challenge.baz.example.de": [
"<token4>"
]
}
]
因为我不需要单独的 _acme-challenge
记录,因为所有有问题的域都是针对单个 Route53 托管区域的 CNAME 别名,我需要将上述输出转换为此,以便我可以 运行 loop
超过 route53
个动作:
[
"<token1>",
"<token2>",
"<token3>",
"<token4>"
]
我在 Ansible 端尝试了所有可能的实验,包括 dict2list
和 map
,但我找不到完成此转换的方法,因为包含令牌的键具有动态名称。有什么想法吗?
查询字典的任何键就像在 JMESPath 中使用 .*
一样简单,然后您将得到一个令牌列表列表。
有了这个,就有了一个展平运算符,它很简单[]
,你需要对你想要展平的每一层列表重复它。
这就是说,您必须先重置您所做的投影:使用 pipe operator — |
。
所以,您的查询最终是:
[].challenge_data_dns.* | [][]
鉴于任务:
- debug:
var: >-
le_challenges.results | json_query(
'[].challenge_data_dns.* | [][]'
)
vars:
le_challenges:
results:
- challenge_data_dns:
_acme-challenge.foo.example.de:
- "<token1>"
_acme-challenge.bar.example.de:
- "<token2>"
- "<token3>"
- challenge_data_dns:
_acme-challenge.baz.example.de:
- "<token4>"
这产生:
? |-
le_challenges.results | json_query(
'[].challenge_data_dns.* | [][]'
)
: - <token1>
- <token2>
- <token3>
- <token4>
一般来说,在字典challenge_data_dns中,可能会有更多的属性伴随着_acme-challenge.*.example.de。然后,下面的表达式完成工作
le_tokens: "{{ le_challenges.results|
map(attribute='challenge_data_dns')|
map('dict2items')|
map('selectattr', 'key', 'match', key_match)|
map('map', attribute='value')|
flatten }}"
key_match: '_acme-challenge\.(.*)\.example\.de'
给予
le_tokens:
- <token1>
- <token2>
- <token3>
- <token4>
备注
使用以下数据进行测试
le_challenges:
results:
- challenge_data_dns:
_acme-challenge.foo.example.de:
- <token1>
b2: test
- challenge_data_dns:
_acme-challenge.bar.example.de:
- <token2>
- <token3>
- challenge_data_dns:
_acme-challenge.baz.example.de:
- <token4>
我有这个字典数组,其中包含来自 acme_certificate
的 Ansible 输出的数组,用于 DNS 挑战({{ le_challenges.results | json_query('[].challenge_data_dns') }}
):
[
{
"_acme-challenge.foo.example.de": [
"<token1>"
],
"_acme-challenge.bar.example.de": [
"<token2>",
"<token3>"
]
},
{
"_acme-challenge.baz.example.de": [
"<token4>"
]
}
]
因为我不需要单独的 _acme-challenge
记录,因为所有有问题的域都是针对单个 Route53 托管区域的 CNAME 别名,我需要将上述输出转换为此,以便我可以 运行 loop
超过 route53
个动作:
[
"<token1>",
"<token2>",
"<token3>",
"<token4>"
]
我在 Ansible 端尝试了所有可能的实验,包括 dict2list
和 map
,但我找不到完成此转换的方法,因为包含令牌的键具有动态名称。有什么想法吗?
查询字典的任何键就像在 JMESPath 中使用 .*
一样简单,然后您将得到一个令牌列表列表。
有了这个,就有了一个展平运算符,它很简单[]
,你需要对你想要展平的每一层列表重复它。
这就是说,您必须先重置您所做的投影:使用 pipe operator — |
。
所以,您的查询最终是:
[].challenge_data_dns.* | [][]
鉴于任务:
- debug:
var: >-
le_challenges.results | json_query(
'[].challenge_data_dns.* | [][]'
)
vars:
le_challenges:
results:
- challenge_data_dns:
_acme-challenge.foo.example.de:
- "<token1>"
_acme-challenge.bar.example.de:
- "<token2>"
- "<token3>"
- challenge_data_dns:
_acme-challenge.baz.example.de:
- "<token4>"
这产生:
? |-
le_challenges.results | json_query(
'[].challenge_data_dns.* | [][]'
)
: - <token1>
- <token2>
- <token3>
- <token4>
一般来说,在字典challenge_data_dns中,可能会有更多的属性伴随着_acme-challenge.*.example.de。然后,下面的表达式完成工作
le_tokens: "{{ le_challenges.results|
map(attribute='challenge_data_dns')|
map('dict2items')|
map('selectattr', 'key', 'match', key_match)|
map('map', attribute='value')|
flatten }}"
key_match: '_acme-challenge\.(.*)\.example\.de'
给予
le_tokens:
- <token1>
- <token2>
- <token3>
- <token4>
备注
使用以下数据进行测试
le_challenges:
results:
- challenge_data_dns:
_acme-challenge.foo.example.de:
- <token1>
b2: test
- challenge_data_dns:
_acme-challenge.bar.example.de:
- <token2>
- <token3>
- challenge_data_dns:
_acme-challenge.baz.example.de:
- <token4>