出直し!! ヘルプ

連載中

連載 終了

2025/05/27

DXL Step-by-Step:#57)ノード操作 ⑩ - ノードの複製

今回はノードを複製する方法についてまとめます。同じフォーマットの表を複数個所に配置するなど応用方法はさまざまですね。


ノードの複製

ノードを複製するには、 Clone メソッドを使用します。

Clone (NotesDOMNode - LotusScript®)

前回紹介した RemoveChild メソッドと同様で、このメソッドも NotesDOMNode クラスのメソッドとなります。ですので、それを継承している NotesDOMEmenetNode でも使用できます。

構文は次の通りです。

Set notesDOMNode = notesDOMNode .Clone( deepClone )

引数 deepClone で True を指定するとサブノードを含めて複製します。False だとそのノードだけとなるのですが、DXL ツリーの階層構造を考えると、通常は True での利用となりますね。


複製したノードの状態

CreateElementNode メソッドで新規作成したノードは、DXL ツリーには属さず宙に浮いたような状態であると #51)ノード操作 ④ - ノードの新規作成 で紹介しました。複製したノードも同様の状態となり、ParentNode が存在しない状態となります。

DXL ツリーに配置するためには、AppendChild メソッドや #52)ノード操作 ⑤ - ノードを挿入する方法 で紹介した方法を追加って、希望する位置に配置する必要があります。


複製時の注意

