zoukankan      html  css  js  c++  java
  • C++ tinyXML的使用和字符编码转换

    转载: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编码方式,如下面代码.
     
    TiXmlDocument* m_pTinXMLDoc = new TiXmlDocument; 
    TiXmlDeclaration* pdecl = new TiXmlDeclaration("1.0", "UTF-8", "yes"); 
    m_pTinXMLDoc->LinkEndChild(pdecl); // <?xml version="1.0" encoding="UTF-8"?> 
     
    // <TransmitInfo datetime="2012-10-10 19:10:23" cmd="1" category=""> 
    TiXmlElement* pEleRoot = new TiXmlElement("RootNode"); 
    pEleRoot->SetAttribute("id", "这是中文"); 
     
    TiXmlElement* pNode = new TiXmlElement("中文标签"); 
    pNode->SetAttribute("中文属性", "属性值");
    pEleRoot->LinkEndChild(pNode); 
     
    m_pTinXMLDoc->LinkEndChild(pEleRoot); 
     
    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格式,在网络上传输.如下代码:

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

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

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

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

  • 相关阅读:
    Servant:基于Web的IIS管理工具
    mono-3.4.0 源码安装时出现的问题 [do-install] Error 2 [install-pcl-targets] Error 1 解决方法
    使用 OWIN Self-Host ASP.NET Web API 2
    Xamarin和微软发起.NET基金会
    SQLite vs MySQL vs PostgreSQL:关系型数据库比较
    Mono 3.2.7发布,JIT和GC进一步改进
    如何使用Microsoft技术栈
    c#开源消息队列中间件EQueue 教程
    通过一组RESTful API暴露CQRS系统功能
    NEsper Nuget包
  • 原文地址:https://www.cnblogs.com/chechen/p/7418932.html
Copyright © 2011-2022 走看看