JMESPath 或 Ansible 扁平化字典

JMESPath or Ansible flatten dictionaries

我想像这样转换输入:

{
    "cluster1": {
        "services": {
            "service1": {
                "name": "foo",
                "version": 1.0
            },
            "service2": {
                "name": "bar",
                "version": 2.0
            }
        }
    },
    "cluster2": {
        "services": {
            "service3": {
                "name": "test",
                "version": 3.0
            },
            "service4": {
                "name": "s4",
                "version": 4.0
            }
        }
    },
    "cluster3": {
        "services": {
            "service5": {
                "name": "s5",
                "version": 5.0
            }
        }
    },
    "clusterx": {
        "name": "value"
    }
}

或这个(哪个无关紧要):

[
    {
        "key": "cluster1",
        "value": {
            "services": {
                "service1": {
                    "name": "foo",
                    "version": 1.0
                },
                "service2": {
                    "name": "bar",
                    "version": 2.0
                }
            }
        }
    },
    {
        "key": "cluster2",
        "value": {
            "services": {
                "service3": {
                    "name": "test",
                    "version": 3.0
                },
                "service4": {
                    "name": "s4",
                    "version": 4.0
                }
            }
        }
    },
    {
        "key": "cluster3",
        "value": {
            "services": {
                "service5": {
                    "name": "s5",
                    "version": 5.0
                }
            }
        }
    },
    {
        "key": "clusterx",
        "value": {
            "name": "value"
        }
    }
]

进入这个:

[
  { "name": "service1", "value": {
    "name": "foo",
    "version": 1
  },
  { "name": "service2", "value": {
    "name": "bar",
    "version": 2
  },
  { "name": "service3", "value": {
    "name": "test",
    "version": 3
  },
  { "name": "service4", "value": {
    "name": "s4",
    "version": 4
  },
  { "name": "service5", "value": {
    "name": "s5",
    "version": 5
  }
]

基本上我希望看​​到所有扁平化服务的列表。

可以用 JMESPath 做到这一点吗?

到目前为止,我对第二种输入类型的了解是:[?value.services].value.services 将我的输入转换为:

[
  {
    "service1": {
      "name": "foo",
      "version": 1
    },
    "service2": {
      "name": "bar",
      "version": 2
    }
  },
  {
    "service3": {
      "name": "test",
      "version": 3
    },
    "service4": {
      "name": "s4",
      "version": 4
    }
  },
  {
    "service5": {
      "name": "s5",
      "version": 5
    }
  }
]

所以我想我需要另一个级别的扁平化,但我不确定该怎么做。

顺便说一句,我正在使用 Ansible,其中 json_query 与 JMESPath 非常相似。 所以如果我们能用 Ansible 实现这个 / json_query,那也是完美的。

在 Ansible 中,我尝试了类似这样的东西,它几乎已经存在,但不完全是:

all_services: |
  {{ input | dict2items | json_query('[?value.services].value.services') }}

我们先组合一个扁平化的服务字典。例如

    - set_fact:
        all_services_dict: "{{ all_services_dict|default({})|combine(item) }}"
      loop: "{{ input|json_query('*.services') }}"
    - debug:
        var: all_services_dict

给予


    "all_services_dict": {
        "service1": {
            "name": "foo",
            "version": 1.0
        },
        "service2": {
            "name": "bar",
            "version": 2.0
        },
        "service3": {
            "name": "test",
            "version": 3.0
        },
        "service4": {
            "name": "s4",
            "version": 4.0
        },
        "service5": {
            "name": "s5",
            "version": 5.0
        }
    }

然后将服务串联成一个列表。例如

    - set_fact:
        all_services_list: "{{ all_services_list|default([]) +
                               [{'name': item.key,
                                 'value': item.value}] }}"
      loop: "{{ all_services_dict|dict2items }}"
    - debug:
        var: all_services_list

给予


    "all_services_list": [
        {
            "name": "service1",
            "value": {
                "name": "foo",
                "version": 1.0
            }
        },
        {
            "name": "service2",
            "value": {
                "name": "bar",
                "version": 2.0
            }
        },
        {
            "name": "service3",
            "value": {
                "name": "test",
                "version": 3.0
            }
        },
        {
            "name": "service4",
            "value": {
                "name": "s4",
                "version": 4.0
            }
        },
        {
            "name": "service5",
            "value": {
                "name": "s5",
                "version": 5.0
            }
        }
    ]