【UiPath】定義した変数を一覧化する

# はじめに
この投稿では、UiPathで定義した変数をExcelに一覧出力する方法について説明します。
また、この投稿は、RPAコミュニティ(#RPALT)のアドベントカレンダー2021の12月9日分の記事となっています。ちなみに、公開日となる12/9はわたしのxx回目の誕生日だったりします(笑)

https://adventar.org/calendars/6396

# いきなり結論！！
今回作成したロボから出力される変数一覧はこんな感じになります。
この結果をご覧いただき、これっていいかも！と思ったら、この先読み進めて頂ければよいかと思います。
![結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/1ca1492d-da29-1fb4-84ca-4674f60c8bab.png)

# 使用環境について
この記事で使っている環境は以下の通りです（すべてCommunityライセンス)。

+ UiPath Studio 2021.10.0

## 使用パッケージ
依存関係に含まれるパッケージとそのバージョンは以下の通りです。

+ UiPath.System.Activities v21.10.2
+ UiPath.Excel.Activities v21.11.4

# 全体像
作成したロボの全体像です。
![全体.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/30d13ee5-2c10-e3a5-ae7d-2789d7e7f79c.png)
それぞれの処理を簡単に説明すると、こんな感じです。
**「ファイルの選択(ユーザ作業)」**では、変数を読み込むxamlファイルの選択を行っています。
**「xamlファイルの読込」**では、xamlファイルを読み込み、改行コードで分割しています。
**「変数一覧Excelの出力」**では、抽出した変数情報をExcelに出力しています。

**「変数情報の抽出」**については、このあと詳細に説明します。

# xamlファイルについて
xamlファイルの中身、見たことありますか？
実はxamlファイルはテキストエディタで開いて、中身を確認することができます。

```xml:xamlファイルの中身(抜粋)
・・・(略)
  <Flowchart DisplayName="メイン" sap:VirtualizedContainerService.HintSize="664,906" sap2010:WorkflowViewState.IdRef="Flowchart_1">
    <Flowchart.Variables>
      <Variable x:TypeArguments="s:String[]" Name="データ配列" />
      <Variable x:TypeArguments="sd:DataTable" Name="変数一覧DT" />
      <Variable x:TypeArguments="x:String" Name="スコープ" />
      <Variable x:TypeArguments="x:String" Name="ファイルパス" />
    </Flowchart.Variables>
・・・(略)
      <Sequence sap2010:Annotation.AnnotationText="xamlファイルから全行読み込み、行ごとに分割する。&#xA;&#xA;IN:String ファイルパス&#xA;OUT:String[] データ配列" DisplayName="xamlファイルの読込" sap:VirtualizedContainerService.HintSize="200,153" sap2010:WorkflowViewState.IdRef="Sequence_14">
        <Sequence.Variables>
          <Variable x:TypeArguments="x:String" Name="ファイル内容" />
        </Sequence.Variables>
・・・(略)
```

先に示した結果Excelのイメージとxamlファイルの中身(抜粋)を見比べてみてください。
既に今回出力しようとしている変数情報の全てが書かれていることが分かると思います。
あとは、これを実装するだけです。

# 変数情報の抽出
今回の変数一覧では、変数名、型、スコープの2つの情報を取り出すこととしています。
他の情報を取り出す際も似たようなやり方で取り出すことができるかと思います。

## 変数名と型の抽出
Variableタグの行に変数情報が書かれています。
`x:TypeArguments`の値が**型**、`Name`の値が**変数名**となります。

Variableタグの行かどうかを判定するには、以下の正規表現を使います。

```
<Variable(?!.Default)
```

変数に規定値が設定されている場合、以下のように`<Variable.Default>`という行が出てくるので、それを読み飛ばすために否定先読み`(?!.Default)`を入れています。

```xml
  <Flowchart DisplayName="メイン" sap:VirtualizedContainerService.HintSize="664,906" sap2010:WorkflowViewState.IdRef="Flowchart_1">
    <Flowchart.Variables>
      <Variable x:TypeArguments="s:String[]" Name="データ配列" />
      <Variable x:TypeArguments="sd:DataTable" Name="変数一覧DT" />
      <Variable x:TypeArguments="x:String" Name="スコープ" />
      <Variable x:TypeArguments="x:String" Name="ファイルパス">
        <Variable.Default>
          <Literal x:TypeArguments="x:String">xxx</Literal>
        </Variable.Default>
      </Variable>
    </Flowchart.Variables>
```

