VC++ 2019 MFC TinyXML2使用教程/方法详解

TinyXML2让VC++中操作XML,如鱼得水,就像一个小型的数据库,特别方便。从WeChat安装目录,可发现腾讯开发微信时,也在使用TinyXML。
在这里插入图片描述

本篇主要介绍在VC++ 2019的MFC项目中,如何利用TinyXML2,创建、插入、查询、更新、删除节点或数据。也顺便介绍下UNICODE转UTF8,因TinyXML2生成的XML文件是UTF-8编码,VS2019开发工具是UNICODE编码,所以,中文不转换会写入乱码。

一、创建MFC项目 MFCTinyXML2

在这里插入图片描述

  1. 应用程序类型选择“基于对话框”
  2. 主框架样式仅选择“粗框架”,其他样式无需选择
  3. 高级功能处全部全部不要选

详细教程见:https://blog.csdn.net/yixiao0307/article/details/119837989

二、下载源码并复制到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文件中,当然会乱码,因此,需要做如下转换:

  1. ASCII(char*)转宽字节(wchar_t*/UNICODE/CP_ACP,因为微软有提供函数MultiByteToWideChar)
  2. 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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值