tinyxml的使用和字符编码转换

来源:互联网 发布:php 记log日志 编辑:程序博客网 时间:2024/06/06 01:13
 tinyxml的使用和字符编码转换
2012-01-11 13:10:00
标签:ansi xml tinyxml使用 tinyxml编码 tinyxml ansi格式保存xml
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://jetyi.blog.51cto.com/1460128/761708

 关于tinyxml使用的文档有很多(这篇文章就写的很好),这里仅提一下字符编码的转换问题,如果你不熟悉字符编码最好先阅读一下计算机内存和文件中的UNICODE字符.

tinyxml定义的类或函数中涉及的字符大都是char,字符串指针也是char*或const char*,看一下面几个函数:
const char* TiXmlElement::Attribute( const char* name ) const
int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
...
这样在你的应用程序中获取的字符串就是const char*类型,如果你的XML文档指定是UTF-8编码(注意保存的时候也是以UTF-8编码方式保存的),例如:
<?xml version="1.0" encoding="UTF-8">
<root>
<item>中文字符</item>
</root>
 
而你的应用程序可能是UNICODE,也可能是多字节,那么在应用程序中会这样读xml文档:
TiXmlDocument doc("UTF8test.xml"); 
doc.LoadFile(TIXML_DEFAULT_ENCODING);//TIXML_DEFAULT_ENCODING指明按照UTF-8编码方式读取xml文档
TiXmlElement* root = doc.RootElement();
TiXmlNode* node = root->FirstChild("item");
TiXmlElement* element = node->ToElement();
const char* text = element->GetText();
 
要注意此时的text,它指向的内存保存的数据是一个char类型的字符,以0结尾,如果你将其直接输出得到的将是乱码,它的内容如下:
e4 b8 ad e6 96 87 e5 ad 97 e7 ac a6 00
这一串数据是保存在文件中的UTF-8编码,它们是多字节字符.
 
将其转换为宽字符(宽字符的意思是:UNICODE 字符在内存中是以"UNICODE字符集中的序号"存在).
WCHAR wtext[MAX_PATH] = {0};
MultiByteToWideChar(CP_UTF8, 0, text, -1, wtext, MAX_PATH);
再看看wtext中的内容: 2d 4e 87 65 57 5b 26 7b 00 00
这是在内存中存放的UTF-8字符编码的序号(UNICODE字符字符内存中存放的是其序号而不是其编码).
 
再将wtext转换为多字符(CP_ACP方式编码) :
char sztext[MAX_PATH] = {0};
WideCharToMultiByte(CP_ACP, 0, wtext, -1, sztext, MAX_PATH, NULL, NULL);
再看看sztext中的内容: d6 d0 ce c4 d7 d6 b7 fb 00
 
可以看到,text,wtext,sztext指向内存中的数据并不相同.
还有一点,如果text中的内容是ASII吗,你就不用转换了,可以直接拿来使用.
 
在内存中动态生成XML文件时,仍然是ANSI编码方式,如下面代码.
 
  1. TiXmlDocument* m_pTinXMLDoc = new TiXmlDocument; 
  2. TiXmlDeclaration* pdecl = new TiXmlDeclaration("1.0""UTF-8""yes"); 
  3. m_pTinXMLDoc->LinkEndChild(pdecl); // <?xml version="1.0" encoding="UTF-8"?> 
  4.  
  5. // <TransmitInfo datetime="2012-10-10 19:10:23" cmd="1" category=""> 
  6. TiXmlElement* pEleRoot = new TiXmlElement("RootNode"); 
  7. pEleRoot->SetAttribute("id""这是中文"); 
  8.  
  9. TiXmlElement* pNode = new TiXmlElement("中文标签"); 
    pNode->SetAttribute("中文属性", "属性值");
  10. pEleRoot->LinkEndChild(pNode); 
  11.  
  12. m_pTinXMLDoc->LinkEndChild(pEleRoot); 
  13.  
  14. m_pTinXMLDoc->SaveFile("e:\\testansi.xml"); 

文件内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

<RootNode id="这是中文">

    <中文标签 中文属性="属性值" />

</RootNode>

上面代码需要注意一个调用:new TiXmlDeclaration("1.0", "UTF-8", "yes");参数"UTF-8"不是设置内存中xml文件的编码方式,而仅仅是这只文件头encoding的属性,跟文件实际编码方式无关.不过这样做还是意义的,可以获取文件内容字符串,然后转换为utf-8格式,在网络上传输.如下代码:

  1. TiXmlPrinter printer; 
  2. m_pTinXMLDoc->Accept(&printer); 
  3.  
  4. int nxmlBytes = printer.Size(); 
  5. const char* xmlcstr = printer.CStr(); 
  6. ASSERT(strlen(xmlcstr)==nxmlBytes && nxmlBytes<nLen); 
  7.        //将xmlcstr转换为utf-8 
  8.        //...略. 

转换之后,encoding=UTF-8真正表示文件的编码格式.

另外,调用SaveFile保存到本地时,仍然是以ANSI字符格式保存到本地.

所以,实际上xml文件头中的属性encoding=UTF-8,但文件未必是UTF-8编码方式.

0 0
原创粉丝点击