例えば、リッチテキストフィールド直下にある 2 つ目の表を複製して一番後ろに挿入したいとします。そのサンプルは次の通りです( #55)ノード操作 ⑧ - ノードの検索 で紹介した関数を使用)。

      ・・・
   'リッチテキスト直下の2つ目のテーブルを取得
   Dim denTbl As NotesDOMElementNode
   Set denTbl = xGetNthChildByName(denRT, "table", 2)

   'テーブルの後ろの段落を得取得
   Dim denPar As NotesDOMElementNode
   Set denPar = xGetNextSiblingByName(denTbl, "par")

   'テーブルを複製して追加
   Dim denNew As NotesDOMElementNode
   Set denNew = denTbl.Clone(True)
   Call denTbl.ParentNode.AppendChild(denNew)

   'テーブルの後ろに段落を追加
   Set denNew = denPar.Clone(True)
   Call denTbl.ParentNode.AppendChild(denNew)
      ・・・

xGetNthChildByName(denRT, "table", 2) で 2 つ目の表を取得して、denTbl.Clone(True) で複製しています。ただ、ポイントはココではありません。表を配置後、その後ろに段落(par ノード)を配置しています。table ノードは前後に par ノードが必要となるための対応なのですが、ノードをコピーして配置するだけではなく、前後関係に配慮して DXL ツリーとして破綻しないよう注意することが重要です。


前回 DXL Step-by-Step 次回


2025/05/19

環境変数の利用と注意

先日、notes.ini 利用したアプリでちょっとしたトラブルがあったので、まとめておきます。

notes.ini ファイルは、ノーツの動作設定が記録されているファイルで、ノーツクライアントのプログラムディレクトリに存在します。セットアップするなどノーツ担当者であれば知らないはずはないファイルですね。


notes.ini ファイルのアクセス

アプリ開発では、notes.ini にアクセスする機能が提供されています。

@関数 LotusScript(NotesSessionクラス)
設定 @Environment SetEnvironmentVar メソッド
取得 @Environment GetEnvironmentString メソッド

例えば、SrcStr フィールドの値を notes.ini に Denaoshi という名前で設定するには、次のように記述します。

@関数 @Environment("Denaoshi"; SrcStr)
LotusScript Dim ns As New NotesSession
Dim nuiw As New NotesUIWorkspace
Dim nuid As NotesUIDocument
Dim sStr As String

Set nuid = nuiw.CurrentDocument
sStr = nuid.FieldGetText("SrcStr")
Call ns.SetEnvironmentVar("Denaoshi", sStr)

実行すると、以下のように notes.ini に新しいエントリ "$Denaoshi" が追加され、値が設定されます。すでにエントリがある場合には、値のみ更新します。

参考までの情報ですが、全角文字の前に付加されている □ は、LMBCS(Lotus Multi-Byte Character Set)の日本語を表すコード(0x10)です。LMBCS の日本語は、0x10 + Shift-JIS の 3 バイトで構成されます。バイナリエディタで ”出” の文字を確認すると次のようになります(”出” の文字コードは 0x8F6F)。

notes.ini ファイルから値を取得して、IniStr フィールドにセットする方法は、次の通りです。

@関数 xIni := @Environment("Denaoshi");
@SetField("IniStr"; xIni)
LotusScript Dim ns As New NotesSession
Dim nuiw As New NotesUIWorkspace
Dim nuid As NotesUIDocument
Dim sIni As String

Set nuid = nuiw.CurrentDocument
sIni = ns.GetEnvironmentString("Denaoshi")
Call nuid.FieldSetText("IniStr", sIni)

取得した値には LMBCS の □ は付加されず、セットした通りの値が取得できます。LMBCS については notes.ini をテキストエディタなどで直接開いたときにだけ気にすればいいということですね。


notes.ini の使い方

上記の通り、notes.ini に値を入出力する方法を紹介しました。これを ”環境変数” と呼び、その名の通り、変数のように利用できます。notes.ini はノーツクライアントに一つですから、アプリをまたがっても値の共有が可能となる点がポイントです。

ワークフローアプリを例にすると、前回選択した上司を保持させ、別のワークフローアプリでそれを上司として初期表示するというような使い方ができます。notes.ini を使えば、簡単な仕組みで大きな効果を得ることができます。

ただ、次にその値を利用するタイミングが、明日なのか1年後なのか定かではありません。先の例のように人の情報の場合、退職などによりノーツユーザとして存在しない場合も考えられます。このような不整合に備え、チェックや再選択させる機能などの用意が必要です。


notes.ini 利用時の注意

最後に先日発生したトラブルについて紹介します。

ワークフロー系のアプリで、質問形式で申請内容を確認するウィザード形式のフォームがありました。ウィザードの最後では、必要な申請書を表示して、起票する機能を提供していました。ウィザードで入力した情報を notes.ini に書き込み、申請書起票時に読み込んで初期表示させ、二重入力を省く仕組みでした。

この機能で、ウィザードと申請書で値が変わる現象が発生しました。連携データに全角スペースが含まれていたことが原因でした。実験したところ、全角スペースは notes.ini に出力時は全角のままですが、読み込んだ際には半角スペースに変換されるようです(@関数、LotusScript とも同様)。

また、複数の全角スペースや複数の半角スペースも半角スペース1つに変換されることも発見しました。この結果より、notes.ini から値を読み込む際には、Trim と同等の機能が実行されいると想定できます。


まとめ

今回紹介した環境変数の利用は、うまく使えば非常に便利な機能です。ただ、Trim のような処理が行われている点には注意が必要です。ご利用の際には、環境変数に格納される値についても意識しておくことをおススメします。

また、環境変数はすべてのノーツアプリで共通で使用できます。便利な反面、大量に使用すると、それそれぞれの目的や設定タイミング、どのアプリで利用しているかが不明瞭になり、バグや仕様の複雑化の要因となります。LotusScript でパブリック変数を使用すべきでない理由と同じですね。

利用の際には環境変数の名称や設定される値、設定タイミングなどの仕様を決め、チーム全体で周知することが重要です。


2025/05/14

@MailSend の動作 ②

@MailSend の紹介です。この関数は、引数なしと引数ありの構文があり、前回は引数なしの動作について説明しました。今回は引数ありのパターンの使い方についてまとめます。


構文

まずは、構文の確認です。

@MailSend( sendTo ; copyTo ; blindCopyTo ; subject ; remark ; bodyFields ; flags )

各引数にセットする値と役割は次の通りです。

1 sendTo 文字列
文字列リスト
メールの宛先
宛先、CC、BCC の 1 つ以上に指定が必要
2 copyTo 文字列
文字列リスト
3 blindCopyTo 文字列
文字列リスト
4 subject 文字列 メールの件名
5 remark 文字列 メールの本文
6 bodyFields 文字列リスト 本文に追加するフィールド
7 flags キーワード メールに関するフラグ


宛先の設定

宛先に設定できるのは、ユーザ名、グループ名です。一人だけに送信する場合は文字列、複数人に送信する場合はリスト値で設定します。宛先、CC、BCC のうちどれか 1 つには指定が必要です。設定しない引数にはからの文字列 ""  を設定します。


件名の設定

メールの件名を文字列で指定します。文字列リストを指定した場合、最初の要素が使用されます。


本文の設定

@MailSend で送信するメールの本文は、プレーンテキストとなります。引数の文字列に @NewLine を含むことで、改行させることができ、体裁を整えることが可能です。


ここまでが一般的な使い方となるので、簡単なサンプルを作成します。

メール送信ボタンの式は次の通りです。

xSubject := "『" + Destination + "』 の申請";
xBody := "新しい申請書を申請しました。";
xBody := xBody + @NewLine + "承認してください。";

@MailSend(Approver; ""; ""; xSubject; xBody)

フォームをプリビューして、メールを送信すると、メールが送信されます。


本文に追加するフィールドの設定

この機能は文書内のフィールドをメール内に埋め込める機能で、リストで複数のフィールドを指定すると、それらすべてを本文に表示します。

xSubject := "『" + Destination + "』 の申請";
xBody := "新しい申請書を申請しました。";
xBody := xBody + @NewLine + "承認してください。";
xBodyFlds := "Date":"Destination":"Purpose":"Amount";

@MailSend(Approver; ""; ""; xSubject; xBody; xBodyFlds)

メール送信ボタンを修正して、メールを送信すると次のようになりました。

指定したフィールドの一部しか表示されいません。しかも、改行も間隔も開けずただ羅列されています。ヘルプによると、数値や日付フィールドには対応していないようです。なかなか使いどころがわからない機能です...。この仕様だと remark にがんばって指定したほうが、自由に体裁が決定できるのでいいですね。


フラグの設定

最後の引数であるフラグは、送信優先度や署名、暗号化など、メール配信の細かな設定ができます。通常のアプリで使いそうなフラグは次の 2 つです。

キーワード 機能
[INCLUDEDOCLINK] @MailSend が実行されたときに開いていた文書の文書リンクを本文の最後に追加します。
ただし、文書は保存されている必要があります。
[RETURNRECEIPT] 受信者がメールを開いたとき、開封確認を送る設定をします。

フラグはリストのように記述すると複数指定することができます。例えば、次のように設定すると、文書リンクと開封確認付きのメールとなります。

xSubject := "『" + Destination + "』 の申請";
xBody := "新しい申請書を申請しました。";
xBody := xBody + @NewLine + "承認してください。" + @NewLine;

@MailSend(Approver; ""; ""; xSubject; xBody; ""; [IncludeDoclink]:[ReturnReceipt])


まとめ

引数付きの @MailSend を使えば、宛先、件名、本文が自由に設定でき、引数なしの場合のようにフィールド名の縛りもありません。また、文書リンク付きのメールを発信できるのでワークフローアプリでも活用できますね。


2025/05/10

@MailSend の動作 ①

Notes アプリ開発とメールの送信は切っても切れない関係といえますね。今回は、式言語でメールを送信する @MailSend について紹介します。


構文

ヘルプによると @MailSend の構文は次のように、引数のあり/なしの 2 通りあります。

@MailSend

@MailSend( sendTo ; copyTo ; blindCopyTo ; subject ; remark ; bodyFields ; [ flags ] )

今回は、前者の引数なしのパターンを紹介します。


引数なしでメール送信できる訳

引数なしということは、宛先も指定しないの? と疑問がわきますが、大丈夫です。この機能は、文書内のフィールド値を使用して送信する機能となっています。

簡単なサンプルとして次のようなフォームを作成します。

フォームをプリビューして、宛先と件名を入力し、[メール送信]ボタンをクリックします。

すると、宛先に指定したユーザのメールボックスにメールが届きます。

とっても簡単ですね。そして仕組みも単純です。

@MailSend を実行する文書にある SendTo が宛先、Subject が件名として使用されます。このように、特定の役割を持ったフィールド名を予約フィールドといいます。


予約フィールド

メールの配信制御に関連する予約フィールドはヘルプに詳細が記載されています。

メールオプションを制御する予約フィールド


通常、メール送信で使用する予約フィールドをまとめると次の通りです。

予約フィールド 役割・使い方
SendTo 宛先(リスト値可)
CopyTo CC(リスト値可)
BlindCopyTo BCC(リスト値可)
Subject メールの件名
Body メールの本文
ReturnReceipt 受信者がメールを開いたとき、開封確認を送る場合 "1" を指定


すべてのフィールドを送信

@MailSend では、送信する文書内のすべてのフィールドをメールで配信されます。例えば、次のようにフィールドを 3 つ追加してメールを送信してみます。

すると届いたメールの文書プロパティでこれらフィールドが確認できます。

Notes メールは、メールとは関係ないフィールドがメール内にあっても、そのまま配信するようです。文書を丸ごと配信する感じですね。いかにもノーツらしい挙動です。


リッチテキストの送信

メールの本文(Body)フィールドはリッチテキストです。これに倣い、作成したフォームの Body フィールドをリッチテキストに変更します。文書を新規作成し、本文を記入して送信しても、届いたメールの本文は空っぽとなります。

リッチテキストは文書を保存しないと @MailSend で送信できない仕様のようです。ただ、文書を保存してから送信するとメールを開く際にエラーが発生します。

これは、送信元の Form フィールドまで含めて送信されているからです。すべてのフィールドが送信される機能の弊害と言えますね。ちなみにメール DB にあわせて、送信元のフォーム名を "Memo" としておくとこのエラーは回避できます。


まとめ

今回は @MailSend の引数なしで使用する方法を紹介しました。引数がないので@式はシンプルになりますが、フィールド名が固定されたり、フォーム名を意識したする必要がありました。また、すべてのフィールドが送信されることもあり、アプリで利用するには制限が多く、活用しづらい機能と言えます。

このような課題を解決するのが引数ありの @MailSend となります。次回、使い方を紹介します。