上記の正規表現に一致した行から、型を取り出すには、以下の正規表現を使います。

```text
(?<=x:TypeArguments=")[^"]+(?=")
```

これで、`x:TypeArguments="ここ"`の「ここ」を取り出しています。

次に変数名を取り出すには、以下の正規表現を使います。

```text
(?<=Name=")[^"]+(?=")
```

これで、Name="変数名"の「変数名」を取り出しています。

## スコープの抽出
UiPathで変数のスコープにできるアクティビティはそれほど多くありません(たぶん)。
代表的なものだと、「フローチャート」や「シーケンス」といったものが挙げられます。
他にも「トライキャッチ」や「並列」などもスコープに指定することができます。

執筆中に、ステートマシンやステートもスコープの対象となり得ることに気づきましたが、
`|StateMachine|State`を足してもらえればいいだけですので、このまま進めます。

まずは、スコープを抽出する対象となる行かどうかを判定します。
ここもやっぱり正規表現の登場です。以下のような正規表現を使っています。

```text
<(Flowchart|Sequence|TryCatch|Parallel)(?!.(Variables|StartNode))
```

`(Flowchart|Sequence|TryCatch|Parallel)`はそれぞれのアクティビティを表しています。
`(?!.(Variables|StartNode))`は先ほども出てきた否定先読みです。これで、変数の定義の始まりを表す行`<Flowchart.Variables>`やフローチャートの開始の接続先を表す行`<Flowchart.StartNode>`を無視しています。

上記の正規表現に一致した行から、スコープを取り出すには、以下の正規表現を使います。

```
"(?<=DisplayName=")[^"]*(?=")"
```

これで、`DisplayName="ここ"`の「ここ」を取り出しています。

型・変数名を取り出す行とスコープを取り出す行は別の行ですが、必ずスコープ行の後に型・変数の行が来るという構造になっていますので、
行を上から順に処理していき、
1. スコープ行がきたら、スコープを記憶。
2. 変数行がきたら、型・変数名＋記憶したスコープを変数情報として書き出す。
という流れで、型・変数名とスコープの関連付けができます。

# 完成！
ここまで説明してきたものを、ごにょごにょと組み合わせれば、簡単に作成できると思います。
そして、最初に挙げた結果のExcelは、この変数一覧出力本体のxamlについて実際に出力したものでした。
本来、xamlを分割して作成したい所を1つのxamlで作成している理由もそれが理由だったりします。

# バグ？
今回、作成している中で、バグ？と思われる事象があったのでご紹介しておきます。
![条件分岐.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218396/588df794-4724-8d8e-a1ff-119ac534a5a2.png)
条件分岐アクティビティをドラッグ&ドロップすると、
ThenとElseにデフォルトでSequenceという名前でシーケンスが作成されます。

シーケンスの定義には、下記のように、表示名(displayName)属性が存在します。

```xml
<Sequence displayName="メイン" …>
```
しかし、ThenとElseにデフォルトで作成されているSequenceという名のシーケンスには、表示名(displayName)属性が存在しません。

```xml
<Sequence sap:VirtualizedContainerService.HintSize="242,83" …>
```
そして、手で表示名を書き換えると、displayName属性がでてきます。

ま、表示名をそのままにしておくのは、[ワークフローアナライザーでも警告となる](https://docs.uipath.com/studio/lang-ja/docs/st-mrd-002)ので、ちゃんと表示名を変えてくださいってことですね。

# 課題
今後、以下のような点を改善し、変数一覧出力をバージョンアップしていこうと思います。

+ 型の出力をStringやIEnumerable<Match>みたいに簡潔にする。
+ 既定値が設定されている場合、規定値も出力されるようにする。
+ プロジェクト配下のxamlファイルの引数一覧を一気に出力できるようにする。
+ スコープの階層が分かるように出力できるようにする。

# まとめ
今回はUiPathのロボを開発している際に、個人的に「あったらいいな」って思っていたものを作ってみました。

xamlファイルの中身は一見複雑に見えますが、意外とシンプルな形をしています。
取り出したい情報に着目して、ルールを見つけて、是非挑戦してみてください。

ただし、xamlファイルへの書き込みは、ぶっ壊れる可能性があるので、やめた方がよろしいかと思います。