Power AutomateでApply to eachを使ってJSONから必要な情報を取り出すループをつくる

Power Automateのアクションは多くが結果をJSON形式で返してきます。処理の中ではJSONのなかの特定の項目を抜き出してループを回したいというニーズがよく登場します。JSONは階層を持っていることが多いので、この記事では階層の中の特定の部分をApply to eachをつかって指定する練習をしてみます。

実行すると、「作成」のなかに、Excelのテーブルを一覧化したJSONに変換されていることがわかります。

[
    {
      "@odata.etag": "",
      "ItemInternalId": "79f139d5-cd56-4e1d-a938-27c717233df7",
      "名前": "竹本チエ",
      "年齢": "11"
    },
    {
      "@odata.etag": "",
      "ItemInternalId": "24611513-787b-45d1-8097-75731a9fd2b1",
      "名前": "竹本テツ",
      "年齢": "30"
    },
    {
      "@odata.etag": "",
      "ItemInternalId": "2b1b2b20-9ff4-4405-ab6b-fcd325ee6748",
      "名前": "竹本ヨシ江",
      "年齢": "30"
    },
    {
      "@odata.etag": "",
      "ItemInternalId": "13925dfe-e714-488f-8f70-f38598054d1e",
      "名前": "竹本菊",
      "年齢": "55"
    },
    {
      "@odata.etag": "",
      "ItemInternalId": "a827ce97-1aa7-4c59-ba47-40a47338aa66",
      "名前": "おじい",
      "年齢": "58"
    }
  ]

JSONの値の中で多階層やさらに配列になっていないような場合、Apply to eachの中では、項目が表示されるのでそのまま「動的なコンテンツ」から選べばOKです。「作成2」の中に「名前」を配置し、マウスカーソルを上に持って行ってみると「items('Apply_to_each’)?['名前’]」と表示されるのがわかります。この形がポイントです。items後ろのカッコの中身に書かれている’Apply_to_each’は、外側にあるループの名前です。

上記では「items」を使っていますが、「item()」のように書いた場合、今自分が回しているループ自身を指しますので、手書きする場合はこちらがおすすめです。※保存した後勝手にitemsに書き換わったりしますが気にせずに。items()の後には「?」をつけましょう。

つけなくても動くのですが若干挙動が変わります。?を付なかった場合にはJSONの中に指定したフィールドがなかった場合にエラーを発生させます。?をつけておくと、nullを返すためエラーは発生しません。

テスト実行してみると、JSONの「名前」の部分の値が1つずつ取得できているのがわかります。Excelで作成した竹本家の家族は5人なので、5回ループが回っています。

ということは、下記のように年齢だって取得できます。実行すると・・・

こうなります。

要素の値が配列になっている場合

先ほどのJSONは1名ごとの集まりでしたが、例えば家族単位で名前値が配列になっていた場合はどうでしょうか?

[
  { 
    "家族":"竹本家",
    "名前": ["竹本チエ","竹本テツ","竹本ヨシ江","竹本菊","おじい"]
  },
  { 
    "家族":"花井家",
    "名前": ["花井拳骨","花井渉","花井朝子"]
  }
]

ループの中で「名前」を指定して実行してみます。

結果は、値が配列なので配列として取得できました。

配列なので、たとえば配列の最初に出てくる人だけを取得するにはこんな風に書きます。

item()?['名前'][0]

配列の最初にいるチエちゃんだけが取得できました。ループの2回目には花井拳骨先生が表示されています。

配列をJOIN関数でつなぐ

家族をテキスト化したいならば、Join関数をつかうというのはいかがでしょう?

join(item()?['名前'],'さん、')

区切り文字に「さん、」だと最後の「おじい」にはつかなかったですねww

このJoin関数は配列からテキストへの変換にすごく便利です。たとえば配列でメールアドレスが用意されている場合には、「;」セミコロンでつないだ状態でOutlookアクションに渡してやることで同報メールを送ることができます。

配列の1要素がJSONの場合

こんどは、配列の1要素が1ユーザーの場合です。

  [
     { "name": "竹本チエ", "age": 11 },
     { "name": "竹本テツ", "age": 30 },
     { "name": "竹本ヨシ江", "age": 30 }
  ]

item() だけで取り出してみるとこうなります。配列が3つ(3人)なので、一人ずつ名前と年齢がセットで取り出されます。

ここから、さらに名前だけを取得したい場合には、以下のようにして取り出します。

item()?['name']

配列の要素の要素のJSONの値がさらに配列になっているケース

こんどは1家族が1つの要素で、名前と年齢がそれぞれ配列となっているケースについてです。まずは、item()だけで取得してみます。

  [
     { "name": ["竹本チエ","竹本テツ","竹本ヨシ江"], "age": [11,30,30] },
     { "name": ["花井拳骨","花井渉","花井朝子"], "age": [55,25,25] }
  ]

1家族分がJSONとしてそのまま取得できました。

さらに名前で絞ってみます。

item()?['name']

1家族の名前だけが配列として取得できました。

配列をつないで一続きのテキストにしたいならば、先ほどのJoin関数です。

join(item()?['name'],'、')

JSONと仲良くなろう!

JSONをループの中で扱うには、item()でどの部分が取れるか確認して、配列であれば[0]のように何番目かを選べばよいですし、さらにJSON形式でまとめられている場合には item()?['name’] のように掘ってけばOKです。

この投稿ではApply to eachを使ったのですが、実はこのループは非常に遅いのが欠点です。実はループを使わずに要素を抜き出す方法は他にもあって、可能ならばできるだけApply to eachを避けることで処理速度が上がります。以下のような他の投稿でも紹介していますのでぜひ参考にしてみてください。

順番にメールを送るなどの処理にはループは欠かせないので、使いどころを見極めながらPower AutomateでJSONと仲良くなりましょう!