Power Automate for desktopの変数に関するTips「JSONにnull値がある場合の選択的置換」

この記事はWeb API Advent Calendar 2021の4日目の記事です。
3日目は @makokeさんの[[音声認識] Webブラウザの音声認識APIを使う](https://mekiku.com/view.php?a=76)でした!

## 概要

Power Automate for desktopからWeb APIを利用するとき、「JSONをカスタムオブジェクに変換」アクションを使うことがあります。しかし、null値を含んだJSONをそのまま変換するとうまくカスタムオブジェクトとして扱えません。そこでnullを含むさまざまなJSONに対応できるようにする方法を紹介します。

```json:JSON
{
  "a": 1,
  "b": 2,
  "c": null
}
```

## 注意

* 2021年12月の記事です。
* Power Automate for desktopでしか役に立たないかもしれません。
* 100％の解決方法ではありません。
* すでに使いこなしているかた向けの記事ではありませんが、Web APIを利用したことがありJSONとカスタムオブジェクトに触れたことのあるかたを対象にしています。
* バージョンは執筆時点で2.14.217.21314です。
* 記事の内容はすべて試していますが公式の見解とは異なる可能性があります。
* コードはコピペで試すことができます。
* 誤りや、より良い方法がありましたらコメントでご指摘いただけると幸いです。

## null値のあるJSONをカスタムオブジェクト型にしてみる

**JSONはテキスト型のデータ形式**です。Power Automate for desktopでデータとして扱えるようにするには「JSONをカスタムオブジェクトに変換」アクションを使います。

1. 変数の設定
   ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/c9452e18-fa1b-a453-b4fa-4f8e1a4decbb.png)

  
2. JSONをカスタムオブジェクトに変換
   ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/b22c3e04-bba5-94c4-05ec-4dbf18784637.png)


動かしてみます。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/1f22918b-f327-7e7e-e200-bbeaadbc3993.png)


**見た感じは問題なく認識しているように見えます。**
しかし・・・・

変数の設定を使ってカスタムオブジェクト内のcの値を参照してみます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/4c9712a1-14b1-8aea-ba39-b73c6326633b.png)

エラーがでます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/4c604ca3-4eef-1b95-50dc-7bff3c9a4036.png)

Power Automate for desktopのカスタムオブジェクトではnullが上手く扱えないようです。
cの値が空になっているように見えますが、よく見ると何か出ています。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/d4f8d408-b8b9-03d4-a3e7-9d2ce28a04ba.png)

JsonAsCustomObject['c'].JsonAsCustomObject['c']が空というよくわからない状態です。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/47583309-b039-1ee3-d118-316a9d7079dd.png)

ここまでのコード

```r:PA4d
SET SampleJson1 TO $'''{
  \"a\": 1,
  \"b\": 2,
  \"c\": null
}'''
Variables.ConvertJsonToCustomObject Json: SampleJson1 CustomObject=> JsonAsCustomObject
SET NewVar TO JsonAsCustomObject['c']
```

## 解決策ぽいけど？

Power Automate for desktopにとってJSONは文字列です。そこでカスタムオブジェクトへ変換する前でnull値を空白文字に置き換えてしまえば良いわけです。

JSONでの空白文字はダブルクオーテーション2個で表現できます。
「テキストを置換する」アクションでnullを""に置換します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/19f8c9cd-464c-36e4-e324-abb1fb71199d.png)

置換した変数%Replaced%をカスタムオブジェクトに変換します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/3b00d7af-ff6e-c7f2-a6f6-ca596400240c.png)

実行してみます。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/f2e608ad-f1a2-b30d-7bac-2cd4969e3339.png)


値を参照してもエラーなく、カスタムオブジェクトになっているようです。

ここまでのコード

```r:PA4d
SET SampleJson1 TO $'''{
  \"a\": 1,
  \"b\": 2,
  \"c\": null
}'''
Text.Replace Text: SampleJson1 TextToFind: $'''null''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''\"\"''' ActivateEscapeSequences: False Result=> Replaced
Variables.ConvertJsonToCustomObject Json: Replaced CustomObject=> JsonAsCustomObject
SET NewVar TO JsonAsCustomObject['c']
```

## そんな置換で大丈夫か？

せっかくなのでWeb APIで試します。
[「JSONPlaceholder」](https://jsonplaceholder.typicode.com/)というフリーのテスト用APIを叩いてみます。
https://jsonplaceholder.typicode.com/

掲示板的な形式の擬似データにGETしてみます。
こういう自由に練習できるサービスはありがたいです！


https://jsonplaceholder.typicode.com/

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/5f129d33-6643-0184-6739-95a8819ca442.png)


このようなかたちでレスポンスが返ってきます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/4e6a65df-e772-1bcf-1b7e-235e1ede3757.png)

null値は無いようですが、これを先ほどの置換アクションを挟んでカスタムオブジェクトに変換してみます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/c31f85c9-68cc-4ab2-13ee-d9d27f4259e0.png)

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/eeb82018-4690-9713-ae7d-63dd5f92f08a.png)

コード

