辛懷聲 王鵬
摘要:在開(kāi)展數(shù)據(jù)處理和數(shù)據(jù)分析的工作前,常常需要對(duì)采集的原始數(shù)據(jù)進(jìn)行解析處理,常規(guī)的方法是針對(duì)大量的數(shù)據(jù)接口分別開(kāi)發(fā)解析代碼,這樣做不僅工作量大,代碼冗余度高,日后對(duì)接口進(jìn)行修改或添加時(shí)都需要同步修改解析程序的相應(yīng)代碼,給數(shù)據(jù)分析處理工作帶來(lái)極大的困難。為了有效解決這一問(wèn)題,該文提出了一種基于XML的數(shù)據(jù)解析方法,實(shí)現(xiàn)接口定義和程序編碼的隔離,能夠在不改動(dòng)程序代碼情況下,實(shí)現(xiàn)數(shù)據(jù)接口的按需添加或修改,有利于節(jié)約后期針對(duì)解析程序的開(kāi)發(fā)和維護(hù)成本。
關(guān)鍵詞:XML;數(shù)據(jù)解析;隔離;接口
中圖分類號(hào):TP319 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2014)01-0057-03
1 概述
在日常軟件工程中為了優(yōu)化或者增加新功能往往需要對(duì)數(shù)據(jù)接口進(jìn)行修改或刪減。這時(shí)數(shù)據(jù)記錄設(shè)備記錄下來(lái)的數(shù)據(jù)格式也會(huì)隨之發(fā)生改變。對(duì)于事后的數(shù)據(jù)分析處理工作來(lái)說(shuō),這意味著數(shù)據(jù)解析的開(kāi)發(fā)工作會(huì)伴隨著數(shù)據(jù)接口的改變而一直進(jìn)行。經(jīng)常出現(xiàn)的一種情況就是進(jìn)行數(shù)據(jù)解析時(shí)程序報(bào)錯(cuò),進(jìn)行錯(cuò)誤定位之后發(fā)現(xiàn)是數(shù)據(jù)格式發(fā)生了變化,于是需要對(duì)相應(yīng)的數(shù)據(jù)接口進(jìn)行代碼開(kāi)發(fā)或更改,這給數(shù)據(jù)解析工作帶了很大的不便,降低了數(shù)據(jù)分析的效率,也加大了數(shù)據(jù)解析和分析出錯(cuò)的幾率。
2 解決辦法
可擴(kuò)展標(biāo)記語(yǔ)言(Extensible Markup Language, XML)是一種用于描述數(shù)據(jù)與平臺(tái)無(wú)關(guān)的語(yǔ)言,以一種開(kāi)放的自我描述方式定義數(shù)據(jù)結(jié)構(gòu),在描述數(shù)據(jù)內(nèi)容的同時(shí)突出對(duì)結(jié)構(gòu)的描述,是一種存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)的規(guī)范[1-2]。XML是一種元標(biāo)記語(yǔ)言, 可以用來(lái)定義其他的標(biāo)記語(yǔ)言, 并且這些標(biāo)記語(yǔ)言的元素標(biāo)記是由用戶自己定義的。所以由XML可以派生出無(wú)限多種標(biāo)記語(yǔ)言。在這些標(biāo)記語(yǔ)言必須根據(jù)一定得規(guī)則來(lái)定義和組織,但是這些標(biāo)記在其含義上是非常靈活的[3]。
本文使用XML對(duì)接口數(shù)據(jù)進(jìn)行映射,不在程序代碼中對(duì)數(shù)據(jù)接口進(jìn)行“硬編碼”,之后針對(duì)XML生成文件解析指令序列,最后按照指令序列對(duì)數(shù)據(jù)文件進(jìn)行解析,把解析程序代碼與接口定義進(jìn)行隔離,從而使數(shù)據(jù)接口的更改對(duì)解析程序代碼的影響降到最低。
3 程序設(shè)計(jì)
3.1 XML與數(shù)據(jù)結(jié)構(gòu)映射
待解析的數(shù)據(jù)都是由網(wǎng)絡(luò)報(bào)文記錄而成的二進(jìn)制文件,報(bào)文內(nèi)容如圖1所示。
如圖1所示,最前面的數(shù)據(jù)是消息代碼,用來(lái)標(biāo)識(shí)消息類型,之后是消息長(zhǎng)度,用來(lái)標(biāo)識(shí)消息之間的邊界位置。通過(guò)這兩個(gè)值我們可以識(shí)別和解析數(shù)據(jù)文件中的所有二進(jìn)制數(shù)據(jù)的內(nèi)容。對(duì)于上述數(shù)據(jù),我們可以用數(shù)據(jù)結(jié)構(gòu)(struct)或類(class)來(lái)進(jìn)行抽象。如下面C++代碼所示:
struct Header
{int messagetype;
int length;
char spare[4]
};
struct DataTypeA
{Header head;
int A;
int B
};
接口數(shù)據(jù)類型DataTypeA包括了消息頭結(jié)構(gòu)和消息體數(shù)據(jù)A和B。消息頭包括了消息類型消息長(zhǎng)度和一些其他數(shù)據(jù)以及保留數(shù)據(jù)空間。
進(jìn)一步可以用XML對(duì)其進(jìn)行表示,如下所示:
<?xml version="1.0" encoding="utf-8"?>
上面的XML中ID表示數(shù)據(jù)項(xiàng)名稱。Array表示是否為數(shù)組,如果Array的值是1,則表示單個(gè)數(shù)據(jù)項(xiàng),如果大于1,則表示一個(gè)數(shù)組。Style表示是否為嵌套的數(shù)據(jù)結(jié)構(gòu),如果值為“element”表示不是數(shù)據(jù)結(jié)構(gòu),如果值為“structure”則表示是數(shù)據(jù)結(jié)構(gòu),需要從XML中另行查找它的具體定義。 從上面XML中可以看出,這里定義了兩類數(shù)據(jù)結(jié)構(gòu),一類是HEADER數(shù)據(jù)結(jié)構(gòu),另一類是DataTypeA數(shù)據(jù)結(jié)構(gòu),而DataTypeA數(shù)據(jù)結(jié)構(gòu)又嵌套了HEADER數(shù)據(jù)結(jié)構(gòu)。這與前面的C++代碼是一致的。通過(guò)上面的步驟,我們建立了一種二進(jìn)制接口數(shù)據(jù)到XML的映射。
3.2 文件解析指令序列
對(duì)數(shù)據(jù)接口進(jìn)行XML映射之后,程序代碼就可以與具體的數(shù)據(jù)接口定義進(jìn)行隔離了,從而實(shí)現(xiàn)數(shù)據(jù)接口變化不影響程序代碼的目標(biāo)。為了實(shí)現(xiàn)程序代碼與數(shù)據(jù)接口隔離,程序?qū)⒏鶕?jù)XML文件的內(nèi)容生成一系列的數(shù)據(jù)解析指令。 這里的指令序列指的是由一系列文件讀取的長(zhǎng)度和數(shù)據(jù)類型組成的序列,如下表1所示:
表1 數(shù)據(jù)解析指令序列
[接口類型\&數(shù)據(jù)名稱\&數(shù)據(jù)類型\&DataTypeA\&MESSAGE_TYPE\∫\&MESSAGE_LEN\∫\&MESSAGE_SPARE\&char\&MESSAGE_SPARE\&char\&MESSAGE_SPARE \&char\&MESSAGE_SPARE\&char\&A\∫\&B\∫\&]
之后我們就可以根據(jù)上述指令序列對(duì)待解析的文件進(jìn)行解析讀取。
3.3 XML文件處理流程
為了生成文件解析指令序列,我們需要對(duì)XML文件進(jìn)行處理。XML文件的處理流程如下圖2所示,首先讀取DataTypeA對(duì)應(yīng)的XML文件,然后定位到定義DataTypeA的節(jié)點(diǎn),之后循環(huán)處理DataTypeA的子節(jié)點(diǎn)。處理過(guò)程是:如果該子節(jié)點(diǎn)為簡(jiǎn)單數(shù)據(jù)類型,則將該節(jié)點(diǎn)中的數(shù)據(jù)類型信息和數(shù)據(jù)名稱加入解析指令序列;如果該節(jié)點(diǎn)表示的是一個(gè)數(shù)據(jù)結(jié)構(gòu)則啟動(dòng)遞歸過(guò)程找到定義該數(shù)據(jù)類型的節(jié)點(diǎn),并重復(fù)與DataTypeA相同的處理過(guò)程,直到處理完所有DataTypeA的子節(jié)點(diǎn)為止。
3.4 文件數(shù)據(jù)解析流程
生成了接口數(shù)據(jù)類型對(duì)應(yīng)的文件解析指令序列后,我們可以根據(jù)文件解析指令序列對(duì)文件進(jìn)行解析。順序讀取解析指令,根據(jù)數(shù)據(jù)類型決定調(diào)用的文件讀取函數(shù)。例如:如果當(dāng)前一條文件讀取指令指示的數(shù)據(jù)類型為char,我們就可以調(diào)用相應(yīng)的類似ReadChar()之類的函數(shù)(由用戶的變成語(yǔ)言確定);如果指示的數(shù)據(jù)類型為float,我們就可以調(diào)用類似ReadFloat()之類的函數(shù)。流程如圖3所示。
4 結(jié)束語(yǔ)
由于大多數(shù)編程語(yǔ)言都對(duì)XML處理提供了強(qiáng)大的處理函數(shù),該文介紹的利用XML文件映射接口數(shù)據(jù),之后再解析數(shù)據(jù)的方法可以用于大部分編程語(yǔ)言環(huán)境。本方法使程序代碼與接口定義解除耦合關(guān)系,做到了新定義接口或修改后的接口的“即插即用”,無(wú)需針對(duì)接口的修改對(duì)解析程序進(jìn)行修改和重新編譯,提高了數(shù)據(jù)解析的工作速度和正確率。
參考文獻(xiàn):
[1] 甘小斌.XML標(biāo)準(zhǔn)體系介紹[J].信息技術(shù)與標(biāo)準(zhǔn)化,2004(9): 41-44.
[2] 陳春詠.基于XML的指揮自動(dòng)化輔助決策系統(tǒng)研究[D].南京:東南大學(xué),2007.
[3] 懷石工作室.XML完全手冊(cè)[M].北京:中國(guó)電力出版社,2000.