转载地址:
VC++ 2019 MFC TinyXML2使用教程/方法详解_vc++2019_一笑的博客-CSDN博客
TinyXML2让VC++中操作XML,如鱼得水,就像一个小型的数据库,特别方便。
本篇主要介绍在VC++ 2019的MFC项目中,如何利用TinyXML2,创建、插入、查询、更新、删除节点或数据。
也顺便介绍下UNICODE转UTF8,因TinyXML2生成的XML文件是UTF-8编码,VS2019开发工具是UNICODE编码,所以,中文不转换会写入乱码。
一、创建MFC项目 MFCTinyXML2
- 应用程序类型选择“基于对话框”
- 主框架样式仅选择“粗框架”,其他样式无需选择
- 高级功能处全部全部不要选
二、下载源码并复制到MFC项目中
1、源码地址:https://github.com/leethomason/tinyxml2
2、将版本库中的tinyxml2.cpp和tinyxml2.h复制到项目中(源码中的文件很多,但,只需要这两个文件~,其他文件直接删掉就好了)
在Dialog界面增加几个按钮,最终项目目录结构如下
在主Dlg类中引用tinyxml2/tinyxml2.h
在项目中,选中tinyxml2.cpp文件,点击右键查看其属性,将“C/C++” - “预编译头” - 设置为“不使用预编译头”(如不设置,VS2019会“温馨”提示你没有使用pch.h这个预编译头文件)
OK,至此已可正常使用tinyxml2中的类和方法了。
三、创建XML,并保存到XML文件中
//使用以下内容建立XMLDocument const char* xmlContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"; tinyxml2::XMLDocument docXml; docXml.Parse(xmlContent);//添加root节点 tinyxml2::XMLElement* root = docXml.NewElement("root"); docXml.InsertEndChild(root);//添加message节点 tinyxml2::XMLElement* messageNode = docXml.NewElement("message"); messageNode->SetAttribute("username", "zhangsan");//属性 messageNode->SetText("hello");//内容 root->InsertEndChild(messageNode);//保存成XML文件 docXml.SaveFile("XMLFile.xml");
生成的XML文件,如下
<?xml version="1.0" encoding="utf-8"?> <root><message username="zhangsan">hello</message> </root>
四、读取XML
tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml");//读取上边生成的XML文件,如果还没有生成,会报错:load xml file failed. if (xmlError == tinyxml2::XML_SUCCESS) { //获取root节点 tinyxml2::XMLElement* root = docXml.RootElement(); //获取message节点 tinyxml2::XMLElement* messageNode = root->FirstChildElement("message"); //获取message->username属性的值 const char* username = messageNode->FindAttribute("username")->Value(); //获取message的内容 const char* content = messageNode->GetText(); //弹窗展示读取到的信息 CString str; str.Format(_T("<message username=\"%s\">%s</message>"), Char2Wchar(username), Char2Wchar(content)); AfxMessageBox(str); } else { AfxMessageBox(_T("load xml file failed.")); }
Char2Wchar转宽字节方法代码
wchar_t* Char2Wchar(const char* str, UINT CodePage) { //先获取转换成宽字符后的长度 int nLen = MultiByteToWideChar(CodePage, MB_PRECOMPOSED, str, -1, NULL, 0); //声明一个宽字符类型变量,用于存放转换后的字符 wchar_t* wstr = new wchar_t[nLen]; //利用微软ANSI转宽字符的函数(name:ANSI字符,wname:宽字符) MultiByteToWideChar(CodePage, MB_PRECOMPOSED, str, -1, wstr, nLen); return wstr; }
效果:XML文件不存在时,会提示
效果:读取成功后
五、新增节点
tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml"); if (xmlError == tinyxml2::XML_SUCCESS) { //获取root节点 tinyxml2::XMLElement* root = docXml.RootElement(); //循环增加3次message节点 const char* arrUsername[3] = {"lisi","wangwu","zhaoliu"}; for (int i = 0; i < 3; i++) { //生成新的message节点(无论在哪个节点中New,都直接在doc.NewElement) tinyxml2::XMLElement* messageNode = docXml.NewElement("message"); messageNode->SetAttribute("username", arrUsername[i]);//属性 messageNode->SetText(i);//内容 root->InsertEndChild(messageNode); } //不要忘记保存一下 docXml.SaveFile("XMLFile.xml"); } else { AfxMessageBox(_T("load xml file failed.")); }
效果:增加了0/1/2三条message节点记录
六、查询
1、根据属性值(如:username = wangwu)查找
方法
/// <summary> /// 根据属性/值查询节点 /// </summary> /// <param name="root">xml root节点</param> /// <param name="elementName">要查询的节点,一般是多行的</param> /// <param name="attributeName">节点的属性名</param> /// <param name="attributeValue">节点的属性值</param> /// <returns></returns> tinyxml2::XMLElement* queryXMLElementByAttribute(tinyxml2::XMLElement* root, const char* elementName, const char* attributeName, const char* attributeValue) { tinyxml2::XMLElement* node = root->FirstChildElement(elementName); while (node != NULL) { const char* value = node->Attribute(attributeName); //比较两个字符串char*是否相等(const char*,不能直接使用等号比较) if (strcmp(value, attributeValue) == 0) break; node = node->NextSiblingElement(); } return node; }
调用
const char* whereUsername = "wangwu"; tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml"); if (xmlError == tinyxml2::XML_SUCCESS) { //获取root节点 tinyxml2::XMLElement* root = docXml.RootElement(); tinyxml2::XMLElement* messageNode = tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "wangwu"); //最后保留下的这个节点就是查询到的节点 //弹窗展示读取到的信息 CString str; str.Format(_T("<message username=\"%s\">%s</message>"), Char2Wchar(messageNode->Attribute("username")), Char2Wchar(messageNode->GetText())); AfxMessageBox(str); } else { AfxMessageBox(_T("load xml file failed.")); }
效果:
2、根据值查找(同理)
七、更新
1、更新属性值
tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml"); if (xmlError == tinyxml2::XML_SUCCESS) { //获取root节点 tinyxml2::XMLElement* root = docXml.RootElement(); //查询 tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "lisi"); //更新 messageNode->SetAttribute("username", "lisi1234");//改成lisi1234 //不要忘记保存一下 docXml.SaveFile("XMLFile.xml"); } else { AfxMessageBox(_T("load xml file failed.")); }
效果:
2、更新内容(同理)
八、删除
1、删除指定节点
tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml"); if (xmlError == tinyxml2::XML_SUCCESS) { //获取root节点 tinyxml2::XMLElement* root = docXml.RootElement(); //查询 tinyxml2::XMLElement* messageNode = queryXMLElementByAttribute(root, "message", "username", "zhaoliu"); //删除查询到的节点 root->DeleteChild(messageNode); //不要忘记保存一下 docXml.SaveFile("XMLFile.xml"); } else { AfxMessageBox(_T("load xml file failed.")); }
2、删除全部子节点
代码:
tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml"); if (xmlError == tinyxml2::XML_SUCCESS) { //获取root节点 tinyxml2::XMLElement* root = docXml.RootElement(); //删除查询到的节点 root->DeleteChildren(); //不要忘记保存一下 docXml.SaveFile("XMLFile.xml"); } else { AfxMessageBox(_T("load xml file failed.")); }
效果:
九、获取XML文件全部内容
tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml"); if (xmlError == tinyxml2::XML_SUCCESS) { tinyxml2::XMLPrinter printer; docXml.Print(&printer); AfxMessageBox(Char2Wchar(printer.CStr())); } else { AfxMessageBox(_T("load xml file failed.")); }
效果:
十、UTF-8编码的XML中,增加中文节点(中文乱码处理办法)
tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml"); if (xmlError == tinyxml2::XML_SUCCESS) { //获取root节点 tinyxml2::XMLElement* root = docXml.RootElement(); //生成新的message节点(无论在哪个节点中New,都直接在doc.NewElement) tinyxml2::XMLElement* messageNode = docXml.NewElement("message"); messageNode->SetAttribute("username", "王二麻子");//属性 messageNode->SetText("中文内容测试");//内容 root->InsertEndChild(messageNode); //不要忘记保存一下 docXml.SaveFile("XMLFile.xml"); } else { AfxMessageBox(_T("load xml file failed.")); }
使用以上代码,不做任何处理,会出现如下情况(乱码)
之所以中文会乱码,分析原因为:VS是使用UNICODE编码(UTF16),直接用写入UTF8编码的XML文件中,当然会乱码,因此,需要做如下转换:
- ASCII(char*)转宽字节(wchar_t*/UNICODE/CP_ACP,因为微软有提供函数MultiByteToWideChar)
- UNICODE以UTF8(CP_UTF8)编码转ASCII
转换成UTF8编码的代码:
char* Ascii2Unicode2Utf8(const char* str) { //ASCII to Unicode(CP_ACP) int nLen = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); wchar_t* wstr = new wchar_t[nLen]; MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstr, nLen); //Unicode to UTF-8 int nLenUTF8 = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); char* strUTF8 = new char[nLenUTF8]; WideCharToMultiByte(CP_UTF8, 0, wstr, -1, strUTF8, nLenUTF8, NULL, NULL); return strUTF8; }
使用了转UTF8编码的方法后,生成XML不再乱码了
tinyxml2::XMLDocument docXml; tinyxml2::XMLError xmlError = docXml.LoadFile("XMLFile.xml"); if (xmlError == tinyxml2::XML_SUCCESS) { //获取root节点 tinyxml2::XMLElement* root = docXml.RootElement(); //生成新的message节点(无论在哪个节点中New,都直接在doc.NewElement) tinyxml2::XMLElement* messageNode = docXml.NewElement("message"); messageNode->SetAttribute("username", Ascii2Unicode2Utf8("王二麻子"));//属性 messageNode->SetText(Ascii2Unicode2Utf8("中文内容测试"));//内容 root->InsertEndChild(messageNode); //不要忘记保存一下 docXml.SaveFile("XMLFile.xml"); } else { AfxMessageBox(_T("load xml file failed.")); }
效果:中文字内容写入正常
十一、本篇文章项目源码
https://gitee.com/kefong/MFCTinyxml2.git
标签:xml,MFC,tinyxml2,TinyXML2,C++,messageNode,docXml,root,节点 From: https://www.cnblogs.com/ckrgd/p/17846779.html