```r:PA4d
Web.InvokeWebService.InvokeWebService Url: $'''https://jsonplaceholder.typicode.com/posts''' Method: Web.Method.Get Accept: $'''application/json''' ContentType: $'''application/xml''' ConnectionTimeout: 30 FollowRedirection: True ClearCookies: False FailOnErrorStatus: False EncodeRequestBody: True UserAgent: $'''Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20100312 Firefox/3.6''' Encoding: Web.Encoding.AutoDetect AcceptUntrustedCertificates: False ResponseHeaders=> WebServiceResponseHeaders Response=> WebServiceResponse StatusCode=> StatusCode
Text.Replace Text: WebServiceResponse TextToFind: $'''null''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''\"\"''' ActivateEscapeSequences: False Result=> Replaced
Variables.ConvertJsonToCustomObject Json: Replaced CustomObject=> JsonAsCustomObject
```

おそらくこのような形でエラーが出ると思います。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/b7082666-17fa-e1d5-eadb-c56d0c726811.png)

Path '[1].body', line 12, position 218.がおかしいということなのでWebServiceResponseとReplacedを調べてみます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/998a731a-5365-27a9-6feb-410398003c96.png)

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/08b75689-c7b1-7ba9-f83d-6c217b6d11a8.png)

投稿文のnullaという単語の一部が置換されてしまいました。
**そこでnullが文字の場合を除き、値として「null」の場合だけを選択して置換する必要があります。**

## 選択的置換を考えてみる

一番よいの考えてみます。
JSONにさまざまなnullの出現パターンをつくり**null値のみ**置換が可能になるように正規表現をかんがえてみます。

```json:JSON
{
  "a":null,
  "b" : Null,
  "c" : null ,
  "Checknull": false,
  "name" : "janull nulla",
  "null_check":true,
  "test": "私はnull",
  "test1":"null",
  "test2":"今日は null ",
  "test3": null  
}
```


置換したいnull値の条件を考えます。

:::note
必ず先頭にコロン「：」があり、スペースなどの空白文字があったりなかったりした後方に存在します。
:::
:::note
スペースなどの空白文字またはカンマ「,」または波括弧「｝」の前方に存在します。
:::
:::note
スペースなどの空白文字は複数回繰り返される可能性があります。
:::

  
これらの条件を**同時に満たすnullのみ**を検索できるようにすればいけそうです。

肯定後読み```?<=```と肯定先読み```?=```を組み合わせて検索条件にしました。

```
(?<=:\s*)null(?=\s*|,|})
```

また大文字小文字を無視するように「テキストを置換する」アクションの設定をします。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/b96d64dd-04f1-b1f9-cac6-16fa3d6f6d76.png)

文字列としてのnullは無視し、null値のみ置換してカスタムオブジェクト型のデータとして扱えるようになりました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680039/e7b43f15-c8f3-2405-9e96-70d513cf5068.png)

[「JSONPlaceholder」](https://jsonplaceholder.typicode.com/)でもうまくいきます。
お試しください。

コード

```r:PA4d
SET SampleJson1 TO $'''{
  \"a\":null,
  \"b\" : Null,
  \"c\" : null ,
  \"Checknull\": false,
  \"name\" : \"janull nulla\",
  \"null_check\":true,
  \"test\": \"私はnull\",
  \"test1\":\"null\",
  \"test2\":\"今日は null \",
  \"test3\": null  
}'''
Text.Replace Text: SampleJson1 TextToFind: $'''(?<=:\\s*)null(?=\\s*|,|})''' IsRegEx: True IgnoreCase: True ReplaceWith: $'''\"\"''' ActivateEscapeSequences: False Result=> Replaced
Variables.ConvertJsonToCustomObject Json: Replaced CustomObject=> JsonAsCustomObject
Web.InvokeWebService.InvokeWebService Url: $'''https://jsonplaceholder.typicode.com/posts''' Method: Web.Method.Get Accept: $'''application/json''' ContentType: $'''application/xml''' ConnectionTimeout: 30 FollowRedirection: True ClearCookies: False FailOnErrorStatus: False EncodeRequestBody: True UserAgent: $'''Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20100312 Firefox/3.6''' Encoding: Web.Encoding.AutoDetect AcceptUntrustedCertificates: False ResponseHeaders=> WebServiceResponseHeaders Response=> WebServiceResponse StatusCode=> StatusCode
Text.Replace Text: WebServiceResponse TextToFind: $'''(?<=:\\s*)null(?=\\s*|,|})''' IsRegEx: True IgnoreCase: True ReplaceWith: $'''\"\"''' ActivateEscapeSequences: False Result=> Replaced2
Variables.ConvertJsonToCustomObject Json: Replaced2 CustomObject=> JsonAsCustomObject2
```

## まとめ

- Power Automate for desktopのカスタムオブジェクト型ではnull値の扱いが今のところ難しいようです。
- 暫定的ですが正規表現の肯定後読みと肯定先読みを組み合わせた置換でほとんどのパターンは処理することができました。
- しかし検索パターンに該当するnullがKEYや値に内包された場合は対応できません。( ﾉД`)ｼｸｼｸ…
- ノーコード、ローコードツールは手軽ですが、いろいろなケースでテストしたほうがよいと思います。
- Web APIから返ってくるJSONっていろいろだし💦