摘要:介紹一種依托數(shù)據(jù)庫技術,以表格定義和表格生成相分離為設計原則的通用表格生成系統(tǒng),通過讀取數(shù)據(jù)庫中的表格定義,即可自動生成所需表格。
關鍵詞:表格描述信息表;表格通用生成程序
中圖分類號:TP311.52 文獻標識碼:A 文章編號:1007-9599 (2012) 17-0000-02
在許多軟件的開發(fā)中,經(jīng)常有生成各種各樣表格的需求。為了實現(xiàn)這一需求,常用的方法是:先在電子表格軟件(如EXCEL)中生成表格模板,然后在軟件中針對每張表格編寫一段程序,有幾張表格,就編寫幾段程序,把需要的數(shù)據(jù)寫入相應的表格模板,最終生成所需的表格。由于表格的繪制工作通過電子表格軟件完成了,所以這種方法大大地減少了生成表格的工作量,加快了軟件的開發(fā)進度。
如果軟件所需要生成的表格比較少,用上述的方法沒有什么大問題。但是,當所需要生成的表格比較多時,情況就有所不同了。由于軟件中各表格的生成模式一般是相同的,但各表格的格式又各不相同,所以各表格的生成代碼基本上是結構相同或相似,但是具體代碼又各有相異。因此,編寫第二張表格或更后面表格的生成代碼時,為了減少工作量,通常的做法是把前面表格的生成代碼拷貝過來,然后再加以修改;甚至可能是直接把以前所編寫軟件中的表格生成代碼拷貝過來,加以修改后用于本軟件的表格生成。這就產(chǎn)生了如下的一些問題:1.修改代碼時容易漏掉需要修改的語句。2.如果做為母版的代碼中存在錯誤,修改時凡是拷貝了這個母版的代碼段都要加以修改。3.盡管各表格的生成代碼類似甚至基本相同,但是每增加一張表格,該表格的生成代碼仍然需要進行調(diào)試并可能需要加以修改,從而增加了工作量。
本文所介紹的通用表格生成系統(tǒng)正是為了試圖解決上述問題而開發(fā)的。該系統(tǒng)的設計思想即:把表格的定義和表格的生成相分離。用專門的數(shù)據(jù)庫來保存表格的定義。表格生成程序則從數(shù)據(jù)庫中讀取表格的定義,來生成相應的表格。由于所有表格都使用一個通用的程序來生成,所以代碼只需要編寫調(diào)試一次,修改糾錯時,也只需要修改一次,因此減少了工作量。要增加新的表格時,則只需在數(shù)據(jù)庫中添加表格定義即可, 從而避免了對代碼的修改。
1 需求分析
要生成一個表格,通常需要知道如下的信息:1.表格的格式;2.要填入的數(shù)據(jù)從何而來?填入到表格的哪行哪列?3.數(shù)據(jù)填入前后,是否需要設置表格的樣式(如:繪制表格線等)
上面所需知道的信息中,表格的格式是固定的,可以預先生成表格模板,其它信息則需要在數(shù)據(jù)庫中描述。
2 數(shù)據(jù)庫設計
本系統(tǒng)選擇Microsoft SQLSERVER2000為數(shù)據(jù)后臺(如果需要,也能很方便地改用其它數(shù)據(jù)庫管理系統(tǒng)),并根據(jù)上述的需求分析,設計了本系統(tǒng)的數(shù)據(jù)庫結構。
2.1 表格描述信息表設計
本表的每條記錄描述一表格區(qū)域的信息,該區(qū)域可能是一個表格單元,也可能是一行或一列表格單元,還可能是多行或多列表格單元。所包含的字段為:記錄號、模板文件名、數(shù)據(jù)來源、記錄類型、行列表、列列表、最大行列表、跳轉(zhuǎn)行列表、分割符、序號、標識符。各字段的含義見下。
記錄號(ID):用于確定記錄的讀取順序,不可為空,表格生成時,根據(jù)記錄號從小到大讀取記錄。
模板文件名(MBn):表示當前表格區(qū)域所屬的表格模板文件的名字,不可為空。
數(shù)據(jù)來源(SQLStr):表示當前表格區(qū)域中的數(shù)據(jù)從哪里獲取,如果是從數(shù)據(jù)庫中獲取,本字段的內(nèi)容為一SQL語句(如:select xj,, is1(duty,'') as duty from usertab where gh='$gh$',$gh$表示該處的值將在表格生成時用gh的實際值替換,之所以字段列表的分隔符使用“,,”,是因為程序中需要提取所要查詢的字段,為了提取時不與可能用到的函數(shù)的參數(shù)列表的分隔符相混淆,所以用“,,”替代了“,”);如果是表格生成時直接指定的(如:表格生成日期、制表人等),則本字段為空。
記錄類型(Type1):表示當前表格區(qū)域的范圍(one、more或其它)。one表示單行或單列;more表示多行或多列;除了one、more以外的其它值(其格式如:$year$年)都代表當前表格區(qū)域為單個表格單元,且其值將在表格生成時用相應變量的實際值替換。
行列表(Rows1)、列列表(Cols1):這兩個字段配對使用,表示當前表格區(qū)域首行或首列的行、列坐標。這兩個字段以“jd,”或“xd,”起始,jd表示后面的坐標為絕對坐標,xd表示后面的坐標為相對坐標(即相對于上一個被填寫的表格單元)。后跟坐標的格式為“x1,x2,x3,…”,其中的各項既可以是一個數(shù)字,也可以是諸如”n:m”、“n-m”的形式, “n:m”表示坐標為m個n;“n-m”表示共m-n+1個坐標,依次為n到m。比如行列表為“jd,7:5“、列列表為“jd,1,3-5,7”時,表示所要填寫的表格單元的行、列位置依次為(7,1)、(7,3)、(7,4)、(7,5)和(7,7); 上一記錄最后填寫的表格單元的行、列位置為(5,10)、行列表為“xd,10,0,0”、列列表為“jd,7-9”時,表示所要填寫的表格單元的行、列位置依次為(15,7)、(15,8)、(15,9)。
最大行列表(MaxR)、跳轉(zhuǎn)行列表(StR):這兩個字段配對使用,適用于如下一種情況——從數(shù)據(jù)庫讀取了多條記錄,逐行填入表格中時,當前頁填不完,需要填到下頁,而下頁又有頁頭,因而不能從下頁的首行開始填入。比如最大行列表為“13,26”,跳轉(zhuǎn)行列表為“16,29”時,表示當填寫到第14行時,需要跳到第16行開始填寫;當填寫到27行時,則跳到29行開始填寫。
分割符(FGf)、序號(ZCh):這兩個字段配對使用,適用于如下一種情況——需要填入的數(shù)據(jù)沒有單獨存在于數(shù)據(jù)庫中。比如,希望獲得的數(shù)據(jù)是“bb”,但數(shù)據(jù)庫中并沒有設計字段來保存這一數(shù)據(jù),而是以“aa:bb:cc:dd”的格式把多個相關數(shù)據(jù)保存在一個字段中,為了能夠在表格生成時獲得正確的數(shù)據(jù),就需要設置分割符為“:”,設置序號為“1”。
標識符(Mark1):表示當前記錄處理時,需要調(diào)用表格模板所帶的宏來設置表格的格式。表格生成時,會帶有一個宏列表參數(shù),該列表的關鍵字即為本處定義的標識符。
3 系統(tǒng)各主要函數(shù)的實現(xiàn)
3.1 主函數(shù)
3.1.1 函數(shù)入口
string CreateTab(mydb dbs,mydb db1, string mbpath, string mbsheet, string tabn, string newn,Hashtable ht_const,Hashtable para1,Hashtable ac1,CallF func1,ArrayList funcArr)。
3.1.2 函數(shù)入口參數(shù)
(1)dbs:連接到表格描述數(shù)據(jù)庫(mydb是一個數(shù)據(jù)庫連接類)。(2)db1:連接到表格數(shù)據(jù)來源數(shù)據(jù)庫。(3)mbpath:表格模板文件路徑名。(4)mbsheet:模板文件中相應工作表的名字。(5)tabn:表格定義描述數(shù)據(jù)庫中相應數(shù)據(jù)表的名字。(6)newn:所生成表格的路徑名。(7)ht_const:用于傳入記錄類型字段中所定義變量的實際值,其關鍵字為記錄類型字段中定義的變量,對應的值為該變量的實際值,本參數(shù)可以為空。(8)para1:用于傳入數(shù)據(jù)來源字段中所定義變量的實際值,其關鍵字為數(shù)據(jù)來源字段中定義的變量,對應的值為該變量的實際值,本參數(shù)可以為空。(9)ac1:用于傳入需要用到宏的名字及參數(shù),其關鍵字為標識符字段設置的標識符,對應的值為一個Hashtable變量action。action所含的關鍵字為before、after1、after2和record中的1個或多個,這些關鍵字所對應的值為1個string[]類型的數(shù)組,該數(shù)組的第1個元素是宏名,后面的元素是該宏所帶的參數(shù)。before所對應的宏在當前被填寫行滿足跳轉(zhuǎn)條件,跳轉(zhuǎn)到指定行進行填寫前執(zhí)行(比如在填寫前需要設置一下格式);after1所對應的宏在當前記錄處理完畢,但當前被填寫行小于或等于最大行列表中某項時執(zhí)行(比如預先在模板中設置了格式,現(xiàn)在由于數(shù)據(jù)比較少,無需跳轉(zhuǎn)到下頁,所以需要清除多余的格式);after2所對應的宏在當前被填寫行等于最大行列表中某項時,在當前行填寫完畢后執(zhí)行(比如把當前頁的格式復制到下頁);record所對應的宏在當前被填寫行滿足跳轉(zhuǎn)條件,跳轉(zhuǎn)到指定行后執(zhí)行,執(zhí)行后在下行進行填寫(比如跳轉(zhuǎn)后要增加一行列標題)。本參數(shù)可以為空。(10)func1:指向一個預先定義的函數(shù),該函數(shù)在表格生成完畢后運行,進行一些收尾工作(CallF是一個函數(shù)代理,其定義為delegate string CallF(Excel.Worksheet sheet1,ArrayList ar1)) ,本參數(shù)可以為空。(11)funcArr:如果func1不為空,本參數(shù)為func1所調(diào)用的參數(shù),本參數(shù)可以為空。
3.1.3 函數(shù)主要流程:獲取tabn表中MBn字段為相應模板文件名的所有記錄,并調(diào)用表格填寫函數(shù)ProcRec處理每條記錄。
3.2 表格填寫函數(shù)
3.2.1 函數(shù)入口
string ProcRec(db.mydb db1, Excel.ApplicationClass app1, Excel.Worksheet sheet1, System.Collections.Hashtable ht1, Hashtable ht_const, Hashtable para1, Hashtable ac1,ref int curR,ref int curC)
3.2.2 函數(shù)入口參數(shù)
(1)app1:指向所調(diào)用Excel對象的引用。(2)sheet1:指向模板文件工作表的引用。(3)ht1:指向保存表格描述數(shù)據(jù)表中當前記錄內(nèi)容的集合。(4)curR:表格當前填寫位置的行號,本參數(shù)同時用于把經(jīng)過本函數(shù)運行后調(diào)整過的當前行號傳出。(5)curC:表格當前填寫位置的列號,本參數(shù)同時用于把經(jīng)過本函數(shù)運行后調(diào)整過的當前列號傳出。(6)db1、ht_const、para1、ac1:這幾個參數(shù)的含義同主函數(shù)的同名入口函數(shù)。
3.2.3 函數(shù)主要流程:從ht1中提取當前記錄各字段的內(nèi)容,用para1中的實際值替換SQLStr字段中的偽變量,根據(jù)Type1字段的內(nèi)容確定表格的填寫方式。
4 結束語
本系統(tǒng)的開發(fā)目的,是想通過把表格的定義和表格的生成相分離,使得程序員在開發(fā)中需要輸出表格時,可以專注于表格的定義,而不用去考慮表格的具體生成,從而以對數(shù)據(jù)庫表記錄的添加修改,來替代程序代碼的編寫調(diào)試,因而減少了程序員的開發(fā)工作量。尤其是需要生成的多張表格格式相同或相近,僅內(nèi)容不同時,使用本系統(tǒng)更是能節(jié)省許多開發(fā)時間、極大地提高開發(fā)效率。
參考文獻:
[1](美)Christian Nagel、Bill Evjen、Jay Glynn等著,李敏波譯,黃靜審校, Professional C# 2005(C#高級編程)(第4版)北京:清華大學出版社,2006.10.
[2[Excel之家編著,Excel實戰(zhàn)技巧精粹 北京:人民郵電出版社,2007.3.
[3]王冠著,SQL查詢語言及應用 北京:科學出版社,1999.6.
[4]楊中科著,程序員的SQL金典 北京:電子工業(yè)出版社,2008.9.