XMLアクティビティを利用してプロセス情報を抽出しよう：Part 1

## はじめに

こんな形のコードを見たことがありませんか？

```ruby:xmlコード
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book>
        <title>Learning UiPath for RPA</title>
        <author>John Doe</author>
        <year>2024</year>
        <price>49.99</price>
    </book>
    <book>
        <title>UiPath Studio Essentials</title>
        <author>Jane Smith</author>
        <year>2023</year>
        <price>59.99</price>
    </book>
    <book>
        <title>Mastering UiPath Automation</title>
        <author>Michael Brown</author>
        <year>2022</year>
        <price>69.99</price>
    </book>
</bookstore>
```

上記のコードはXML言語で記述されたものです。私たちRPA開発者が日々開発しているワークフローは、一見GUIで表現されているように見えますが、実際にはXML形式で記述されています。確認してみましょう！

簡単にメッセージボックスが入るワークフローを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/a3604472-3865-e349-2946-76be9fdf75d4.png)


Notepad++でこのワークフローを開いてみたら、こうなりますね。

```ruby:xmlコード
<Activity mc:Ignorable="sap sap2010" x:Class="Main" VisualBasic.Settings="{x:Null}" sap2010:WorkflowViewState.IdRef="ActivityBuilder_1" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sap="http://schemas.microsoft.com/netfx/2009/xaml/activities/presentation" xmlns:sap2010="http://schemas.microsoft.com/netfx/2010/xaml/activities/presentation" xmlns:scg="clr-namespace:System.Collections.Generic;assembly=System.Private.CoreLib" xmlns:sco="clr-namespace:System.Collections.ObjectModel;assembly=System.Private.CoreLib" xmlns:ui="http://schemas.uipath.com/workflow/activities" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <TextExpression.NamespacesForImplementation>
    <sco:Collection x:TypeArguments="x:String">
      <x:String>System.Activities</x:String>
      <x:String>System.Activities.Statements</x:String>
      <!-- 長いので省略 -->
    </sco:Collection>
  </TextExpression.NamespacesForImplementation>
  <TextExpression.ReferencesForImplementation>
    <sco:Collection x:TypeArguments="AssemblyReference">
      <AssemblyReference>Microsoft.VisualBasic</AssemblyReference>
      <AssemblyReference>mscorlib</AssemblyReference>
      <!-- 長いので省略 -->
    </sco:Collection>
  </TextExpression.ReferencesForImplementation>
  <Sequence DisplayName="Main Sequence" sap:VirtualizedContainerService.HintSize="1120,906.04" sap2010:WorkflowViewState.IdRef="Sequence_1">
    <sap:WorkflowViewStateService.ViewState>
      <scg:Dictionary x:TypeArguments="x:String, x:Object">
        <x:Boolean x:Key="IsExpanded">True</x:Boolean>
      </scg:Dictionary>
    </sap:WorkflowViewStateService.ViewState>
    <ui:MessageBox Caption="{x:Null}" ChosenButton="{x:Null}" AutoCloseAfter="00:00:00" DisplayName="メッセージ ボックス" sap:VirtualizedContainerService.HintSize="416,108" sap2010:WorkflowViewState.IdRef="MessageBox_1" Text="[&quot;Hello, UiPath developer!&quot;]" />
  </Sequence>
</Activity>
```

「うわ、なんだこれ。長くて読みにくい！」きっとそう思うでしょう。しかし、このXML言語を読み取れれば、いちいちプロセスを開かなくても、ワークフローの比較、情報抽出や編集など、たくさんのことが簡単に実現できます。それでは、XMLの世界に入りましょう。

## XML言語とは

XML（エックスエムエル）とは、拡張可能マークアップ言語の略で、データを構造的に表現するためのテキストベースのフォーマットです。主に、異なるシステムやアプリケーション間でデータを交換したり保存したりするために使用されます。

HTML言語に詳しい方は、上記のコードを見て親しみを感じたかもしれません。確かに、この二つの言語は似たような構造を持っています。ただし、いくつか違いがあります。

まず、使用の目的が異なります。XMLは、データを保存、交換するためのコードであり、主にデータの記述と構造に焦点を当てており、データの表示は目的ではありません。それに対して、HTMLは、Webページの内容を定義したものであり、ブラウザの情報を表示します。たとえば、拡張子が「.html」のファイルを作成して、以下のコードを記述して保存します。

```ruby:HTMLコード
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>UiPath</title>
</head>
<body>
    <button>UiPath</button>
</body>
</html>
```
その後、HTMLファイルを開いたら、「UiPath」のボタンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/8ed43987-1401-e1c1-aaa0-0c54038a7174.png)

