2024/12/29

DXL Step-by-Step:#47)添付ファイルの取得 ②

DXL 経由で添付ファイルのダウンロードに関して、前回 は、プログラムの全体像を説明しました。今回はその続きです。添付ファイルの実体をを取得する部分を紹介します。


呼び出し元の確認

まずは、呼び出し元のプログラムを再確認します。

attachmentref ノードが denRef にセットされており、name 属性から文書内で一意となるファイル名を取得しています。このファイル名を引数に、そのファイルの実体を保存している $FILE フィールドを取得する関数が xGetDXL_FileItem でした。

   If Not (denRef Is Nothing) Then
      'ファイル名取得
      Dim sName As String
      Dim sDisp As String
      sName = denRef.GetAttribute("name")
      sDisp = denRef.GetAttribute("displayname")

      '$FILE フィールド取得
      Dim denFile As NotesDOMElementNode
      Set denFile = xGetDXL_FileItem(ddn, sName) 'Notes 内部の名称で検索


添付ファイルの DXL 確認

続いて、添付ファイルの DXL 構造の再確認です。

添付ファイルは $FILE というフィールド内に保存されいました。下図 の赤線のように $FILE も通常のフィールドと同列なので、Title や Body といったフィールド(item ノード)に並んで登場します。

item ノード内に添付ファイルがある場合、item > object > file と階層化さた file ノードの name 属性に、一意となるファイル名がセットされています。

よって、添付ファイルの実体を探す際には、item ノードだけでなく、file ノードの属性を含めて判定する必要があります。

これで作成すべきロジックが見えてきましたね。


ファイルの実体の取得

では、添付ファイルの実体を取得する関数 xGetDXL_FileItem を紹介します。

フィールドを取得する関数 xGetDXL_item をベースに作成しました。通常のフィールドと違うのは、フィールド名が $FILE 固定になっている点です(赤字)。フィールド名が $FILE であれば、file ノードを取得して、ファイル名を判定しています(紫字)。

Function xGetDXL_FileItem(vddn As NotesDOMDocumentNode, ByVal vsName As String) As NotesDOMElementNode
   '文書のノードの取得
   Dim denDoc As NotesDOMElementNode
   Set denDoc = vddn.DocumentElement

   'itemノードをチェック
   Dim denItem As NotesDOMElementNode
   Dim dnl As NotesDOMNodeList
   Dim i As Integer
   Dim sFld As String
   Dim sName As String
   Dim den As NotesDOMElementNode

   Set dnl = denDoc.GetElementsByTagName("item")
   For i = 1 To dnl.NumberOfEntries
      Set denItem = dnl.GetItem(i)
      sFld = denItem.GetAttribute("name")
      If LCase(sFld) = LCase("$FILE") Then
         '添付ファイルなのでチェックを継続
         'object ノード取得
         Set den = xGetDXL_FirstNodeByName(denItem, "object")
         If Not (den Is Nothing) Then
            'file ノード取得
            Set den = xGetDXL_FirstNodeByName(den, "file")
            If Not (den Is Nothing) Then
               '添付ファイルなので Notes 内部のファイル名取得
               sName = den.GetAttribute("name")
               If LCase(sName) = LCase(vsName) Then
                  'ファイル名一致
                  '戻り値セットしてループ脱出

                  Set xGetDXL_FileItem = den 'file ノード
                  Exit For
               End If
            End If
         End If
      End If
   Next
End Function

object や file ノードの取得は ”最初の子ノード” というような単純な取得ではなく、xGetDXL_FirstNodeByName 関数を利用して検索しています。また、ノードが見つからないときは、次のフィールドに進むようになっています。

$FILE フィールドは、添付ファイル以外にも利用されるようなので、それに備えています。


メインプログラム

これで必要な関数がそろいました。エージェントの本体、Initialize の処理を修正します。

作成した xGetDXL_FirstAttachment 関数をコールして Body フィールド内の最初の添付ファイルを取得します。戻り値は、添付ファイル名です。

Sub Initialize
   Dim ndb As NotesDatabase
   Dim ndc As NotesDocumentCollection
   Dim nd As NotesDocument

   '処理対象の文書を取得
   Set xns = New NotesSession
   Set ndb = xns.CurrentDatabase
   Set ndc = ndb.UnprocessedDocuments
   Set nd = ndc.GetFirstDocument()

   '画像データの取得
   Dim nst As NotesStream '添付ファイル
   Dim sName As String 'ファイル名

   If Not(nd Is Nothing) Then
      'フィールドの内の最初の添付を取得
      sName = xGetDXL_FirstAttachment(nd, "Body", nst)

      If sName <> "" Then
         '取得できたらファイルとして保存
         Call StreamToFile(nst, "c:\tmp\" & sName)
      End If
   End If
End Sub

添付ファイルが取得できたら(= sName に値がある)、保存処理を行います。nst にファイルの中身が NotesStream オブジェクトとして入っているので、StreamToFile 関数で保存します。

Sub StreamToFile(vnst As NotesStream, ByVal vsFP As String)
   Dim nstOut As NotesStream

   On Error Resume Next
   Kill vsFP '存在してたら削除

   Set nstOut = xns.CreateStream()
   Call nstOut.Open(vsFP)

   vnst.Position = 0
   Do Until vnst.Position >= vnst.Bytes
      Call nstOut.Write(vnst.Read(16000))
   Loop
End Sub

この関数、どこかで見たことがありますね。

#9 で作成し、今回もとにしたエージェント #42 でも利用したダウンロードした画像をファイルとして保存する StreamToImageFile 関数です。今回は画像ではないので "Image" とった名前にしています。

関数の機能としては、画像に特化していません。初期段階で命名を失敗したということですね...


前回 DXL Step-by-Step


0 件のコメント:

コメントを投稿