下面是我的示例JSON文件。
[
{
"?xml": {
"attributes": {
"encoding": "UTF-8",
"version": "1.0"
}
}
},
{
"domain": [
{
"server": [
{
"name": "myserv1"
},
{
"ssl": {
"name": "myserv1"
}
},
{
"log": [
{
"name": "myserv1"
},
{
"file-name": "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
}
]
}
]
},
{
"server": [
{
"name": "myserv2"
},
{
"ssl": {
"name": "myserv2"
}
},
{
"log": [
{
"name": "myserv2"
},
{
"file-name": "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
}
]
}
]
}
]
}
]
我的要求是读取 json 文件并将值存储在文件中,如下所示:
myserv1_log: "/web/bea_logs/domains/mydom/myserv1/myserv1.log"
myserv2_log: "/web/bea_logs/domains/mydom/myserv2/myserv2.log"
即
<server>_log: <file-name>
这是我的 Ansible 游戏,它使用 JMESPath 查询来读取 json 数据。
- name: Server Names and log details
set_fact:
serverlog: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: '[].domain[].server[*].log[*].[name, "file-name"]'
- name: Print all server names with log details
debug:
msg: "{{ item }}"
with_items:
- "{{ serverlog }}"
如您所见,我在输出中得到了几个null
值
输出:
TASK [Print all server names with log details] *********************************
Wednesday 02 March 2022 03:17:45 -0600 (0:00:00.100) 0:00:04.730 *******
ok: [localhost] => (item=[]) => {
"msg": []
}
ok: [localhost] => (item=[[['myserv1', None], [None, '/web/bea_logs/domains/mydom/myserv1/myserv1.log']]]) => {
"msg": [
[
[
"myserv1",
null
],
[
null,
"/web/bea_logs/domains/mydom/myserv1/myserv1.log"
]
]
]
}
我使用以下方法摆脱了null
,但这也不能让我获得所需的输出:
- name: test
set_fact:
list2: "{{list2 + [item]}}"
when: item != "null"
with_items:
- "{{serverlog}}"
- name: Neww Print all server names with log details
debug:
msg: "{{ item }}"
with_items:
- "{{ list3 }}"
我也尝试了在StackOverflow上提出的解决方案,但出现错误:
"{{ jsondata | selectattr('domain', 'defined') | map(attribute='domain') | flatten | map(attribute='server') | flatten | selectattr('log', 'defined') | map(attribute='log') | map('combine') }}"
输出错误:
The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'server'nnThe error appears to be in....
任何早期的类似帖子都没有得到任何有效的解决方案,这就是我决定在这里发布的原因:
从列表 Ansible 中删除空元素
恳请建议。
你的json的结构总是相同的,不需要使用jmepath:
- hosts: localhost
gather_facts: no
vars:
json: "{{ lookup('file', './file.json') | from_json }}"
tasks:
- name: display
debug:
msg: "name: {{ servername }} --> filename: {{ filename }}"
loop: "{{ json[1].domain }}"
vars:
servername: "{{ item.server.0.name }}_log"
filename: "{{ item['server'][2]['log'][1]['file-name'] }}"
结果:
ok: [localhost] => (item={'server': [{'name': 'myserv1'}, {'ssl': {'name': 'myserv1'}}, {'log': [{'name': 'myserv1'}, {'file-name': '/web/bea_logs/domains/mydom/myserv1/myserv1.log'}]}]}) => {
"msg": "name: myserv1_log --> filename: /web/bea_logs/domains/mydom/myserv1/myserv1.log"
}
ok: [localhost] => (item={'server': [{'name': 'myserv2'}, {'ssl': {'name': 'myserv2'}}, {'log': [{'name': 'myserv2'}, {'file-name': '/web/bea_logs/domains/mydom/myserv2/myserv2.log'}]}]}) => {
"msg": "name: myserv2_log --> filename: /web/bea_logs/domains/mydom/myserv2/myserv2.log"
}
一些解释: JSON 是一个包含 2 条记录的数组,一条带有键?xml
另一条带有键domain
domain
是一个具有键server
的数组
server
是一个数组,其中包含不同的键name, ssl and log
log
是一个具有不同键的数组name and file-name
json[1].domain
只保留包含域的部分,json[0] 包含 json 的标头
item.server.0.name (= item['server'][0]['name'])
是记录服务器的第一项,其中包含密钥name
item['server'][2]['log'][1]['file-name']
是记录服务器的第三项,它包含密钥log
,日志的第二项包含密钥file-name