以文本方式查看主题

-  中文XML论坛 - 专业的XML技术讨论区  (http://bbs.xml.org.cn/index.asp)
--  『 XML基础 』  (http://bbs.xml.org.cn/list.asp?boardid=1)
----  [转帖]用Expat處理你的XML資料(1)  (http://bbs.xml.org.cn/dispbbs.asp?boardid=1&rootid=&id=59934)


--  作者:emmali808
--  发布时间:3/14/2008 12:55:00 PM

--  [转帖]用Expat處理你的XML資料(1)
用Expat處理你的XML資料(1)
By Sam .... 2006/07/07
    當你的程式之間需要傳遞資料時,你會怎麼做?譬如說設定檔資料,使用一個最簡單的型式:
『id := value』
那如果設定值很複雜又有層次呢?我甚至還看過透過網路把整個二進位資料結構memory複製到網路去,由接受端宣告一個一模一樣的資料結構在memcpy......(當然,看到這種程式要我處理我會有想自殺的感覺...)。
其實XML是一個很好的規範,他的可擴充性讓程式可以自己去處理自己要的資料,也不會因為多了一個欄位讓天下大亂(我的世界就處在混亂中...ㄏㄏ)。但是要你面對XML這類的複雜結構時,我想很多人看到就感到害怕吧。還好這個世界甚麼不多,Open Source的library最多...ㄏㄏ,Expat是一個很不錯的XML parser library,原則上他是一個C library,而且可以在許多平台使用(好啦...有win32版本...不過我沒用過),Expat是一個stream導向的parser library,也就是說他會從data buffer一直讀進資料然後遇到不同的狀態改變做不同的處理。
經過一番google搜尋後發現Expat的文章不多,只有看到一篇在xml.com的介紹文章,當然expat也有不少wrapper library,譬如Python、Perl、Tcl、C++....等等,你可以直接去使用你習慣的語言的wrapper。這篇文章只是抱持著研究的精神的小小介紹,這裡我們使用C++語言來實作一個簡單的xml parser吧。
使用Expat很簡單,首先當然你必須include相關的header file,Expat只會將兩個header file放進你的系統,分別是expat.h與expat_external.h(這裡以Expat2.0.0為例)。其實你只要加入expat.h,而expat_external.h會自動被加入。所以當然你必須有:
#include <expat.h>
在你要使用Expat library的程式碼中。因為這裡我使用C++語言,因此我定義一個自己的類別"MyParser"
class MyParser
{
public:
    MyParser(string fname);
    virtual ~MyParser();
}
先不要緊張,這目前是一個do-nothing的類別,我在建構式的地方傳入一個XML檔案名稱的參數,我也將parser的動作在初始階段完成,讓我們看看建構式的內容。Expat需要一個XML_Parser的instance在整個parsing階段,因此我們第一步便要宣告一個XML_Parser然後建立它:
XML_Parser parser;
parser = XML_ParserCreate(NULL);
if (!parser) {
   cout << "create XML_Parser error" << endl;
   return 0;
}
Expat使用callback function來處理狀態改變的動作,所以當你需要對某些tag做處理的時候你必須要設定相關的處理函式,這裡我們只對最簡單的型式做處理,因此我只設定start tag、end tag與default handler:
::XML_SetUserData(parser, this);
::XML_SetElementHandler(parser, expatStart, expatEnd);
::XML_SetDefaultHandler(parser, expatHandler);
你可以使用this指標將自己傳給expat當成UserData;再來我們必須在類別內宣告相關的member function,因此我們的類別便宣告成:
class MyParser
{
public:
   MyParser(string fname);
   virtual ~MyParser();
   static void expatStart(void *data, const XML_Char *el, const XML_Char **attr);
   static void expatEnd(void *data, const XML_Char *el);
   static void expatHandler(void *data, const XML_Char *s, int len);
}
你可以看到為了讓Expat的C library當成callback function我們將其宣告成static的member function,而當你要用類別內的成員變數或函式時,你不能直接呼叫或使用(沒忘記static吧),因此這個時候我們在XML_SetUserData(parser, this)做的動作便派上用場,你可以看到expatStart、expatEnd與expatHandler中第一個不定指標參數void *data便會是你在XML_SetUserData時傳入的第二個參數。因此假設你在這3個callback function中要使用一個類別函式"do_something()"時,你可以這樣做:
((MyParser *)data)->do_something();
這樣一來,我們基本的宣告便完成,可以開始餵資料給XML_Parser了
file = fopen(fname.c_str(), "r");
do {
   len = fread(buf, 1, sizeof(buf), file);
   done = len < sizeof(buf);
   if (!XML_Parse(parser, buf, len, done))
   done = 1;
} while (!done);
::XML_ParserFree(parser);
fclose(file);
當然最後不要忘了釋放掉我們宣告的parser與關閉檔案。一個最簡單的Expat動作流程就是這麼簡單.......待續


--  作者:emmali808
--  发布时间:3/14/2008 12:57:00 PM

--  
先占一下,原文的网址:http://joepasscheng.googlepages.com/expat-1
W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
46.875ms