將Datawindow資料存出成EDI檔案

PowerBuilder 的 DataWindow 本身可以將資料存成許多種格式,但偏偏就是缺了一種格式--EDI (Eletronic Data Interchange)--

這種格式在台灣是早期非常普遍的格式,詳見維基百科經建會-解釋「通關作業XML電子資料交換格式」與EDI格式,主要多是公家機關使用,舉凡報稅、金融皆是使用此一格,久而久之就變成了早期台灣電腦最普遍的資料交換檔案格式。

這個格式的特色是每個欄位呈現在文字檔案中都有指定的長度(位元數),各欄位資料之間無分隔符號。所以每個ROW DATA呈現成一串字串,每個ROW字串的長度完全一樣。當然,這種格式的優缺點並非這篇的重點,所以這裡就不討論。

例如:
假設 CSV 格式的資料如下
黃小明,1978/3/2,台中市中山路120號,0922-222-113,15
李大海,1970/12/14台北市忠孝東路三段41號8樓-5,02-12345678,23

而轉成 EDI 格式就可能如此
黃小明19780302台中市中山路120號             0922-222-113   SIMON           15
李大海19701214台北市忠孝東路三段41號8樓-5   02-12345678    DAVID CHAU      23



所以若要將DataWindow的資料輸出成為EDI的格式,就需要一點技巧了

因此我們設計一個Function,讓它可以自動幫我們存成所需要的EDI格式

先定義一個 Function 名稱 f_ds2edi
迴傳一個 Long
參數兩個:ads_process[datastore][reference]as_filename[string][value]


//////////////////////////////////////////////////////////////////////////////
// Arguments:
// ads_process - datastore for processing
// as_filename - file name for exprot
//////////////////////////////////////////////////////////////////////////////
// Returns: Long
// -1 : failue
// ll_NumsRow : the adding rows
//////////////////////////////////////////////////////////////////////////////

st_Column lst_Column[]
Integer li_NumsColumn, li_Pos, li_no
Long ll_NumsRow, ll_Row
String ls_Value
Integer li_FileNum
String ls_LineWrite
Long ll_RecNum

// Open text file
li_FileNum = FileOpen(as_filename, LineMode!, Write!, LockWrite!, Replace!)
IF li_FileNum = -1 THEN
  RETURN -1
END IF

// Set default column's expression
li_Pos = 1
li_NumsColumn = Integer(ads_Process.Object.Datawindow.Column.Count)
FOR li_no=1 TO li_NumsColumn
  lst_Column[li_no].name = ads_Process.Describe("#" + string(li_no) + ".Name")
  lst_Column[li_no].coltype = ads_Process.Describe("#" + string(li_no) + ".ColType")
  lst_Column[li_no].pos = li_Pos
  lst_Column[li_no].len = Integer(ads_Process.Describe("#" + string(li_no) + ".Edit.Limit"))
  li_Pos += lst_Column[li_no].len
NEXT

// Read from text file
ll_NumsRow = ads_process.RowCount()
ll_RecNum = 0
FOR ll_Row = 1 TO ll_NumsRow
  ls_LineWrite = ''
  FOR li_no=1 TO li_NumsColumn
    IF lst_Column[li_no].len > 0 THEN
      IF left(lst_Column[li_no].coltype, 4) = 'char' THEN
        ls_Value = ads_Process.GetItemString(ll_Row, lst_Column[li_no].name)
        IF IsNull(ls_Value) THEN
          ls_Value = Space(lst_Column[li_no].len)
        ELSE
          IF lst_Column[li_no].len > Len(ls_Value) THEN
            ls_Value = ls_Value + Space(lst_Column[li_no].len - Len(ls_Value))
          END IF
        END IF
      ELSEIF left(lst_Column[li_no].coltype, 4) = 'date' THEN
        ls_Value = String(ads_Process.GetItemDateTime(ll_Row, lst_Column[li_no].name), 'yyyymmdd')
        IF IsNull(ls_Value) THEN
          ls_Value = Space(lst_Column[li_no].len)
        ELSE
          IF lst_Column[li_no].len > Len(ls_Value) THEN
            ls_Value = Space(lst_Column[li_no].len - Len(ls_Value)) + ls_Value
          END IF
        END IF
      ELSE
        ls_Value = String(ads_Process.GetItemNumber(ll_Row, lst_Column[li_no].name))
        IF IsNull(ls_Value) THEN
          ls_Value = Space(lst_Column[li_no].len)
        ELSE
          IF lst_Column[li_no].len > Len(ls_Value) THEN
            ls_Value = Space(lst_Column[li_no].len - Len(ls_Value)) + ls_Value
          END IF
        END IF
      END IF
      ls_LineWrite += ls_Value
    END IF
  NEXT
  ll_RecNum++
  FileWrite(li_FileNum, ls_LineWrite)
NEXT

// Close text file
FileClose(li_FileNum)

RETURN ll_RecNum


照此SCRIPT來實做,要注意的是傳入的 DataStore 設計,該 Function 輸出的欄位順序是 DataStore 的 SQL 裡面定義的欄位順序,並非 painter (設計版面)上設計的欄位排列順序。

另外,每個欄位輸出的長度是定義在每個欄位 properties 裡面 Edit屬性中的 Length ,數值型態的資料欄位輸出也是依照此長度產生,數值欄位特別要注意小數點,因為小數點佔用一個 byte 輸出。如果 length 設定成 0 則該欄位不會輸出任何資料(包含空白)。

這個 SCRIPT 能處理的欄位型態(Data Type)為三種: char、date(包含Date、DateTime)、Number(包含Lont、Integer、Decimal、UnsignedLong、UnsignedInteger......)。
如果需要增加處理資料型態的方式,就要自己增加程式規則了。這一部分可以依照個人資料庫特性結構去調整,你可以把它寫得很完備,並包入PFC中。不過,依照我的作法並不會這樣做,原因在於EDI接收對象的不同,你需要調整的輸出就很多。

就如日期這個欄位來比喻吧。

如果你輸出的資料是要給公家機關(政府機關),就有可能會是 yyy.mm.dd (這個yyy還是民國年!一般的 Convert Format 不會認得這個格式),年、月、日中間要有個『‧』,但是部分機關的格式就不可以有這個『‧』;然若是給銀行的就是標準的 yyyymmdd ,所以這樣輸出差異頗大的,若要做成 PFC 確實可用性就可議了。

另一個變化比較大的就是數值欄位了

例如有的程式接收數直欄位時必須是像 『0000123』 或也有像『    123』這樣的格式,或是『123    』這樣的格式,所以這種欄位也混因為需求不同而發生調整。

所以依照你要輸出對象單位的 EDI 檔案格式來調整這個 Function Script 才是比較實用的方式。

留言

這個網誌中的熱門文章

【研究】列印的條碼為什麼很難刷(掃描)

統一發票列印小程式

C# 使用 Process.Start 執行外部程式