はじめに
前回は、XMLの概念及びUiPath StudioにおけるXMLの操作方法についてご紹介しました。実際に、RPA開発者が日々触っているワークフロー(xmalファイルとして保存)もXML言語で記述されています。XML言語を使いこなせば、ワークフローを開かなくても、プロセスの編集と情報抽出が可能になります。特に、たくさんのプロセスに対して、一括で情報抽出の際に、この方法は非常に効率的なので、本記事は、Part 1の内容を土台にしてXMLによるxamlファイル情報抽出の方法について紹介しようと思います。まだPart1がご覧になっていない方はぜひ目を通していただければ幸いです。
環境準備
項目 | バージョン |
---|---|
UiPath Studio | 2024.10.6 |
UiPath.WebAPI.Activities | 1.21.1 |
対応OS | Windows |
XMLで記述されるxamlの構造
簡単なワークフローを作成してxmalファイルの実態を確認してみましょう。以下の手順に従って作成します。
①xmlReaderという名前を付けてプロジェクトを作成します。
②sampleという名前を付けて新しいシーケンスを作成します。
③メッセージボックスを配置して、"Hello World!"のテキストを記述します。
④シーケンスを保存して、プロジェクトフォルダでsample.xmalをNotepad++で開きます。
すると、以下のXML文章が表示されます。長いため、同じタグの一部のChild Elementを削除しました。
<Activity mc:Ignorable="sap sap2010" x:Class="sample"
VisualBasic.Settings="{x:Null}"
sap2010:WorkflowViewState.IdRef="sample_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="sample" sap:VirtualizedContainerService.HintSize="1120,786.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_2" Text="["Hello World"]" />
</Sequence>
</Activity>
読みにくいですね。もっと中身を簡略化して構造だけを残すと、このようになります。前回の復習ですね。
<Activity(ルート要素) x:Class="sample"(属性)
xmlns:ui="http://schemas.uipath.com/workflow/activities"(名前空間)>
<TextExpression.NamespacesForImplementation(子要素)>
<sco:Collection(孫要素) x:TypeArguments="x:String"(孫要素の属性)>
<x:String(曾孫要素)>System.Activities(曾孫要素のテキスト)</x:String>
</sco:Collection>
</TextExpression.NamespacesForImplementation>
<Sequence(子要素) DisplayName="sample"(子要素の属性)>
<ui:MessageBox(孫要素) Caption="{x:Null}" ChosenButton="{x:Null}" AutoCloseAfter="00:00:00"
DisplayName="メッセージ ボックス" sap:VirtualizedContainerService.HintSize="416,108"
sap2010:WorkflowViewState.IdRef="MessageBox_2" Text="["Hello World"]"(孫要素の属性)/>
</Sequence>
</Activity>
たくさんの情報が入っていますが、今回の抽出作業に関する項目だけ、ご理解いただければと思います。
①<Activity>
タグ:UiPathワークフローのルート要素であり、ワークフロー全体を囲んでいます。属性には、ワークフローの名前空間や、Visual Basic設定、ワークフローのIDなどが含まれます。
②xmlns:ui="http://schemas.uipath.com/workflow/activities"
:UiPathのワークフローアクティビティを識別する名前空間です。ui プレフィックスを使って、UiPathのUI操作に関連するアクティビティ(例:メッセージボックス、ダイアログ、フォーム、UI操作など)を参照します。
③<TextExpression.NamespacesForImplementation>
タグ:ワークフロー内で使用する名前空間のリストを定義します。ここには、System.ActivitiesやUiPathのアクティビティや基本的な.NET名前空間が多数含まれています。
④<Sequence>
タグ:UiPathのシーケンスアクティビティを表します。シーケンスアクティビティは、順番に実行されるアクティビティの集合です。DisplayName="sample"
で、シーケンスの名前が指定されています。
⑤<ui:MessageBox>
タグ:UiPathの「メッセージボックス」アクティビティを定義します。中のText="["Hello World"]"
は、メッセージボックスに表示するテキスト"Hello World"
を指定しています。
ワークフローの実装
今回の目標は、UiPathフォルダ(C:\Users\UserID\Documents\UiPath)配下における、すべてのプロセスの中のOpenBrowserで記録されているウェブサイトのURLを抽出しようと思います。以下はイメージです。
ワークフローが少し長いため、まず完成図を頭に入れて、ステップバイステップで作成していきましょう。
では、始めましょう。
①プロセスとそのURLを記録するために、「データテーブルを構築」を使います。ProcessNameとURLという2つの列を構築してdtUrlInfoとして保存します。
②UiPathフォルダ配下のプロジェクトフォルダの情報を取得します。
上図の赤枠の情報を取得するために、System.IO.DirectoryクラスのGetDirectoriesメソッドを利用します。
Dim fileDirectories() As String
fileDirectories = System.io.Directory.GetDirectories("C:\Users\UserID\Documents\UiPath")
次に、各フォルダ内のxmalファイルを探しだすために、「繰り返し(コレクションの各要素)」を使います。
For Each dire In fileDirectories
Body
Next
完成図は以下の通りです。
③Bodyを展開します。
まず、各プロセスの名前を取得します。Studioでプロセスを作成したら、UiPath配下でプロジェクトフォルダが作成され、そのプロジェクトフォルダの名前はプロセスの名前になります。
Dim fileName As String
fileName = System.IO.Path.GetFileName(dire)
次に、取得したプロジェクトフォルダの配下のxmalファイルを探し出します。一つのプロジェクトフォルダには複数のxmalが存在可能なので、配列の変数xamlFilesを作成して情報を保存します。
Dim xamlFiles() As String
xmlFiles = System.IO.Directory.GetFiles(dire,"*.xaml")
さらに、xmalファイルをループし、URLの取得を準備します。
For Each xamlFile in xamlFiles
Body
Next
④Body2を展開します。いよいよXML操作が始まりますね!
i.「テキストファイルを読み込み」でxamlFileをstXamlとして出力します。
ii.「XMLを逆シリアル化」でstXamlをXDocumentに変換します。
iii.名前空間の取得
名前空間は、XML文書内で同じ要素(もしくは、同じ種類の要素)や属性が重複しないように区別するための仕組みです。XMLでは、同じ要素(もしくは、同じ種類の要素)が異なる名前空間に属していることがよくあります。そのため、名前空間を管理することが非常に重要です。通常、名前空間はxmlns属性を使って定義され、XMLタグで指定されたプレフィックス(例えばui
やsap
)が、実際にどの名前空間に属するかを示します。イメージとして、名前空間は要素の住所のように、その要素の取得の前提となります。
さきほど説明した通り、ui
というプレフィックスは、UiPathのアクティビティに関連する名前空間を指します。「OpenBrowser」もこの名前空間を利用しているため、XMLで「OpenBrowser」の情報を抽出するために、ui
プレフィックスの指定が前提となります。
<ui:OpenBrowser AutomaticallyDownloadWebDriver="{x:Null}" BrowserType="{x:Null}" CommunicationMethod="{x:Null}" Hidden="{x:Null}" NewSession="{x:Null}" Private="{x:Null}" UiBrowser="{x:Null}" DisplayName="ブラウザーを開く" sap:VirtualizedContainerService.HintSize="467,237" sap2010:WorkflowViewState.IdRef="OpenBrowser_1" Url="https://www.apple.com/jp/">
<ui:OpenBrowser.Body>
<ActivityAction x:TypeArguments="x:Object">
<ActivityAction.Argument>
<DelegateInArgument x:TypeArguments="x:Object" Name="ContextTarget" />
</ActivityAction.Argument>
<Sequence DisplayName="実行" sap:VirtualizedContainerService.HintSize="416,89" sap2010:WorkflowViewState.IdRef="Sequence_2">
<sap:WorkflowViewStateService.ViewState>
<scg:Dictionary x:TypeArguments="x:String, x:Object">
<x:Boolean x:Key="IsExpanded">True</x:Boolean>
</scg:Dictionary>
</sap:WorkflowViewStateService.ViewState>
</Sequence>
</ActivityAction>
</ui:OpenBrowser.Body>
上記をご理解いただいた上で、以下のコードを使って名前空間を取得します。
Dim uiNameSpace As System.Xml.Linq.XNameSpace
uiNameSpace = xDocument.Root.GetNamespaceOfPrefix("ui")
iv.条件分岐を配置します
まず、xmalファイルにより、ui
の名前空間が必ずしも存在するわけではありません。そのため、ui
の名前空間が存在しない場合、現在の繰り返しをスキップして、次のxmalにいかないとエラーになるので、「Else」のところに「繰り返しをスキップ」を配置します。
次に、ui
の名前空間が存在する場合の処理は、「Then」の中で書きます。
v.「Then」を展開してコードを書きます
まず、ui
の名前空間に所属するOpenBrowserの要素を取り出します。Descendantsのメソッドを使いますので、まだわからない方はPart 1をご参照ください。
Dim elems As IEnumerable(Of XElement) = xDocument.Descendants(uiNameSpace+"OpenBrowser")
次に、一つのxamlファイルに複数のOpenBrowserが存在する場合、複数のOpenBrowser要素が返ってくるので、elemsをループして個々のOpenBrowserのURLを取得する必要があります。
For Each currentXElement In elems
Body3
Next
vi.Body3を展開してURLを取得します
URLはOpenBrowser要素のどこで書いてあるのかを確認しましょう。
<ui:OpenBrowser
AutomaticallyDownloadWebDriver="{x:Null}"
BrowserType="{x:Null}"
CommunicationMethod="{x:Null}"
Hidden="{x:Null}"
NewSession="{x:Null}"
Private="{x:Null}"
UiBrowser="{x:Null}"
DisplayName="ブラウザーを開く"
sap:VirtualizedContainerService.HintSize="467,237"
sap2010:WorkflowViewState.IdRef="OpenBrowser_1"
Url="https://www.apple.com/jp/">
長いですが、<ui:OpenBrowser>
に入っているので、Urlは<ui:OpenBrowser>
の属
性ですね!そうしたら、Attributeのメソッドを使ってUrlを抽出してみましょう。
Dim Url As String
Url = currentXElement.Attribute("Url").Value.ToString
抽出した後、xmal名と共にdtUrlInfoに行として追加します。
最後はdtUrlInfoを出力して結果を確認します。
終わりに
今回はxmalファイルをXDocumentに変換して中身の情報を抽出する方法をご紹介しました。活用シーンとしては、例えば、稼働中の数千本のプロセスから特定のURLに紐づくシステムの利用状況を洗い出すことが挙げられます。いちいちワークフローを開いて確認する必要はなく、わずか数秒で情報が入手できるため、ぜひ試してみてくださいね!