1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ansible Tips: データ構造変換にはjinja2 for loopが使いやすい

Last updated at Posted at 2024-10-22

備忘

概要

以前の以下の記事の更新。

https://qiita.com/hiroyuki_onodera/items/8588c44c9886aa67cb96
Ansible Tips: データ構造変換にはjinja2 for loopとfrom_yamlフィルターの組み合わせが使いやすい

上ではfrom_yamlフィルターを使った2段階変換を行っていたが、YAMLを経由しないで直接変換する例を示す。

元のロジックの例 (YAML経由変換)

元の、一旦YAMLデータを作成し、構造化データに変換する例

  - debug:
      msg: "{{ target }}"
    vars:
      source_data:
      - - hoge1
        - - foo: FOO1
            bar: BAR1
          - foo: FOO2
            bar: BAR2
      - - hoge2
        - - foo: FOO3
            bar: BAR3
          - foo: FOO4
            bar: BAR4
            
      target_yml: |
        {% for i0 in source_data %}
        {{ i0[0] }}:
        {% for i1 in i0[1] %}
        - {{ (i1['foo'] + '/' + i1['bar']) | to_json(ensure_ascii=false, sort_keys=false) }}
        {% endfor %}
        {% endfor %}
        
      target: "{{ target_yml | from_yaml }}"

この例では、一旦YAMLデータのtarget_yamlを作成し、その後from_yamlで構造化データとして読み込み直しの2段階データ変換。
YAMLのブロックスタイルなども利用可能なので結構ユニークな使い方ができるが、反面、to_jsonにてデフォルトではキーが勝手にソートされるなど、それなりに癖がある。この例ではソートはされないが。

直接変換の例 (YAMLを経由しない)

以下のように書けばYAMLを経由せず、1段階で変換可能

  - debug:
      msg: "{{ target2 }}"
    vars:
      source_data:
      - - hoge1
        - - foo: FOO1
            bar: BAR1
          - foo: FOO2
            bar: BAR2
      - - hoge2
        - - foo: FOO3
            bar: BAR3
          - foo: FOO4
            bar: BAR4

      target2: |
        {% set ns = namespace(output={}, lst=[]) %}
        {% for i0 in source_data %}
          {%- set ns.lst = [] -%}
          {% for i1 in i0[1] %}
            {%- set ns.lst = ns.lst + [i1['foo'] + '/' + i1['bar']] -%}
          {% endfor %}
          {%- set ns.output = ns.output | combine({i0[0]: ns.lst}) -%}
        {% endfor %}
        {{ ns.output }}

考慮点

  • for loop内で更新した変数の値をloop外に持ち出すことで対応。jinja2におけるloop外への値の持ち出しはいくつか方法があるが、ここでは判り易いと思えるnamespaceを利用。
  • 変換箇所が不必要な改行やスペースなどを生み出さないように、適宜{%- -%}などで前後の改行空白を削除する。for loop内のそれぞれのsetの箇所において{%- -%}とすれば十分な様子。
  • データの追加はlistなら+などが、dictならcombineなどが利用可能。
  • 最後に変換後の値を{{ }}にて変数に設定。

namespace参考

https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-globals.namespace
https://qiita.com/masa2223/items/129012d5539a8724556d
https://qiita.com/waro_a2606/items/ae92dc26841a302ca95e

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?