Infopath ボタンクリックでローカルにフォームを保存したい

Infopath は Office 製品のひとつですので、お馴染みの [ファイル]→[名前をつけて保存] でどこにでも保存することができます。

この機能、確かに便利なのですが、SharePoint のフォームライブラリと連携して Infopath を利用しはじめると、逆に厄介な機能にもなります。

つまり、何処にでも保存できてしまう上、ファイル名も自由につけられてしまうので、正しい場所に正しい名前で保存される保障がありません。そこで、Infopath のボタンコントロール+データ接続で、[保存] ボタンを用意するのが一般的なシナリオです。

しかし、データ接続は必ず絶対パスでなくてはならないという制約があるため、[名前をつけて保存] でローカルに保存されたファイルでも、[保存] ボタンが(間違って)クリックされると、SharePoint 側のフォームライブラリを更新してしまいます。


実際のところ、これはかなり問題です。
フォームライブラリからファイルを開いている限りにおいては、きちんと排他制御がかかります。
しkし、一度ローカルに保存したファイルには、当然、排他がかかりません。
そのため、ユーザがローカルに保存した古いファイルで、誤って [保存] ボタンをクリックしてしまうと、SharePoint 側の最新情報を古いファイルで上書きしてしまうのです。

これを防ぐには、フォームのオプションで、[名前をつけて保存] 機能そのものを無効にしてしまえばよいのですが、そうすると、今度は情報をローカルに保存しておくこと自体ができなくなります。
それはそれで不便です。

ローカルには保存させたい。
しかし、ボタンなど動的なコントロールは無効にしたい。

この二つの要件を満たすには
「クリックすると特定のフラグ(コントロール無効化)を立てて、ローカルにファイルを保存する」
機能を持ったボタンが必要です。
これは標準の動作規則では無理ですので、コードで記述してやる必要があります。

どこかに参考になるソースはないかと、ネットを探したところ。
海外にそのままズバリなコードがありました

Try the following function
[jScript]
function saveFormAsFile()
{
var strFileName = “formName.xml”
var xmlDoc = XDocument.DOM.xml;
var objFSO = new ActiveXObject(“Scripting.FileSystemObject”);
var tempFile = objFSO.CreateTextFile(“c:¥¥” + strFileName , true);
tempFile.Write(xmlDoc);
}

このコードをボタンに仕込み、実行すると、見事ローカルに xml が保存されました!

よし、これで OK!─と思いきや。

…開けません。
メモ帳で開いてみても、XML に特に不審な点はありません。
サーバ上のオリジナルとの違いは、文字コード指定
encoding=”UTF-8″?>
が無いこと位です。

─文字コード?

結局、これが原因でした。

今日覚えたこと FileSystemObjectの使い方まとめ
CreateTextFileメソッドは、空のテキストファイルを作成してTextStreamのインスタンスを返す。以降、ファイルへの書き込みはこのTextStreamのインスタンスを使う。終わったらTextStreamをCloseする。
CreateTextFileの第1引数は作るファイル名。
CreateTextFileの第2引数は上書き許可フラグ。
CreateTextFileの第3引数をtrueにするとUTF-16でファイルを作る。falseにするとShift_JIS。UTF-8で作ることはできない。UTF-8で作りたいときはFileSystemObjectではなくADODB.Streamを使う。

つまり、Infopath は UTF-8 で XML を出力するので、UTF-8 に対応していない CreateTextFile では、2バイト文字がエラーになるんですね。
前述の外人さんは、アルファベットしか使わないので問題にならなかった、と。
くそ、うらやましいぞ外人(笑)

で、この方によると、ADODB.Stream を使えばいいらしい。

今日覚えたこと いろんな文字コードでファイルを読み書きするにはADODB.Stream 
ファイルの書き込み
var s = new ActiveXObject(‘ADODB.Stream’);
s.type = 2;
s.charset = ‘utf-8′;
s.open();
s.writeText(‘hello’);
s.saveToFile(‘C:¥¥data¥hoge.txt’, 2);
s.close();
書き込みの際も、charsetプロパティに文字コード名を渡せばおk。
・saveToFileメソッドの第2引数の2は、上書きで書き込むよ、という意味。1を渡すと既にファイルがあった場合にエラーになる。
・新しいファイルを作ることしかできない。追記/編集はない。

なるほど。
このソースをそのまま(パスだけ C:¥¥ に変更)テキストにコピペし、拡張子を .js にしてから起動したところ、C ドライブに UTF-8 の hoge.txt ができました!

…。
問題はこれをどう Infopath 内で表記するかということだ^^;;;


※英語だと Infopath Automation Server can’t create the object

いろいろ試しましたが、どうしてもこのエラーから抜けられない…。
var s = new ActiveXObject(‘ADODB.Stream’);
の時点でエラーしてますね。
ひょっとして Infopath では ADODB.Stream は使えない?
いやでも、JScript はサポートされている訳だし…。

調べてみると、どうやらコーディングの問題ではないようです。
KBがありました。

Microsoft サポートオンライン InfoPath で CreateObject 関数または ActiveXObject 関数のスクリプト エラーが発生する
InfoPath フォームは、常にインターネット セキュリティ ゾーンのコンテキスト内で実行されます。インターネット セキュリティ ゾーンではフォームのスクリプトで実行できる操作と実行できない操作が定義されています。通常このエラーは、フォームが実行されるインターネット セキュリティ ゾーンで “スクリプトを実行しても安全だとマークされていない ActiveX コントロールの初期化とスクリプトの実行” が無効になっているため、ActiveX コンポーネントの作成が許可されない場合に発生します。このオプションは、悪意のあるスクリプトやデータを受け取った場合に、このコンポーネントによるシステムへの損害がないことをコントロールの作成者が保証できないことを意味します。

Infopath はクライアントアプリケーションなのに、ブラウザ(ie)の設定に依存しているんですね!
これは初めて知りました。驚きです。

InfoPath フォームでこの問題を回避するには、以下の方法のいずれかを使用します。
・フォームを完全に信頼された URN ベースのフォームにする
・InfoPath フォームをホストするサーバーの URL を、Microsoft Internet Explorer の信頼済みサイトの一覧に追加する
・フォーム テンプレートにデジタル署名する (InfoPath 2003 Service Pack 1 に適用)

1番目と3番目は難しそう…。
2番目が一番手軽ですね。早速、試してみます。

つづきます

Infopath 正しくは XDocument.Solution.URI ではなく XDocument.URI だったらしい
続・Infopath ボタンクリックでローカルにフォームを保存したい2
続・Infopath ボタンクリックでローカルにフォームを保存したい
Infopath ボタンクリックでローカルにフォームを保存したい


Author

中村 和彦(シンプレッソ・コンサルティング株式会社 代表)が「ユーザ視点の SharePoint 情報」を発信します。元大手製造業 SharePoint 運用担当。現SharePoint コンサルタント。お仕事のお問い合わせはこちらまでお願いします。当ブログにおける発信内容は個人に帰属し所属組織の公式発信/見解ではありません。
FB : 中村 和彦
blog: Be・Better!
MS MVP SharePoint 2009/10-2011/9
MS MVP Office 365 2012/10-2014/9