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]。
最终,得到结论: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。
若您有任何改进建议,请告诉我 ^_^
参考文献:
[1]邹月明, 剖析Xml4C源码,完美兼容中文XML
[2]ASCII 、GB2312、GBK、GB18030、unicode、UTF-8字符集编码详解
[3]Joseph M. Newcomer, Surviving the Release Version
opencv xml,xml解析,xml c++,xml读写