3 votes

JMESPath pour générer un tableau d'objets à partir d'un objet d'objets

J'ai l'exemple suivant de document json (objet des objets) :

{
   "key1": { "key1a": [{"key1aa": "value1aa"}, {"key1ab": "value1ab"}],... },
   "key2": { "key2a": [{"key2aa": "value2aa"}, {"key2ab": "value2ab"}],... },
   ...
}

Et j'essaie de le remodeler en un tableau de ces objets, par exemple

[
  { "key1": { "key1a": [{"key1aa": "value1aa"}, {"key1ab": "value1ab"}],... }},
  { "key2": { "key2a": [{"key2aa": "value2aa"}, {"key2ab": "value2ab"}],... }},
  ...
]

Ce que je peux utiliser est JMESPath à l'intérieur du filtre jinja2 json_query d'Ansible.

Comment est-ce possible ?

Merci

David

2voto

Vladimir Botka Points 10170

Étant donné que mon_dict la pièce

  vars:
    my_dict:
      key1: { "key1a": ["key1aa": "value1aa", "key1ab": "value1ab"]}
      key2: { "key2a": ["key2aa": "value2aa", "key2ab": "value2ab"]}
  tasks:
    - set_fact:
        my_list: "{{ my_list|default([]) + [{item.key: item.value}] }}"
      loop: "{{ my_dict|dict2items }}"
    - debug:
        msg: "{{ my_list|to_json }}"

donne

msg: '[{"key2": {"key2a": [{"key2aa": "value2aa"}, {"key2ab": "value2ab"}]}},
       {"key1": {"key1a": [{"key1aa": "value1aa"}, {"key1ab": "value1ab"}]}}]'

La sortie a été imprimée avec yaml callback ( export ANSIBLE_STDOUT_CALLBACK=yaml ). Ensuite, la sortie a été divisée manuellement après le premier élément de la liste.


json_query

Il est également possible de créer la liste avec jmespath c'est-à-dire json_query . Par exemple, la tâche ci-dessous donne le même résultat

- set_fact:
    my_list: "{{ my_dict|
                 dict2items|
                 json_query('[].[{key: key, value: value}]')|
                 map('items2dict')|
                 list }}"

to_nice_yaml

Il est plus facile de voir la structure des données lorsqu'elles sont imprimées avec le filtre to_nice_yaml . Par exemple

- debug:
    msg: "{{ my_list|to_nice_yaml }}"

donne

  msg: |-
    -   key2:
            key2a:
            -   key2aa: value2aa
            -   key2ab: value2ab
    -   key1:
            key1a:
            -   key1aa: value1aa
            -   key1ab: value1ab

filtres_plugins

Il est également possible d'utiliser des Plugins de filtrage . Par exemple avec le plugin

$ cat filter_plugins/dict_utils.py

def dict2list(d):
    l = []
    for i in d:
        h = {i:d[i]}
        l.append(h)
    return l

class FilterModule(object):

    def filters(self):
        return {
            'dict2list': dict2list
        }

la tâche ci-dessous donne le même résultat

- set_fact:
    my_list: "{{ my_dict|dict2list }}"

Pour votre confort :

2voto

Zeitounator Points 2743

Ce n'est pas possible avec jmespath (i.e. json_query) seul à moins que vous ne soyez prêt à perdre la clé de niveau supérieur. Dans ce cas, vous pouvez simplement appliquer l'expression jmespath avec caractère de remplacement (c'est-à-dire * ) à votre objet.

Si vous ne voulez pas perdre les clés de premier niveau et que vous voulez toujours garder jmespath dans l'équation, l'exemple suivant répond à ces exigences mais nécessite quelques filtres supplémentaires.

Quelques détails sur le scénario :

  • Transformer le hachage initial en une liste de {key: XXX, value: YYY} avec des hachages dict2items
  • Utilisez json_query pour transformer cette liste de hashs (i.e. [{}, {}] ) en une liste de listes de hachages (c'est-à-dire [[{}], [{}]] )
  • Cartographier le items2dict filtre sur chaque élément de la liste de résultats
  • Enfin, le list filtre transformera l'objet temporaire de map à une liste utilisable.


    • name: Transform hash to list with jmespath and dict2items/items2dict hosts: localhost gather_facts: false

      vars: my_object: { "key1": { "key1a": ["key1aa": "value1aa", "key1ab": "value1ab"] }, "key2": { "key2a": ["key2aa": "value2aa", "key2ab": "value2ab"] } }

      tasks:

      • name: Do transform with json_query debug: msg: >- {{ my_object | dict2items | json_query('[].[{key: key, value: value}]') | map('items2dict') | list }}

Ce qui donne :

PLAY [Transform hash to list with jmespath and dict2items/items2dict] ***************************************************************************************************************************************************************************************************

TASK [Do transform with json_query] *************************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "key1": {
                "key1a": [
                    {
                        "key1aa": "value1aa"
                    },
                    {
                        "key1ab": "value1ab"
                    }
                ]
            }
        },
        {
            "key2": {
                "key2a": [
                    {
                        "key2aa": "value2aa"
                    },
                    {
                        "key2ab": "value2ab"
                    }
                ]
            }
        }
    ]
}

PLAY RECAP **************************************************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

1voto

oliv Points 7025

Notez que votre tableau dans les deux exemples n'est pas conforme à la syntaxe JSON (les éléments du tableau doivent se trouver dans un objet).

Donc, dans cet exemple :

cat file
{
  "key1": { "key1a": [{"key1aa": "value1aa"}, {"key1ab": "value1ab"}] },
  "key2": { "key2a": [{"key2aa": "value2aa"}, {"key2ab": "value2ab"}] }
}

Vous pouvez utiliser jq :

<file jq 'to_entries|map({(.key):.value})'

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X