Notes的開發者都很清楚,Notes不像其他程式語言可以將元件個別存成不同檔案,而是將程式邏輯權限資料附檔全都打包成一個NSF檔案,且只有在安裝Notes後才可開啟。
其他語言在一個專案下可以切割成多個檔案維護 |
但最麻煩的,就是把所有程式資料綁在一起,造成切割困難,今天如果要將其中一個表單或一支代理程式分享,也只能打包成一個NSF檔後寄出,收件者再自行複製所需元件至目標資料庫,這過程實在太搞缸了,且在實現單一元件的版本安控來說是個很大的漏洞。
Notes在一個NSF檔中包含了所有的設計元件 |
再則另一個問題,雖然Notes程式對資料的控制十分完備,但對設計元件的控管卻相對荒蕪,除了開啟designer外幾乎別無他法,而造成在設計時的彈性不足。
這困擾其實還是有改善空間的。為了加強對設計元件的控制,Notes很早就推出DXL(Domino xml language),以XML為資訊交換的標準格式,進而加強了對文件及設計元件的新增修改功能,如前所提,文件控管其實沒有太多額外需求,所以我們將重心放在設計元件。
白話的說法就是,在程式執行時,要如何視需要而動態地新增agent、form、view甚至field。
首先在安裝Notes時,在安裝目錄下,lotus/notes/xmlschemas的資料夾路徑,便已包含了各個版本副檔名為.dtd的定義檔和.xsd的schema檔,這存放路徑的名稱便已透露了玄機,包含的是安裝版本以降的所有版本定義檔,在解析XML檔案時的前提就是,解析時的版本至少要高過匯出DXL時的版本,才能有對應的定義檔。這定義檔和Schema中所存放的,就是判別及解讀匯出的DXL的結構及定義。
所以,正確的程序是,將要增加或修改的設計元件匯出為DXL格式,再將此DXL經由對應的DTD判讀後匯入,產生新的Notes設計元件。
範例為版本8.5.2,若版本為9.0.1則會包含9.0.1, 9.0, 8.5.3的版本 |
在這我們至少就碰到二個課題。該如何匯出DXL,以及該如何將DXL匯入。
我先假意地誇讚Notes,它貼心地提供了便利的匯出DXL工具,見下圖,以DXL匯出器直接匯出,以後如果有Notes只交付部分元件時,多了另一種選擇,可以直接傳送單一檔案供換版者匯入。
但接下來又引發了幾個問題,接收者該用什麼工具匯入DXL?以及最小的元件單位為何?這就算是敗筆了。Notes並未提供匯入工具,且最小匯入單位僅為表單(form)。Notes雖然沒有提供匯入工具,但好在不管是用Java或LS,都不是太困難,且若要動態新增或修改時,也不可能是由designer手動匯入,所以除非是如前面所提的,要將部分元件匯出再轉入,否則就算有匯入工具,大多也只是感受上的問題。
DXL的類別主要就是NotesDXLExporter和NotesDXLImporter二個Class,分別為匯出及匯入,至於parser則是NotesDOMParser及NotesSAXParser,差別在DOM將整份XML一次Load並暫存於記憶體來存取,效能自然比逐行循序讀取的SAX要高些,但還得視產出的XML檔案大小,來決定效能或資源之間的取捨。而DXL匯入的關鍵在,
Set importer = session.CreateDXLImporter(stream, db)
importer.Process
Set importer = session.CreateDXLImporter(stream, db)
importer.Process
但匯出匯入讓人頭疼的重點肯定不在Code,而是若不使用Exporter時,該如何產生DXL檔?
提個簡單的範例,
這個簡單的表單,包含Form和Description_1二個欄位和一個TEST按鈕。我們試著如上面的DXL匯出器,可以得到以下的DXL檔案結果。
斷行整理一下(或可直接以browser開啟更容易閱讀),第一行代表了XML的宣告和編碼,接著<!DOCTYPE>是指定引用的DTD,用來規範及解讀匯出匯入的DXL檔案,如果在匯出和匯入有版本差異時,可以在此去修改解讀的DTD檔案版本。
宣告後的部份是Notes DB的屬性,有些無法以程式達成的DB屬性變更,也都可以在匯入DXL時直接取代。粗框圍起來的地方代表的是Notes的表單內容,全都包含在<body>和<richtext>的標記中。裡面的三個細框,分別是Form 和Description_1欄位,以及TEST按鈕。
而我現在想做手腳的是Description_1列,假設在匯出時,把Description依實際需求變動的狀況,動態產生新欄位XML
Tag,Description_2欄位,如下圖。
接著再將此DXL欄案匯入,重新在Designer裡去開啟表單,會發現有些變化,多了一個Description_2的欄位了。
執行匯入後表單產生新的欄位Description_2 |
匯入時要小心的是,DXL匯入時是以NoteID為Key去取代,執行匯入時,並不會像Designer一樣貼心地提示將產生衝突文件,或因相同名稱而產生備存元件,而是毫不留情地立即取代現有的表單。這是因為DXL新增元件只能到表單,而不是欄位。但我們可以應用此方法,在XML對應欄位的地方,用程式加以判斷來新增欄位的XML tag,要幾個欄位就在DXL中加幾個tag。
甚至在選擇產生新元件的部份,做個彈性的選項專用的子表單,讓使用者不需透過Designer,決定要新增幾個欄位、欄位名稱為何、欄位屬性,又或者更擴大範圍,可以決定新增或修改哪些View、呈現哪些Column、表單、頁面、子表單、共用欄位。。。等。這些在web上原本就能夠以HTML輕易達成,但HTML上的欄位只是個愰子,並不真的具備Notes的元件屬性,更別提Notes Client了。
Notes的欄位,就可以想成是HTML 的欄位,在迴圈中的
|<input type="text" name="Field_| + CStr(i) + |" value=.......
再加上能彈性地對應資料庫中的欄位Field_1, Field_2, Field_3.....等的綜合結論,這樣看來是不是就覺得比較厲害些?而這目標能以DXL輕易達成。
Notes的欄位,就可以想成是HTML 的欄位,在迴圈中的
|<input type="text" name="Field_| + CStr(i) + |" value=.......
再加上能彈性地對應資料庫中的欄位Field_1, Field_2, Field_3.....等的綜合結論,這樣看來是不是就覺得比較厲害些?而這目標能以DXL輕易達成。
但我們的困難仍停留在如何隨心所欲地產生DXL檔案,以人力去比對dtd & xsd來產生DXL肯定會讓人消化不良,但我們可以參考一些簡單的定義及屬性,或更偷懶的方法是,在執行程式前,就先將原生表單(在尚未新增欄位前)先行以匯出器或檢視器做一DXL範本文字串存於Profile中,在程式執行時會先取得文字串,再加上程式判斷而加入欄位的tag,最後再加以XML的收尾,組合成完整的新DXL後,再重新匯入,而匯入後自然就取代了原來的表單。
因為是直接取代,如果重覆執行只會有相同的結果,並不會將變動的元件累加。所以在這表單到底現在已經有幾個欄位了,各是什麼屬性,程式是無法判讀的,必須記錄在Profile中,每次執行時才能夠一再地累加上去,不會永遠都只有一次新增的欄位。
這方法說穿了也挺傻眼,就像魔術被看穿一樣,但做大事不拘小節,拿出來嚇唬人是「挫挫有餘」。當然,這動作也要在點選後、存檔前能即時顯現,才能顯出其高大深遠及氣宇非凡。
可惜,講了半天,我的範例還是失敗了!!!!
所有的理論都能實現,唯獨即時顯現變動的元件這點,若是查看欄位屬性,其實我在Debug狀態可看到,UI已經產生Description_2了,但表單即使關閉再重新開啟欄位也未顯現,問題徵結隱藏在前面提過的,
必須「重新在Designer裡開啟表單」或是「重新開啟資料庫」,設計才會被顯示,如下圖:
再說一次,不是重開文件,而是重新在Designer裡開啟表單,或重新開啟資料庫。
重新在Designer裡開啟表單,或重新開啟資料庫。
這麼機歪所以說了三次,有點無奈,還在思考其他的解決方法。未來有結果再陸續更新。