Tixml保存

 

原本链接地址: 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);
这个标记没多大作用,无论设为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 }

开源项目TinyXml项目所涉及的字符编码说明如下: 1. TinyXml函数调用接口的字符型参数,仅支持`窄字符`格式(char*),不兼容`宽字符`格式(wchar_t*)。 2. TinyXml函数提供的Xml内容解析功能,仅支持以ANSI编码和UTF8编码的Xml字符串,也即`多字节编码`。 3. TinyXml函数提供的Xml内容解析功能,不支持内容以UTF16编码和UTF32编码的Xml字符串,也即`Unicode编码`。 4. UTF8编码是Unicode编码的一种实现方式,以不定个数的字节来存储一个Unicode码值,支持多国语言文字。 也即,UTF8编码在编码实现上属于`多字节编码`,在编码标准上属于`Unicode编码`。 5. 人类语言中同一个的字符,如果在各种不同的标准如ANSI编码、UTF8编码、UTF16编码和UTF32编码中都存在码值, 就可以相互转换。因为各个标准下的可编码字符容量不同,部分语言字符会在一个编码标准库下存在, 而在另外一个编码标准库下不存在,这时精确的相互转换就无法执行,但是仍然有默认字符转换。 -- 6. VC语言,当定义了宏 _UNICODE 后,_T系列宏或函数,以`宽字符`承载UTF16编码。 TinyXml如何提供`宽字符`函数接口,支持解析UTF16编码、UTF32编码标准下的Xml字符串呢? 本项目: - 新增适用于`宽字符`参数的函数接口,调用字符集转换功能,转换为`窄字符`参数,再回调TinyXml原版接口。 - 对于以UTF16编码、或UTF32编码的Xml字符串,转换为UTF8编 --
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值