XML即extensibe markup language的縮寫,也就是可擴展標識語言。由於其開放性,越來越多的軟件採用它作爲描述語言;由於其平臺無關性,越來越多的系統採用它作爲數據傳遞中介。計算機行業已經把XML爲數據交換的標準,並提供了相當數量的支持工具。但是,C++中解析xml還依然不夠完美,特別是對於中文字符集的支持。大家總是遇到各種問題,本文改進了OPENCV的XML讀寫函數,支持中文字符串。
在OPENCV開發包中,存在着讀寫XML的一系列函數,雖然並不完善,有些功能還有欠缺。但是,比起動輒幾兆的XML讀寫開發包(如Xerces-C++),它容易使用,代碼量小。對於在計算機視覺研究過程中的數據交換任務,這些簡單IO函數基本足夠了。唯一可惜的是,它目前不支持中文,在某些需要中文字符串的場合,有些遺憾。能不能通過簡單的修改,讓它支持中文?作者做了如下試驗,修改方法簡單可行!
首先,分析cxpersistence.cpp中的函數,發現只需要修改一處就能夠讓XML系列函數支持中文[2]。也就是檢測字符C是否可打印的宏cv_isprint。即將:
#define cv_isprint(c) ((signed char)(c) >= (signed char)' ')
替換爲
#define cv_isprint(c) ((unsigned char)(c) >= 0x20 )
經過一系列測試,發現這樣的修改是可行的。在debug版完全正常,可是,當用release發佈時。VC罷工了,編譯的程序進入類似死循環的狀態。接着,進入漫長的release版本和debug版本的剖析分析[3]。本文來自:http: //www.shenlejun.cn.
最終,得到結論:DEBUG版和RELEASE版的區別,是cxpersistence.cpp中的XML解析函數用到的isdigit(),isalpha(),isalnum(),isspace()等C庫函數,其DEBUG版和RELEASE版的行爲居然不一樣。解決這些問題的途徑很多,最簡單的方法就是,將cxpersistence.cpp中所有的
char c
替換爲
unsigned char c
通過上述2處修改,OPENCV的XML讀寫函數,完全支持中文(包括簡體和繁體)了。呵呵!
測試程序如下:本文來自:蜜蜂電腦.
int sub_test_opencv_xml_write(void)
{
// 創建文件存儲對象
CvFileStorage *fs=cvOpenFileStorage("test.xml",0,CV_STORAGE_WRITE);
// 寫註釋
cvWriteComment(fs,"測試寫XML文件",1);
// 開始寫結構,類型是圖map,也就是有名字的無序節點集合
cvStartWriteStruct(fs,"Employee",CV_NODE_MAP);
// 註釋
cvWriteComment(fs,"MAP類型,姓名,年齡,薪水",1);
// 姓名
cvWriteString(fs,"name","劉越");
// 年齡
cvWriteInt(fs,"age",18);
// 薪水
cvWriteReal(fs,"salary",2780.3);
// 銷售次數
cvWriteInt(fs,"sales_count",4);
{
// 銷售具體數據
int sales_record[]={30000,4200,50090};
// 註釋
cvWriteComment(fs,"SEQ類型,銷售記錄",1);
// 開始寫結構,類型是序列sequence,無名字的有序節點集合
cvStartWriteStruct(fs,"sales_record",CV_NODE_SEQ);
// 前3條銷售記錄
cvWriteRawData(fs,sales_record,3,"i");
// 第4條銷售記錄,注意無名字
cvWriteInt(fs,0,6100);
// 結束
cvEndWriteStruct(fs);
}
{
// 註釋
cvWriteComment(fs,"MAP類型,親友",1);
// 開始
cvStartWriteStruct(fs,"Parent",CV_NODE_MAP);
// 父親
cvWriteString(fs,"father","楊舜");
// 母親
cvWriteString(fs,"mother","王娟");
// 結束
cvEndWriteStruct(fs);
}
// 結束
cvEndWriteStruct(fs);
// 釋放文件存儲對象
cvReleaseFileStorage(&fs);
}
int sub_test_opencv_xml_read(void)
{
// 文件節點
CvFileNode * node, *node2;
char * str;
int count;
int * d;
//cve_dm.debug_break();
// 打開XML文件
CvFileStorage *fs = cvOpenFileStorage("test.xml",0,CV_STORAGE_READ);
// 獲得第一層數據節點
node = cvGetFileNodeByName(fs,0,"Employee");
str = cvReadStringByName(fs,node,"name");
printf("/n姓名=%s",str);
printf("/n年齡=%d",cvReadIntByName(fs,node,"age"));
printf("/n薪水=%g",cvReadRealByName(fs,node,"salary"));
count = cvReadIntByName(fs,node,"sales_count");
printf("/n銷售%d條",count);
d = cvAlloc(sizeof(int)*count);
if(d)
{
int i;
node2 = cvGetFileNodeByName(fs,node,"sales_record");
if(node2)
{
cvReadRawData(fs,node2,d,"i");
printf("/n銷售記錄=");
for(i=0;i<count;i++)
printf("%d, ",d[i]);
}
cvFree(&d);
}
// 獲得第二層節點
node = cvGetFileNodeByName(fs,node,"Parent");
printf("/n根節點=%s",cvGetFileNodeName(node));
str = cvReadStringByName(fs,node,"father");
printf("/n父親=%s",str);
str = cvReadStringByName(fs,node,"mother");
printf("/n母親=%s",str);
}
開發環境: VC6.0 + WINXP。
若您有任何改進建議,請告訴我 ^_^
轉自http://www.shenlejun.cn/my/article/show.asp?id=35,沒試過裏面的方法,只是想拿來分享下,有用的時候再來看看。
參考文獻:
[1]鄒月明, 剖析Xml4C源碼,完美兼容中文XML
[2]ASCII 、GB2312、GBK、GB18030、unicode、UTF-8字符集編碼詳解
[3]Joseph M. Newcomer, Surviving the Release Version