原本链接地址: tinyXml处理UTF-8编码详解——写入和读取 以前写过一篇博文介绍tinyXml输出utf-8文档。 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); 对于下面文档,怎样才能正确读取到TemplateStr节点的内容?很简单,在读取时进行转换就行。 1 2 3 4 5 6 7 8 9 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 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 } |