🥭
Power Automate Desktop で XML ファイルの編集
XML アクション
PAD で XML ファイルを読み取って要素を挿入してみようと思います。
使い方
- ファイルから読み取った値に
- 「XML 要素を挿入します」アクションで挿入すると
- 上手い具合に追加されます。
テキストアクションでごちゃごちゃやるより簡単で良いですね。
フローで使ってみる
ついでになにか作ってみようと思います。
ちょうど良い具合に思いついたものがあったのでそれで使います。
いままで手作業で行っていた準備を自動化します。
作業内容はシンプル。
- 手順
- 格納先のフォルダーを作成
- 定義ファイルに追加
これだけ。簡単。
作業頻度は四半期ごとに 1 回とそんなんでもないのですが、
何十回もコピペするのが面倒……。と言いつつ 11 年くらい続けていました…………。
一応、定義にないファイルを放り込んだら fss ファイルが出てきて、そこに変更を加えると定義ファイルも更新されるのですが、何だかんだで最初にまとめて定義を作っちゃうので活用はしてなかったりします。
定義ファイルは XML で書いていて、以下のようなフォーマットになっています。
定義ファイル
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Strategies>
<Strategy name="">
<Regex></Regex>
<DestDir></DestDir>
</Strategy>
</Strategies>
★ ~ ★ を編集。
<Strategy name="★~★">
<Regex>★~★</Regex>
<DestDir>★~★</DestDir>
</Strategy>
実行
- すっごい塗りつぶしていて分かりづらいのですが、こういうファイルからタイトル列をまとめてコピー
- PAD の入力フォームにペースト →OK
- おしまい
↓
複数行のテキストをまとめて貼り付けるだけ。
あとは PAD が良い感じにやってくれます。
楽になったのでは? 次は 10 月実施……。
フロー
おおまかな部分は以前作ったフローとだいたい一緒。
Main
FUNCTION Main_copy GLOBAL
**REGION 読み込み
CALL Now
SET Log TO $'''%CurrentDateTime% INFO Master setting process.'''
# Configファイルのパスを環境に合わせて書き換える
System.GetEnvironmentVariable.GetEnvironmentVariable Name: $'''OneDrive''' Value=> OneDrive
SET AppConfig TO $'''%OneDrive%\\OneLibrary\\automation\\AddMasterSetting\\AppConfig.json'''
File.GetPathPart File: AppConfig Directory=> BaseDir
CALL Init
**ENDREGION
**REGION ping
Text.Replace Text: Server TextToFind: $'''\\''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''%''%''' ActivateEscapeSequences: False Result=> Host
System.Ping HostName: Host Timeout: 5000 PingResult=> PingResult
ON ERROR REPEAT 2 TIMES WAIT 30
ON ERROR
END
IF PingResult = $'''Failure''' THEN
EXIT Code: 0 ErrorMessage: $'''%Host% に接続できません。'''
END
**ENDREGION
CALL InputData
CALL Registration
**REGION 最終処理
CALL Now
Text.AppendLine Text: Log LineToAppend: $'''%CurrentDateTime% INFO Process is succeed.''' Result=> Log
File.WriteText File: StoreLog TextToWrite: Log AppendNewLine: True IfFileExists: File.IfFileExists.Append Encoding: File.FileEncoding.Unicode
**ENDREGION
END FUNCTION
Init
FUNCTION Init GLOBAL
**REGION 設定ファイル
Text.AppendLine Text: Log LineToAppend: $'''%CurrentDateTime% INFO Check config.''' Result=> Log
File.ReadTextFromFile.ReadTextAsList File: AppConfig Encoding: File.TextFileEncoding.UTF8 Contents=> FileContents
ON ERROR
SET ErrorMsg TO $'''%AppConfig% を読み取れません。'''
THROW ERROR
END
Variables.ConvertJsonToCustomObject Json: FileContents CustomObject=> Settings
ON ERROR ParseJsonError
SET ErrorMsg TO $'''構文エラーです。'''
CALL Catch
THROW ERROR
END
SET StoreLog TO $'''%BaseDir%%Settings['AppSettings']['StoreLog']%'''
SET Fqdn TO Settings['AppSettings']['Fqdn']
SET Server TO Settings['AppSettings']['Server']
SET StoreDir TO Settings['AppSettings']['StoreDir']
SET MasterFile TO Settings['AppSettings']['MasterFile']
SET DestDir TO Settings['AppSettings']['DestDir']
**ENDREGION
END FUNCTION
InputData
FUNCTION InputData GLOBAL
@@statistics_statistics_Input_Text: '1'
@@statistics_statistics_Action_Submit: '1'
Display.ShowCustomDialog CardTemplateJson: '''{
\"type\": \"AdaptiveCard\",
\"version\": \"1.4\",
\"id\": \"AdaptiveCard\",
\"body\": [
{
\"type\": \"Input.Text\",
\"id\": \"Title\",
\"isMultiline\": true,
\"label\": \"${Title_Label}\",
\"spacing\": \"extraLarge\"
}
],
\"actions\": [
{
\"type\": \"Action.Submit\",
\"id\": \"Submit\",
\"title\": \"${Submit_Title}\"
}
]
}''' CustomFormData=> CustomFormData ButtonPressed=> ButtonPressed @Title_Label: $'''タイトル''' @Submit_Title: $'''Ok'''
IF ButtonPressed = $'''Cancel''' THEN
EXIT Code: 0 ErrorMessage: $'''実行を中止します。'''
END
IF IsEmpty(CustomFormData.Title) THEN
EXIT Code: 0 ErrorMessage: $'''入力がありませんでした。'''
END
Text.Trim Text: CustomFormData.Title TrimOption: Text.TrimOption.Both TrimmedText=> TrimmedText
**REGION 半角→全角
/# ファイル名に使用できない文字列: \\ / : * ? " < > |
使用できるがついでに置換する: !#/
Text.Replace Text: TrimmedText TextToFind: $'''/''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''/''' ActivateEscapeSequences: False Result=> TrimmedText
Text.Replace Text: TrimmedText TextToFind: $''':''' IsRegEx: False IgnoreCase: False ReplaceWith: $''':''' ActivateEscapeSequences: False Result=> TrimmedText
Text.Replace Text: TrimmedText TextToFind: $'''*''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''*''' ActivateEscapeSequences: False Result=> TrimmedText
Text.Replace Text: TrimmedText TextToFind: $'''?''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''?''' ActivateEscapeSequences: False Result=> TrimmedText
Text.Replace Text: TrimmedText TextToFind: $'''<''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''<''' ActivateEscapeSequences: False Result=> TrimmedText
Text.Replace Text: TrimmedText TextToFind: $'''>''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''>''' ActivateEscapeSequences: False Result=> TrimmedText
Text.Replace Text: TrimmedText TextToFind: $'''|''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''|''' ActivateEscapeSequences: False Result=> TrimmedText
Text.Replace Text: TrimmedText TextToFind: $'''!''' IsRegEx: False IgnoreCase: False ReplaceWith: $'''!''' ActivateEscapeSequences: False Result=> TrimmedText
**ENDREGION
Text.SplitText.Split Text: TrimmedText StandardDelimiter: Text.StandardDelimiter.NewLine DelimiterTimes: 1 Result=> 作品リスト
END FUNCTION
Registration
FUNCTION Registration GLOBAL
XML.ReadFromFile File: $'''%OneDrive%%MasterFile%''' Encoding: XML.FileEncoding.DefaultEncoding XmlDocument=> XmlDocument
ON ERROR DirectoryNotFoundError
SET ErrorMsg TO $'''ディレクトリが見つかりません。'''
CALL Catch
THROW ERROR
ON ERROR FileNotFoundError
SET ErrorMsg TO $'''ファイルが見つかりません。'''
CALL Catch
THROW ERROR
ON ERROR ReadFileError
SET ErrorMsg TO $'''ファイルを読み取れませんでした。'''
CALL Catch
THROW ERROR
ON ERROR InvalidFileError
SET ErrorMsg TO $'''ファイルに有効な XML ドキュメントが含まれていません。'''
CALL Catch
THROW ERROR
END
LOOP FOREACH タイトル IN 作品リスト
CALL Now
**REGION フォルダーの作成
IF (Folder.IfFolderExists.Exists Path: $'''%Server%%StoreDir%\\%タイトル%''') THEN
# フォルダーが存在していたら定義も作成済みなのでスキップする
Text.AppendLine Text: Log LineToAppend: $'''%CurrentDateTime% INFO Skip %タイトル%''' Result=> Log
NEXT LOOP
END
Text.AppendLine Text: Log LineToAppend: $'''%CurrentDateTime% INFO Set %タイトル%''' Result=> Log
Folder.Create FolderPath: $'''%Server%%StoreDir%''' FolderName: タイトル
ON ERROR REPEAT 3 TIMES WAIT 15
ON ERROR
SET ErrorMsg TO $'''フォルダー「%タイトル%」を作成できません。'''
CALL Catch
THROW ERROR
END
**ENDREGION
**REGION 定義ファイルに追加
@@copilotGeneratedAction: 'False'
Scripting.RunPowershellScript.RunPowershellScript Script: $'''New-Guid''' ScriptOutput=> PowershellOutput
Text.ParseText.RegexParseForFirstOccurrence Text: PowershellOutput TextToFind: $'''\\w+-\\w+-\\w+-\\w+-\\w+''' StartingPosition: 0 IgnoreCase: False Match=> GUID
XML.InsertElement Document: XmlDocument XPathQuery: $'''Strategies''' Element: $'''<Strategy name=\"%GUID%\">
<Regex>%タイトル%</Regex>
<DestDir>%DestDir%</DestDir>
<DestDir>%Fqdn%%StoreDir%\\%タイトル%</DestDir>
</Strategy>'''
**ENDREGION
END
XML.WriteXmlToFile.WriteToFileFormatted File: $'''%OneDrive%%MasterFile%''' Xml: XmlDocument Encoding: XML.FileEncoding.UTF8 Indentation: 2
ON ERROR REPEAT 3 TIMES WAIT 15
END
END FUNCTION
- フォルダー
- あり:作業不要なのでスキップ
- なし:フォルダーを作成し、定義ファイルに追加
Now
FUNCTION Now GLOBAL
DateTime.GetCurrentDateTime.Local DateTimeFormat: DateTime.DateTimeFormat.DateAndTime CurrentDateTime=> CurrentDateTime
END FUNCTION
Catch
FUNCTION Catch GLOBAL
ERROR => LastError
CALL Now
Text.AppendLine Text: Log LineToAppend: $'''%CurrentDateTime% ERROR Process is failure. %LastError.Message% - %LastError.Location%''' Result=> Log
File.WriteText File: StoreLog TextToWrite: Log AppendNewLine: True IfFileExists: File.IfFileExists.Append Encoding: File.FileEncoding.Unicode
XML.WriteXmlToFile.WriteToFileFormatted File: $'''%OneDrive%%MasterFile%''' Xml: XmlDocument Encoding: XML.FileEncoding.DefaultEncoding Indentation: 2
ON ERROR
END
EXIT Code: 0 ErrorMessage: ErrorMsg
END FUNCTION
AppConfig.json
AppConfig.json
{
"AppSettings": {
"StoreLog": "\\fslog.txt",
"Fqdn": "\\\\hogehoge",
"Server": "\\\\192.168.xxx.xxx",
"StoreDir": "\\xxx",
"MasterFile": "\\hogehoge\\MasterSetting.xml",
"DestDir": "hogehoge"
}
}
Discussion