🥭

Power Automate Desktop で XML ファイルの編集

2024/07/07に公開

XML アクション

PAD で XML ファイルを読み取って要素を挿入してみようと思います。

使い方

  1. ファイルから読み取った値に
    Before
  2. 「XML 要素を挿入します」アクションで挿入すると
    Action
  3. 上手い具合に追加されます。
    After

テキストアクションでごちゃごちゃやるより簡単で良いですね。


フローで使ってみる

ついでになにか作ってみようと思います。
ちょうど良い具合に思いついたものがあったのでそれで使います。

いままで手作業で行っていた準備を自動化します。
作業内容はシンプル。

  • 手順
    1. 格納先のフォルダーを作成
    2. 定義ファイルに追加

これだけ。簡単。
作業頻度は四半期ごとに 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>

実行

  1. すっごい塗りつぶしていて分かりづらいのですが、こういうファイルからタイトル列をまとめてコピー
    Excel
  2. PAD の入力フォームにペースト →OK
    カスタム フォーム
  3. おしまい

複数行のテキストをまとめて貼り付けるだけ。
あとは 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

Main

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

InputData

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

Registration

  • フォルダー
    • あり:作業不要なのでスキップ
    • なし:フォルダーを作成し、定義ファイルに追加
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