それに対して、XMLは何も表示されません。

次に、XMLは厳密な文法規則があり、すべてのタグを閉じる必要があり、拡張性が高いです。以下にXMLコードの例を示します。

```ruby:XMLコード
<bookstore>
    <book>
        <title>Learning UiPath for RPA</title>
        <author>John Doe</author>
        <year>2024</year>
        <price>49.99</price>
    </book>
</bookstore>
```

`<bookstore> </bookstore> <title> </title>`のように、記述内容は必ず開始タグと終了タグの間に入っています。HTMLは、文法が緩やかです。必ずしもタグを閉じる必要がない（例: `<img>`は終了タグが不要）し、タグの大文字と小文字も区別しません。

## XMLの構造
以下の図は、XMLの構造を表しています。

```ruby:XMLの構造
+----------------------------------------------------------+
|                        XML Document                      |
+----------------------------------------------------------+
|                          Prolog                          |
|                 <?xml version="1.0" encoding="UTF-8"?>   |
+----------------------------------------------------------+
|                        Root Element                      |
|                         <bookstore>                      |
|                 +-------------------------+              |
|                 |      Child Element       |             |
|                 |         <book>           |             |
|                 |   +-------------------+  |             |
|                 |   | <author>John</author>|             |
|                 |   +-------------------+  |             |
|                 +-------------------------+              |
|                 +-------------------------+              |
|                 |      Child Element       |             |
|                 |         <book>           |             |
|                 |   +-------------------+  |             |
|                 |   | <author>Jane</author>|             |
|                 |   +-------------------+  |             |
|                 +-------------------------+              |
+----------------------------------------------------------+
```

簡単に言うと、XMLはプロローグ（Prolog）と要素（Root Element）という２つのパーツからなります。

PrologはXMLの最初に書かれる部分で、XMLのバージョンや文字エンコーディング（文字コード）などを指定します。

```ruby:Prolog
<?xml version="1.0" encoding="UTF-8"?>
```

Root ElementはXMLの「最上位」に位置する要素で、全てのデータを包含する役割を持ちます。XMLは必ず一つのRoot Elementを持つ必要があります。

```ruby:Root Element
<bookstore>
    <!-- Child Elementがここに入る -->
</bookstore>
```

Root Elementの中に、Child Elementが入り、データを具体的に表します。

```ruby:Root Element & Child Element
<bookstore>
    <book>
        <title>Learning UiPath for RPA</title>
        <author>John Doe</author>
        <year>2024</year>
        <price>49.99</price>
    </book>
</bookstore>
```

続いて、Elementの内部構造を解読します。

要素は主に、開始タグ、名前空間、属性、テキスト、終了タグという5つのパーツからなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/dc9b7f37-5e81-8216-5d4d-8acc5fb80ac9.png)

①開始タグ: タグが始まる部分で、要素の開始を示します。例：`<book>`

②命名空間: XMLドキュメント内で名前の衝突を避けるための仕組みです。複数の異なるXML文書が同じ名前のタグや属性を使う場合、その名前が衝突しないように、各要素に一意の識別子を付けることができます。名前空間は通常、xmlns 属性を使って定義されます。この属性により、タグ名がどの名前空間に属しているかを指定します。例：`xmlns="http://www.example.com/book"`

③属性: タグ内に指定される追加情報です。属性は開始タグの中で、name="value" の形式で記述します。例：`genre="education"`

④テキスト: タグで囲まれたデータの部分です。要素の中に格納される情報や値を指します。例：`Learning UiPath for RPA`

⑤終了タグ: 開始タグに対応し、要素の終わりを示します。開始タグと同じ形式ですが、先頭にスラッシュ「/」が追加されます。例：`</book>`

（以上の部分的な内容は「XML Introduction」(英語動画、作成者：Act Automate)を参考にして筆者が修正・補足したものです。）

## UiPath StudioでXMLを操作する

UiPathは、XML操作用のアクティビティパッケージを提供しています。パッケージを管理で、UiPath.WebAPI.Activitiesをインストールしたら、XMLファイルに対する操作ができるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/cbc54220-bc19-32b2-7607-258d8cae07e5.png)

UiPathはXMLを操作するためのたくさんのデータタイプを提供していますが、上記の構造に基づき、よく使用されるタイプは以下の通りです。

