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); |
09 |
XmlEntityTree->Accept(&printer); |
11 |
char UTF8BOM[3]={'\xEF','\xBB','\xBF'}; |
14 |
theFile.Open(_T("test.xml"),CFile::modeCreate|CFile::modeWrite); |
15 |
theFile.Write(UTF8BOM,3); |
16 |
theFile.Write(printer.CStr(),strlen(printer.CStr())); |
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" ?> |
3 |
<TemplateStr>中文</TemplateStr> |
4 |
<AutoFixCue>true</AutoFixCue> |
5 |
<AutoFixTTA>true</AutoFixTTA> |
6 |
<AcceptDragFLAC>true</AcceptDragFLAC> |
7 |
<AcceptDragTAK>true</AcceptDragTAK> |
8 |
<AcceptDragAPE>true</AcceptDragAPE> |
01 |
TiXmlDocument *xmlfile= new TiXmlDocument(FilePath); |
02 |
xmlfile->LoadFile(TIXML_ENCODING_UTF8); |
04 |
TiXmlHandle hRoot(xmlfile); |
06 |
TiXmlHandle hXmlHandle(0); |
09 |
pElem=hRoot.FirstChildElement().Element(); |
10 |
if (!pElem) return FALSE; |
11 |
if (strcmp(pElem->Value(),"config")!=0) |
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) |
14 |
for (UINT i=0;i<length;) |
16 |
if ((0x80&utf8Str[i])==0) |
21 |
else if((0xE0&utf8Str[i])==0xC0) |
23 |
chr =(utf8Str[i+0]&0x3F)<<6; |
24 |
chr|=(utf8Str[i+1]&0x3F); |
27 |
else if((0xF0&utf8Str[i])==0xE0) |
29 |
chr =(utf8Str[i+0]&0x1F)<<12; |
30 |
chr|=(utf8Str[i+1]&0x3F)<<6; |
31 |
chr|=(utf8Str[i+2]&0x3F); |
46 |
unicodeStr.AppendChar(chr); |
52 |
CString UTF8toUnicode(const char* utf8Str) |
54 |
UINT theLength=strlen(utf8Str); |
55 |
return UTF8toUnicode(utf8Str,theLength); |
strlen取char*的长度等于字节数(不含终止符),不是utf-8字串的真正字符个数。