[OutSystems11]OfficeUtils V5.4.0でWordファイルに書き込みを行う

ちょっと聞かれたので、OutSystems11でWordファイルを出力する方法について確認。
おそらく他にも方法はあるが、ここではForgeコンポーネントのOfficeUtilsを使う。
OfficeUtilsにはODCのコンポーネントもある[^1]が、ここではO11版の方を見る。

[^1]:Version 5.2.1のRelease NotesにはODC版コンポーネントの記述があるので、同じ作者によるものか、何らかの関係はあるものと思われる

# 環境情報
Personal Environment (Version 11.35.0 (Build 45040))
Service Studio (Version 11.53.33) Mac
[Office Utils (Version 5.4.0)](https://www.outsystems.com/forge/component-overview/687/officeutils-o11)

# ライセンスについて
Forgeコンポーネントページによると、[NPOI](https://github.com/nissl-lab/npoi)を使っているとのこと。NPOIのレポジトリによると、ライセンスはApache-2.0 license。

念の為、コンポーネントをダウンロードし、展開して、xifファイル中を確認してみる。
.csprojファイルを開いて、Referenceを確認するとかなり多量のコンポーネントを参照している。SystemやOutSystemsで始まるライブラリとNPOIを除くと以下のものを参照していた。NuGetで探し、ライセンスを確認した。ICSharpCode.SharpZipLib以外は問題なさそう。ICSharpCode.SharpZipLibも問題はなさそうな気がするが、慎重に行くなら、もう少しよく見たほうが良さそう。

- BountyCastle.Cryptography Version=2.0.0.0　→ 独自ライセンス？　https://www.nuget.org/packages/BouncyCastle.Cryptography/2.0.0/License
- Enums.NET Version=4.0.0.0　→ MIT
- ExtendedNumerics.BigDecimal Version=2025.1001.2.129　→ MIT
- ICSharpCode.SharpZipLib Version=1.4.2.13　→ MIT？　NuGet内で似たような名前のライブラリが複数見つかるが、ズバリの名前のものがない。もしかしたら使っているものはDeprecatedになったのかもしれない。業務で使うならもう少し調査するところだが……
- MathNet.Numerics ersion=5.0.0.0　→ MIT
- Microsoft.IO.RecyclableMemoryStream Version=3.0.0.0　→ MIT
- SixLabors.Fonts Version=1.0.0.0　→ Apache 2.0
- SixLabors.ImageSharp Version=2.0.0.0　→ Apache 2.0

なお、OutSystemsプログラム部分はBSD-3。これはForgeコンポーネントのデフォルト。

# このコンポーネントでできること (Wordについて）
## Wordファイルのテンプレート内の特定文字列を置き換える
実行例：↓のようなWordファイルを対象に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/6fec3508-0b92-4bc5-b4ec-a6ca1f7d7511.png)
特定文字列（ここでは、PlaceholderTextとPlaceholderImage）を別の文字列や画像に置き換える。

結果例：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/90618f8e-7ec3-4a23-a5e7-2bf58a71ef14.png)

「PlaceholderText」を「置換されたテキスト」に、「PlaceholderImage」をモジュール内にあったfavicon画像に置き換えている。

- スタイルが違っていても、特定文字列に一致していればうまく置換してくれる
- 行内に複数特定文字列があっても置換してくれる
- 1回の置換呼び出しで、特定文字列に合致する部分全ての置換を行ってくれた

## Wordファイルからテキスト（だけ）を抽出する
見出し通りなので中身は省略。
Word_Extract_ContentAsText ActionのInput ParameterにWordファイルのバイナリを渡すだけ。

# アーキテクチャ
OfficeUtils（Serviceモジュール）とOfficeUtilExternalLib（Extension）の組み合わせで構成されるが、開発者が直接呼び出すのはOfficeUtilsのActionのみ。

Extensionが提供するWordFileというStructureに、テンプレートとなるWordファイル、書き込み指示を蓄積し、最後にWord_Export_GenerateFile Actionに渡すことで、置換を行った結果のWordファイルのバイナリを取得する仕組み。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/f7e99436-5caf-414f-b36a-527c3d0d739f.png)

# 使い方
1. WordFile型のLocal Variableを用意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/4fb560ee-8d3a-41bf-9604-6d3a5d141e97.png)
2. テンプレートとなるWordファイルをWord_Export_SetTemplate Actionで設定する（Input Parameterはまだ値を設定していないWordFileとテンプレートのバイナリ）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/c57180c1-5579-49eb-a393-e43a9f7b90b7.png)
3. OptionをWord_Export_SetOptions Actionで設定（前のステップで呼んだActionのOutput ParameterをInput ParameterのWordFileに渡す）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/3f5899be-5dbe-45dc-a117-dc1361a3d0f6.png)
4. TextやImageの置換情報をWord_Export_SetTextやWord_Export_SetPicture Actionで登録する（前のステップで呼んだActionのOutput ParameterをInput ParameterのWordFileに渡す）
Textの置換例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/4bc2dfb5-c149-47ab-8f1d-9825a5625a37.png)
2-4は順不同と思われるが、この順番がわかりやすいのではないか
5. ここまでに編集してきたWordFileをInput ParameterにしてWord_Export_GenerateFile Actionを呼んで結果のWordファイルを取得
下の例は直前呼び出しが、Word_Export_SetPicture Actionなので、そのOutput Parameterを渡している
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/aab8bc2f-ddcc-4038-84cd-a402d2cfaed9.png)

# 設計パターン
この、
「編集情報をローコード部分で行い、その結果をローコード内の変数で蓄積する。蓄積した結果（複数の操作が溜まっている）を1回のC#呼び出しで処理する」
という設計パターンは、私もODCのExternal Logicで利用することを考えていた。External Logicの場合はO11のExtensionと違い、通信を経由して実行されるため、呼び出し回数を減らすことがより重要であるため。