①XDocument（System.Xml.Linq.Xdocument）
②XElement （System.Xml.Linq.Element）
③XAttribute（System.Xml.Linq.XAttribute）
④XText     （System.Xml.Linq.Xdocument）
⑤XNamespace（System.Xml.Linq.XNamespace）

変数を作成する際に、「Browse of type」から、System.Xml.Linqをキーワードにして検索してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/c1f3c760-77e7-b0d7-b0a4-d374edfc2b4c.png)

## ワークフローを作成

Xamlファイルの構造は複雑なので、次回詳しく説明しようと思います。今回はとりあえず簡単なXMLファイルを使って中身の情報を抽出してみましょう。

①ファイル準備

メモ帳を開いて、以下のXML文を貼り付けます。その後、「UiPathTestXml.txt」という名前を付けて保存します。名前空間のあるXMLを解読するのはややこしいので、今回は名前空間のないXML文を用意しました。

```ruby:XML文
<?xml version="1.0" encoding="UTF-8"?>
<bookstore genre="education">
    <book>
        <title>Learning UiPath for RPA</title>
        <author>John Doe</author>
        <year>2024</year>
        <price>49.99</price>
    </book>
    <book>
        <title>UiPath Studio Essentials</title>
        <author>Jane Smith</author>
        <year>2023</year>
        <price>59.99</price>
    </book>
    <book>
        <title>Mastering UiPath Automation</title>
        <author>Michael Brown</author>
        <year>2022</year>
        <price>69.99</price>
    </book>
</bookstore>
```

②StudioのRead Text Fileで上記のファイルを読み込みます。変数stTextを作成してテキストを格納します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/f2fcaa1a-1acc-5386-4b50-ef7581b852ea.png)

③XMLを逆シリアル化を配置して、stTextをXMLの形に整形します。XDocument型の変数xmlFileを作って構造化されたデータを保存。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/f3ce867b-591c-be1a-4589-3c516a851283.png)

④メッセージボックスを配置して、XMLの構造を確認しましょう。

```ruby:ルート構造
xmlFile.Root
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/c5f10776-e894-3f0e-bde7-7fe993dec14a.png)

⑤Root ElementのAttributeを取り出す

ワークフローの全体図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/37a75951-8925-d4ae-cb9b-67269d2c1fda.png)


Root ElementのAttributeの数がわからないので、Attributeを取る際に、Attributesのメソッドを使います。まず、xAttributesという変数を作成して、変数の型を`IEnumerable<xAttribute>`にします。Assignで以下の構文を書きます。

```ruby:Assign構文
xAttributes = xmlFile.Root.Attributes
```
次に、xAttributesをループします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/6a0fa33a-d06a-15b7-c349-50ab54adee77.png)

結果を確認しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/9da9ec47-64c5-4450-2ac3-ac0cceca00c5.png)

⑤Child Elementの情報を抽出する

Root Elementの下にChild Elementがあります。さらに、Child Elementにも孫Elementがありますね。階層が深くなるとElementを探し出すのが面倒ですが、ここで、Elementのタグが分かれば一発でその値を取得できるDescendantsメソッドを紹介します

Descendants メソッドは、System.Xml.Linq名前空間の一部で、XML文書または要素内のすべての子孫要素を取得するためのメソッドです。このメソッドは、指定した要素とそのすべての子孫要素を再帰的に探索し、結果として`IEnumerable<XElement>`型で返します。

今回はすべての本及びその値段の情報を取得しましょう。

ワークフローの全体図

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/8188c5be-890f-a042-eb96-6afc93c423d1.png)

まず、`<book>`というChild Elementの情報を取得します。

```ruby:Assign構文
xElements = xmlFile.Descendants.Elements("book")
```

xElementsがIEnumerable`<XElement>`なので、ループしてその中の孫要素を抽出し、Element("孫要素").Valueのメソッドで書名と値段情報を取得します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/3a9bfad6-375c-8a9b-1b07-394b1027bd56.png)

```ruby:ログメッセージ構文
"The book name is <" & currentXElement.Element("title").Value & "> and it's price is $" & currentXElement.Element("price").Value
```

実行結果は以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334103/448b71cc-6f4b-c039-fbf3-e0c7d448118a.png)

## 終わりに

今回はXMLの定義及びUiPath StudioにおけるXMLの操作方法をご紹介しました。Studioのワークフロー（xmalファイル）のXML構造は、名前空間といった制限が絡んでいるため、非常に複雑です。そこから情報をうまく抽出できるように、xmalファイルのXML構造をよく把握してXML操作言語を使いこなす必要があります。次回は、その話題について詳しく話しましょう！