zzOPENCV XML函数完美支持中文方法

来源:互联网 发布:g76车梯形螺纹编程实例 编辑:程序博客网 时间:2024/05/01 14:55

           

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