phpwap

C++博客 联系 聚合 管理
  0 Posts :: 4 Stories :: 0 Comments :: 0 Trackbacks

tinyXml的特点是不对xml节点内容的具体编码处理,这一切都交给用户。因此tinyXml和字符有关的函数都是只接受char*的数据类型。
例如:

1 TiXmlElement *pRoot=new TiXmlElement("test");
2 pRoot->SetAttribute("name","名字");

上述代码产生的节点,如果用TiXmlDocument的SaveFile函数直接保存,只能是ANSI的本地编码(无论程序是否是 unicode),即使TiXmlDeclaration指定为utf-8。一种方法是输出到TiXmlPrinter,将 TiXmlPrinter.CStr()转换到utf-8编码的char*后保存。

char*在双字节编码下是一种很奇特的字符串,中文平台下的VC的编译器,char*可以存放GBK汉字,编译能正确识别字符,因为ASCII码的最高位为0,而GBK双字节字符的首字节最高位为1。

在使用utf-8字符串时,必须树立一个观念:utf-8应当只在传输时使用,不适合作为函数过程的处理对象。什么是传输场合?网络传输和文件读 写。以文件读写为例,文件以utf-8编码存放,在读入到内存后,应当立刻转换为unicode宽字符串。程序的内部处理过程中只有unicode宽字符 串。直到写入文件时,unicode宽字符串才转换为utf-8字符串。

utf-8字符串本身是变长字符串,并没有特定的数据类型。它是以char*形式存放,它的byte的表现不符合任何双字节编码,当成双字节编码处 理会立刻出错。事实上,char*只是一个存放空间,用void*、unsigned char*本质上没有区别。(倘若你喜欢,甚至可以拿char*来存放unicode宽字符串,一次memcpy两个byte就是了)。

脱离双字节编码(如GBK)的tinyXml使用方法是存在的。
例如上述代码可以改为:

1 TiXmlElement *pRoot=new TiXmlElement("test");
2 CStringA UTF8Str=CW2A(L"名字",CP_UTF8);
3 pRoot->SetAttribute("name",UTF8Str);

UTF8Str变量名即是内含的char*字符串的起始指针。CW2A函数可以自己写一个代替,并不难实现。此时可以直接调用 TiXmlDocument的SaveFile函数保存为无BOM的UTF-8文档。要保存为含BOM的UTF-8文档,仍然需要 TiXmlPrinter,但此时不需要对TiXmlPrinter.CStr()进行任何处理。

01 XmlEntityTree=new TiXmlDocument;
02 TiXmlDeclaration *dec=new TiXmlDeclaration("1.0","utf-8","");
03 XmlEntityTree->LinkEndChild(dec);
04 TiXmlElement *pRoot=new TiXmlElement("test");
05 CStringA UTF8Str=CW2A(L"名字",CP_UTF8);
06 pRoot->SetAttribute("name",UTF8Str);
07 XmlEntityTree->LinkEndChild(pRoot);
08 TiXmlPrinter printer;
09 XmlEntityTree->Accept(&printer);
10  
11 char UTF8BOM[3]={'\xEF','\xBB','\xBF'};
12  
13 CFile theFile;
14 theFile.Open(_T("test.xml"),CFile::modeCreate|CFile::modeWrite);
15 theFile.Write(UTF8BOM,3);
16 theFile.Write(printer.CStr(),strlen(printer.CStr()));
17 theFile.Close();

tinyXml在加载xml文档时有一个标记,TiXmlDocument.LoadFile(TiXmlEncoding encoding);
这个标记没多大作用,无论设为TIXML_ENCODING_UTF8还是TIXML_ENCODING_LEGACY,读入的节点的数据类型一样是char*。
设为TIXML_ENCODING_UTF8标记的唯一作用是tinyXml会自动处理文档的BOM。

对于下面文档,怎样才能正确读取到TemplateStr节点的内容?很简单,在读取时进行转换就行。

1 <?xml version="1.0" encoding="utf-8" ?>
2 <config>
3     <TemplateStr>中文</TemplateStr>
4     <AutoFixCue>true</AutoFixCue>
5     <AutoFixTTA>true</AutoFixTTA>
6     <AcceptDragFLAC>true</AcceptDragFLAC>
7     <AcceptDragTAK>true</AcceptDragTAK>
8     <AcceptDragAPE>true</AcceptDragAPE>
9 </config>
01 TiXmlDocument *xmlfile= new TiXmlDocument(FilePath);
02 xmlfile->LoadFile(TIXML_ENCODING_UTF8);
03  
04 TiXmlHandle hRoot(xmlfile);
05 TiXmlElement *pElem;
06 TiXmlHandle hXmlHandle(0);
07  
08 //config节点
09 pElem=hRoot.FirstChildElement().Element();
10 if (!pElem) return FALSE;
11 if (strcmp(pElem->Value(),"config")!=0)
12     return FALSE;
13  
14 //TemplateStr节点
15 hXmlHandle=TiXmlHandle(pElem);
16 pElem=hXmlHandle.FirstChild("TemplateStr").Element();
17 if (!pElem) return FALSE;
18 CString TemplateStr=UTF8toUnicode(pElem->GetText());

UTF8toUnicode函数:

01 CString UTF8toUnicode(const char* utf8Str,UINT length)
02 {
03     CString unicodeStr;
04     unicodeStr=_T("");
05  
06     if (!utf8Str)
07         return unicodeStr;
08  
09     if (length==0)
10         return unicodeStr;
11  
12     //转换
13     WCHAR chr=0;
14     for (UINT i=0;i<length;)
15     {
16         if ((0x80&utf8Str[i])==0) // ASCII
17         {
18             chr=utf8Str[i];
19             i++;
20         }
21         else if((0xE0&utf8Str[i])==0xC0) // 110xxxxx 10xxxxxx
22         {
23             chr =(utf8Str[i+0]&0x3F)<<6;
24             chr|=(utf8Str[i+1]&0x3F);
25             i+=2;
26         }
27         else if((0xF0&utf8Str[i])==0xE0) // 1110xxxx 10xxxxxx 10xxxxxx
28         {
29             chr =(utf8Str[i+0]&0x1F)<<12;
30             chr|=(utf8Str[i+1]&0x3F)<<6;
31             chr|=(utf8Str[i+2]&0x3F);
32             i+=3;
33         }
34         /*
35         else if() // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
36         {}
37         else if() // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx  10xxxxxx
38         {}
39         else if() // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx  10xxxxxx 10xxxxxx
40         {}
41         */
42         else // 不是UTF-8字符串
43         {
44             return unicodeStr;
45         }
46         unicodeStr.AppendChar(chr);
47     }
48  
49     return unicodeStr;
50 }
51  
52 CString UTF8toUnicode(const char* utf8Str)
53 {
54     UINT theLength=strlen(utf8Str);
55     return UTF8toUnicode(utf8Str,theLength);
56 }

strlen取char*的长度等于字节数(不含终止符),不是utf-8字串的真正字符个数。

posted on 2010-10-20 17:57 涣熊 阅读(1670) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航:   博客园   博客园最新博文   博问   管理