C/C++ 使用 tinyxml库 操作XML格式文件(创建、插入、删除、修改、解析)

C++ XML文件读取 C++快速读取XML文件 阅读详情
AI摘要

本文详细介绍了如何使用TinyXML库在C++中创建、添加、删除、修改和解析XML文件。从创建XML文档、添加头部信息、根节点和子节点,到设置属性,再到将XML内容写入文件,每个步骤都有清晰的代码示例。接着,文章展示了如何添加新的节点元素、删除指定节点和属性,以及修改节点值。最后,讲解了如何解析XML文件中的节点值,包括获取特定节点的属性和子节点内容。通过这些实例,读者可以快速掌握TinyXML在实际项目中的应用。

前段时间学习了C语言使用cJOSN去解析json文件,都是工作需要才去学习的,现在这一篇C/C++解析xml文件,也是因为工作需要,不得已去学。

本来就会使用QT去解析了,但是还不够,使用QT语言编写的代码,无法在其他项目中去运行,所以,现在带来一篇自学tinyxml解析xml的文件的博客,供大家学习研究!



一、准备工作

首先看一下XML文件的组成部分:
xml主要是由两部分组成,头部信息 和 节点

细分下来,头部信息就是开头这一串东西:<?xml version="1.0" encoding="utf-8" ?>

节点是:根节点、子节点、属性三部分。

如下图:
在这里插入图片描述
一个完整的xml文件由图中部分组成!

头部信息:这个是xml文件必须要有的一段描述语句;
根节点:xml文件由只有一个根节点(仅有),它是所有子节点的父节点;
子节点:可有多个,必须在根节点内;
属性:存储数据的一种方式。

这里所讲的tinyxml使用的是DOM解析方式,优点是解析速度快,缺点是无法解析复杂的xml文件。

下载tinyxml
https://sourceforge.net/projects/tinyxml/

在这里插入图片描述
下载后解压出来会得到以下文件:
在这里插入图片描述
其实只需要将我用红色方框框中的那六个文件拷贝到自己的项目中去,在添加到项目中就可以使用了。当然,也可以使用vs编译成lib库去调用,这个我编译过了,我这边使用不了,不知道原因,所以只能将源文件都拷贝到项目中去使用了。
在这里插入图片描述
像我这样,把文件都添加到项目中去,最后在需要使用的地方添加头文件:#include "tinyxml.h" 就可以去解析了!

在Linux系统中也是可以这样去使用的!


二、创建

创建一个xml文件,并为其插入头部信息 和 跟、子节点

1. 创建一个XML类

TiXmlDocument* tinyXmlDoc = new TiXmlDocument();

2. 创建头部信息

并插入到xml类中

// xml的声明(三个属性:版本,编码格式,保留空串即可)
TiXmlDeclaration* tinyXmlDeclare = new TiXmlDeclaration("1.0", "utf-8", "");	// 声明头部格式
// 插入文档类中
tinyXmlDoc->LinkEndChild(tinyXmlDeclare);

就是这一行东西
在这里插入图片描述

3. 创建根节点

// 创建时需要指定根节点的名称
TiXmlElement* Library = new TiXmlElement("Library");
tinyXmlDoc->LinkEndChild(Library);		// 把根节点插入到文档类中

如图:
在这里插入图片描述

4. 添加子节点

首先创建一个子节点,然后新建一个文本,将文本添加到子节点中,最后将字节点添加到根节点中。

TiXmlElement *Book = new TiXmlElement("Book");
TiXmlText *bookText = new TiXmlText("书本");	// 创建文本
Book->LinkEndChild(bookText);	// 给Book节点添加文本
Library->LinkEndChild(Book);	// 插入到根节点下

如图:
在这里插入图片描述

5. 添加带属性的子节点

使用setAttribute可以简单的给节点添加属性值;
如果要创建子节点的子节点,就跟创建子节点一样,只是创建好后要添加到子节点中即可。

TiXmlElement *Book1 = new TiXmlElement("Book1");
// 插入属性
Book1->SetAttribute("ID", 1);
Book1->SetAttribute("Name", "水浒传");
Book1->SetAttribute("Price", "64.6");

// 创建Book1的子节点Description
TiXmlElement *Description = new TiXmlElement("Description");
TiXmlText *descriptionText = new TiXmlText("108个拆迁户");		// 创建文本
Description->LinkEndChild(descriptionText);		// 给Description节点添加文本
Book1->LinkEndChild(Description);				// 插入到Book1节点下

// 创建Book1的子节点Page
TiXmlElement *Page = new TiXmlElement("Page");
TiXmlText *pageText = new TiXmlText("100页");		// 创建文本
Page->LinkEndChild(pageText);	// 给Page节点添加文本
Book1->LinkEndChild(Page);		// 插入到Book1节点下

Library->LinkEndChild(Book1);	// 插入到根节点下

如图:
在这里插入图片描述

6. 将doc写入xml文件

只需使用文档类调用SaveFile方法即可,参数传文件名
写入成功返回true,写入失败返回false

bool result = tinyXmlDoc->SaveFile(FILE_NAME);

7. 转换为字符串

TiXmlPrinter printer;
tinyXmlDoc->Accept(&printer);
printf("%s\n", printer.CStr());

在这里插入图片描述
如果只是想在控制台打印而已,那么可以直接调用函数tinyXmlDoc->Print();就可以实现在控制台上打印出来了!

8. 创建xml文件并插入元素节点,总代码如下

void create_XML() {
	printf("\n----- create_XML -----\n"); 

	//新建一个xml文件
	// 定义一个TiXmlDocument类指针
	TiXmlDocument* tinyXmlDoc = new TiXmlDocument();



	// xml的声明(三个属性:版本,编码格式,保留空串即可)
	TiXmlDeclaration* tinyXmlDeclare = new TiXmlDeclaration("1.0", "utf-8", "");	// 声明头部格式
	// 插入文档类中
	tinyXmlDoc->LinkEndChild(tinyXmlDeclare);



	// 根节点
	TiXmlElement* Library = new TiXmlElement("Library");
	tinyXmlDoc->LinkEndChild(Library);		// 把根节点插入到文档类中



	// 创建Book节点
	TiXmlElement *Book = new TiXmlElement("Book");
	TiXmlText *bookText = new TiXmlText("书本");	// 创建文本
	Book->LinkEndChild(bookText);	// 给Book节点添加文本
	Library->LinkEndChild(Book);	// 插入到根节点下


	// 创建Book1节点
	TiXmlElement *Book1 = new TiXmlElement("Book1");
	// 插入属性
	Book1->SetAttribute("ID", 1);
	Book1->SetAttribute("Name", "水浒传");
	Book1->SetAttribute("Price", "64.6");

	// 创建Book1的子节点Description
	TiXmlElement *Description = new TiXmlElement("Description");
	TiXmlText *descriptionText = new TiXmlText("108个拆迁户");		// 创建文本
	Description->LinkEndChild(descriptionText);		// 给Description节点添加文本
	Book1->LinkEndChild(Description);				// 插入到Book1节点下

	// 创建Book1的子节点Page
	TiXmlElement *Page = new TiXmlElement("Page");
	TiXmlText *pageText = new TiXmlText("100页");		// 创建文本
	Page->LinkEndChild(pageText);	// 给Page节点添加文本
	Book1->LinkEndChild(Page);		// 插入到Book1节点下

	Library->LinkEndChild(Book1);	// 插入到根节点下



	// 保存到文件	
	bool result = tinyXmlDoc->SaveFile(FILE_NAME);
	if (result == true) printf("文件写入成功!\n");
	else printf("文件写入失败!\n");

	// 打印出来看看
	//tinyXmlDoc->Print();

	TiXmlPrinter printer;
	tinyXmlDoc->Accept(&printer);
	printf("%s\n", printer.CStr());
}

当执行完成后,会在指定路径创建一个xml文件,内容如下图:
在这里插入图片描述


三、添加

往xml文件中添加节点元素

例:在上面创建的xml文件基础上,添加两个Book1子节点。

1. 定义一个xml文件类,并读取文件中的xml内容初始化它

这里有两种方式,有点奇怪,当使用第一种方式读取xml文件时,xml中有多个子节点Book1时,由于属性都有相同的id、name、price,导致会读取失败,不得已让我搞出了第二种方式去读取进行初始化,这样就没问题!

1). 方式1

// 定义一个TiXmlDocument类指针
TiXmlDocument* tinyXmlDoc = new TiXmlDocument;

// 读取文件中的xml
if (!tinyXmlDoc->LoadFile(FILE_NAME)) {
	// 读取失败,打印失败原因
	printf("Could not load example xml file %s. Error='%s'\n", FILE_NAME, tinyXmlDoc->ErrorDesc());
	return ;
}

读取失败显示:
在这里插入图片描述

2). 方式2

定义xml文档类对象时指定文件名,然后在使用这个对象去调用LoadFile传参TIXML_ENCODING_LEGACY即可,具体传参是什么意思,我也不清楚,自己摸索出来的,其中有三个枚举可以选择,其他两个都不行,就这个可以!

// 定义xml文档类对象时指定文件名
TiXmlDocument* tinyXmlDoc = new TiXmlDocument(FILE_NAME);
// 然后在使用这个对象去调用LoadFile传参TIXML_ENCODING_LEGACY即可
tinyXmlDoc->LoadFile(TIXML_ENCODING_LEGACY);

我一般都是,第一种方式用不了,就用第二种方式初始化!

3). 对已存在的数据进行初始化

std::string data;	// 这里默认data是存储xml数据的字符串变量

/* 方式一: */
// 定义一个TiXmlDocument类指针
TiXmlDocument* tinyXmlDoc = new TiXmlDocument();
// 数据初始化
tinyXmlDoc->Parse(data.c_str());

/* 方式二: */
// 定义一个TiXmlDocument类指针
TiXmlDocument* tinyXmlDoc = new TiXmlDocument(data.c_str());

4). 也可以获取头部信息中的版本号和编码

// 读取文档声明信息(也就是xml的头部信息:<?xml version="1.0" encoding="utf-8" ?>)
TiXmlDeclaration *pDeclar = tinyXmlDoc->FirstChild()->ToDeclaration();
if (pDeclar != NULL) {
	printf("头部信息: version is %s , encoding is %s\n", pDeclar->Version(), pDeclar->Encoding());
}

2. 获取根节点

这个定义是需要指定参数根节点的名字,然后再通过RootElement方法获取。

TiXmlElement *Library = new TiXmlElement("Library");
Library = tinyXmlDoc->RootElement();

3. 创建Book1节点,并设置属性

TiXmlElement *Book1 = new TiXmlElement("Book1");
// 插入属性
Book1->SetAttribute("ID", 2);
Book1->SetAttribute("Name", "西游记");
Book1->SetAttribute("Price", "99.81");

假设创建好后,在xml文件中是这样显示的:
在这里插入图片描述

4. 创建Book1的子节点Description 和 Page

和上面创建的思路代码是一样的,创建好后在插入到Book1节点中就好了

// 创建Book1的子节点Description
TiXmlElement *Description = new TiXmlElement("Description");
TiXmlText *descriptionText = new TiXmlText("师徒四人");		// 创建文本
Description->LinkEndChild(descriptionText);		// 给Description节点添加文本
Book1->LinkEndChild(Description);				// 插入到Book1节点下

// 创建Book1的子节点Page
TiXmlElement *Page = new TiXmlElement("Page");
TiXmlText *pageText = new TiXmlText("81页");		// 创建文本
Page->LinkEndChild(pageText);	// 给Page节点添加文本
Book1->LinkEndChild(Page);		// 插入到Book1节点下

假设创建好后,在xml文件中是这样显示的:
在这里插入图片描述

5. 将Book1节点添加到根节点中

Library->LinkEndChild(Book1);	// 插入到根节点下

6. 将doc写入xml文件

// 保存到文件	
bool result = tinyXmlDoc->SaveFile(FILE_NAME);
if (result == true) printf("文件写入成功!\n");
else printf("文件写入失败!\n");

7. 为已存在的xml文件添加节点元素,总代码如下

void add_XML() {
	printf("\n----- add_XML -----\n");

	// 定义一个TiXmlDocument类指针
	TiXmlDocument* tinyXmlDoc = new TiXmlDocument(FILE_NAME);
	tinyXmlDoc->LoadFile(TIXML_ENCODING_LEGACY);

	// 读取文档声明信息(也就是xml的头部信息:<?xml version="1.0" encoding="utf-8" ?>)
	TiXmlDeclaration *pDeclar = tinyXmlDoc->FirstChild()->ToDeclaration();
	if (pDeclar != NULL) {
		printf("头部信息: version is %s , encoding is %s\n", pDeclar->Version(), pDeclar->Encoding());
	}

	// 得到文件根节点
	TiXmlElement *Library = new TiXmlElement("Library");
	Library = tinyXmlDoc->RootElement();


	// 创建Book1节点
	TiXmlElement *Book1 = new TiXmlElement("Book1");
	// 插入属性
	Book1->SetAttribute("ID", 2);
	Book1->SetAttribute("Name", "西游记");
	Book1->SetAttribute("Price", "99.81");

	// 创建Book1的子节点Description
	TiXmlElement *Description = new TiXmlElement("Description");
	TiXmlText *descriptionText = new TiXmlText("师徒四人");		// 创建文本
	Description->LinkEndChild(descriptionText);		// 给Description节点添加文本
	Book1->LinkEndChild(Description);				// 插入到Book1节点下

	// 创建Book1的子节点Page
	TiXmlElement *Page = new TiXmlElement("Page");
	TiXmlText *pageText = new TiXmlText("81页");		// 创建文本
	Page->LinkEndChild(pageText);	// 给Page节点添加文本
	Book1->LinkEndChild(Page);		// 插入到Book1节点下

	Library->LinkEndChild(Book1);	// 插入到根节点下




	// 创建Book1节点
	Book1 = new TiXmlElement("Book1");
	// 插入属性
	Book1->SetAttribute("ID", 3);
	Book1->SetAttribute("Name", "三国演义");
	Book1->SetAttribute("Price", "66.66");

	// 创建Book1的子节点Description
	Description = new TiXmlElement("Description");
	descriptionText = new TiXmlText("三国大战");		// 创建文本
	Description->LinkEndChild(descriptionText);		// 给Description节点添加文本
	Book1->LinkEndChild(Description);				// 插入到Book1节点下

	// 创建Book1的子节点Page
	Page = new TiXmlElement("Page");
	pageText = new TiXmlText("30页");		// 创建文本
	Page->LinkEndChild(pageText);	// 给Page节点添加文本
	Book1->LinkEndChild(Page);		// 插入到Book1节点下

	Library->LinkEndChild(Book1);	// 插入到根节点下


	// 保存到文件	
	bool result = tinyXmlDoc->SaveFile(FILE_NAME);
	if (result == true) printf("文件写入成功!\n");
	else printf("文件写入失败!\n");

	// 打印出来看看
	tinyXmlDoc->Print();
}

执行完如上代码,会在xml文件中添加指定的节点元素,如下图
在这里插入图片描述
可以看到,创建相同子节点的代码都是一样的,也就是说,当需要创建几十个这个的子节点时,可以使用for循环去处理,至于数据可以使用数组是事先存储即可!


四、删除

删除子节点

例:
/* 删除book 和 其中一个book1节点 和 其中一个属性 */

1. 定义一个xml文件类,并读取文件中的xml内容初始化它

和上面 三、添加 的第1步骤 一样…

2. 获取根节点

这个定义是需要指定参数根节点的名字,然后再通过RootElement方法获取。

// 创建时需要指定名称
TiXmlElement *Library = new TiXmlElement("Library");
Library = tinyXmlDoc->RootElement();

3. 删除Book节点

像这种只有自己本身的,没有其他子节点的节点,它有两种方式去删除

1). 方式一

获取到对应节点后调用Clear()方法去删除。

// 方式一
TiXmlElement* Book = Library->FirstChildElement("Book");
Book->Clear();

2). 方式二

获取到对应节点后,根节点调用RemoveChild去删除,传参时需要对变量转换一下

// 获取Book节点
TiXmlElement* Book = Library->FirstChildElement("Book");
Library->RemoveChild(Book->ToElement());

建议还是使用第二种方式

a. 当然,如果Book节点不止一个时,如果需要删除特定的几个,可以使用for循环去删除

判断文本,符合条件就删除

调用FirstChildElement方法,传入子节点名字,可以获得第一个相同名字的子节点
调用NextSiblingElement方法,传入节点名字,可以获得下一个相同名字的节点

调用RemoveChild方法,是父节点删除子节点的方法

TiXmlElement* pItem1 = Library->FirstChildElement("Book");
for (; pItem1 != NULL; ) {

	if (strncmp(pItem1->GetText(), "书本", 6) == 0) {
		// 提前存储删除节点的下一个节点
		TiXmlElement* temporary = pItem1->NextSiblingElement("Book1");

		// 删除当前节点,删除后pItem为NULL,如果再继续使用它会报错
		Library->RemoveChild(pItem1->ToElement());

		// 所以这里要进行赋值回来
		pItem1 = temporary;
		
	} else {
		// 寻找下一个Book1节点
		pItem1 = pItem1->NextSiblingElement("Book1");
	}
}

用if判断,然后符合条件进行删除即可!

这里讲一下if里面的操作:
首先删除当前pItem1后,pItem1就变为NULL值了,如果在进行判断pItem1,它就是等于NULL的,那么就直接结束循环了,有时候不等于NULL,再去使用它去获取下一个节点会报错。
所以,在删除之前,先获取下一个节点保存着,然后进行删除,最后将赋值回来就可以了!

这个也是自己摸索出来的,不知道会不会有什么隐藏的BUG,反正目前我测试着是没有问题的!
也许还会有其他更好的方法,目前我是想不出来了,如果有想出来的朋友,可以评论区发出来,互相学习学习,谢谢!

假设执行完,xml中将会是这样:
在这里插入图片描述

4. 删除属性

可以使用直接写全代码的方式去删除,如上面的方式二一样,也可以使用for循环,然后用符合条件后去删除,这里就是使用了for循环去删除属性。

删除属性直接删除即可,不需要做其他什么操作!

调用Attribute方法,传入属性名可以获得属性的值
调用RemoveAttribute方法,传入属性名可以进行删除

// 删除属性
TiXmlElement* pItem = Library->FirstChildElement("Book1");
for (; pItem != NULL; pItem = pItem->NextSiblingElement("Book1")) {

	// 找到属性ID = 1的节点
	if (strcmp(pItem->Attribute("ID"), "1") == 0) {
		// 删除属性为Name的属性
		pItem->RemoveAttribute("Name");
	}
}

假设执行完,xml中将会是这样:
在这里插入图片描述

5. 删除整个节点

思路和上面删除Book节点一样

这里是删除ID属性为2的Book1节点

pItem = Library->FirstChildElement("Book1");
for (; pItem != NULL; ) {

	// 找到属性ID = 2的节点
	if (strcmp(pItem->Attribute("ID"), "2") == 0) {
		// 提前存储删除节点的下一个节点
		TiXmlElement* temporary = pItem->NextSiblingElement("Book1");

		// 删除当前节点,删除后pItem为NULL,如果再继续使用它会报错
		Library->RemoveChild(pItem->ToElement());

		// 所以这里要进行赋值回来
		pItem = temporary;
		
	} else {
		// 寻找下一个Book1节点
		pItem = pItem->NextSiblingElement("Book1");
	}
}

假设执行完,xml中将会是这样:
在这里插入图片描述

6. 将doc写入xml文件

// 保存到文件	
bool result = tinyXmlDoc->SaveFile(FILE_NAME);
if (result == true) printf("文件写入成功!\n");
else printf("文件写入失败!\n");

7. 删除总代码如下

void del_XML() {
	printf("\n----- del_XML -----\n");

	// 定义一个TiXmlDocument类指针
	TiXmlDocument* tinyXmlDoc = new TiXmlDocument(FILE_NAME);
	tinyXmlDoc->LoadFile(TIXML_ENCODING_LEGACY);

	// 读取文档声明信息(也就是xml的头部信息:<?xml version="1.0" encoding="utf-8" ?>)
	TiXmlDeclaration *pDeclar = tinyXmlDoc->FirstChild()->ToDeclaration();
	if (pDeclar != NULL) {
		printf("头部信息: version is %s , encoding is %s\n", pDeclar->Version(), pDeclar->Encoding());
	}

	// 得到文件根节点
	TiXmlElement *Library = new TiXmlElement("Library");
	Library = tinyXmlDoc->RootElement();


	/* 删除 Book 节点 */
	// 方式一
	//TiXmlElement* Book = Library->FirstChildElement("Book");
	//Book->Clear();


	// 方式二
	// 获取Book节点
	TiXmlElement* Book = Library->FirstChildElement("Book");
	Library->RemoveChild(Book->ToElement());


	//TiXmlElement* pItem1 = Library->FirstChildElement("Book");
	//for (; pItem1 != NULL; ) {

	//	if (strncmp(pItem1->GetText(), "书本", 6) == 0) {
	//		// 提前存储删除节点的下一个节点
	//		TiXmlElement* temporary = pItem1->NextSiblingElement("Book1");

	//		// 删除当前节点,删除后pItem为NULL,如果再继续使用它会报错
	//		Library->RemoveChild(pItem1->ToElement());

	//		// 所以这里要进行赋值回来
	//		pItem1 = temporary;
	//	
	//	} else {
	//		// 寻找下一个Book1节点
	//		pItem1 = pItem1->NextSiblingElement("Book1");
	//	}
	//}
	


	// 删除属性
	TiXmlElement* pItem = Library->FirstChildElement("Book1");
	for (; pItem != NULL; pItem = pItem->NextSiblingElement("Book1")) {

		// 找到属性ID = 1的节点
		if (strcmp(pItem->Attribute("ID"), "1") == 0) {
			// 删除属性为Name的属性
			pItem->RemoveAttribute("Name");
		}
	}

	// 删除整个节点
	pItem = Library->FirstChildElement("Book1");
	for (; pItem != NULL; ) {

		// 找到属性ID = 2的节点
		if (strcmp(pItem->Attribute("ID"), "2") == 0) {
			// 提前存储删除节点的下一个节点
			TiXmlElement* temporary = pItem->NextSiblingElement("Book1");

			// 删除当前节点,删除后pItem为NULL,如果再继续使用它会报错
			Library->RemoveChild(pItem->ToElement());

			// 所以这里要进行赋值回来
			pItem = temporary;
		
		} else {
			// 寻找下一个Book1节点
			pItem = pItem->NextSiblingElement("Book1");
		}
	}




	// 保存到文件	
	bool result = tinyXmlDoc->SaveFile(FILE_NAME);
	if (result == true) printf("文件写入成功!\n");
	else printf("文件写入失败!\n");

	// 打印出来看看
	tinyXmlDoc->Print();

}

执行后xml文件如下图:
在这里插入图片描述


五、修改

修改(更改)XML中节点的值

例:将ID属性为3的Book1节点的Price属性值修改为33.33;将ID属性为1的Book1节点的Description子节点值修改为108个没房住,Page修改为999页。

1. 定义一个xml文件类,并读取文件中的xml内容初始化它

和上面 三、添加 的第1步骤 一样…

2. 获取根节点

和上面 三、添加 的第2步骤 一样…

3. 修改属性值

符合条件后使用SetAttribute方法即可进行重新修改属性

TiXmlElement* pItem = Library->FirstChildElement("Book1");
for (; pItem != NULL; pItem = pItem->NextSiblingElement("Book1")) {

	// 设置属性
	if (strcmp(pItem->Attribute("ID"), "3") == 0) {
		pItem->SetAttribute("Price", "33.33");
	}
}

执行后xml文件如下图:
在这里插入图片描述

4. 修改节点值

首先使用FirstChildElement获得对应节点后,在使用FirstChild获得需要修改的文本指针对象,最后在调用SetValue就可以进行修改了

TiXmlElement* pItem = Library->FirstChildElement("Book1");
for (; pItem != NULL; pItem = pItem->NextSiblingElement("Book1")) {

	// 找到属性ID = 1的节点
	if (strcmp(pItem->Attribute("ID"), "1") == 0) {
		// 设置Book1的子节点Description的值
		TiXmlElement* Description = pItem->FirstChildElement("Description");	// 获得<Description>108个没房住</Description>
		TiXmlNode* des = Description->FirstChild();	// 获取元素指针	// 获得存储 108个没房住 的指针
		des->SetValue("108个没房住");	// 重新为其设置值

		TiXmlElement *Page = pItem->FirstChildElement("Page");
		TiXmlNode *page = Page->FirstChild();
		page->SetValue("999页");
	}
}

执行后xml文件如下图:
在这里插入图片描述

其实修改属性和修改节点值可以放在同一个for循环中去操作的!

5. 将doc写入xml文件

// 保存到文件	
bool result = tinyXmlDoc->SaveFile(FILE_NAME);
if (result == true) printf("文件写入成功!\n");
else printf("文件写入失败!\n");

6. 修改xml中的节点值,代码汇总

void alt_XML() {
	printf("\n----- alt_XML -----\n");

	// 定义一个TiXmlDocument类指针
	TiXmlDocument* tinyXmlDoc = new TiXmlDocument(FILE_NAME);
	tinyXmlDoc->LoadFile(TIXML_ENCODING_LEGACY);

	// 读取文档声明信息(也就是xml的头部信息:<?xml version="1.0" encoding="utf-8" ?>)
	TiXmlDeclaration *pDeclar = tinyXmlDoc->FirstChild()->ToDeclaration();
	if (pDeclar != NULL) {
		printf("头部信息: version is %s , encoding is %s\n", pDeclar->Version(), pDeclar->Encoding());
	}

	// 得到文件根节点
	TiXmlElement *Library = new TiXmlElement("Library");
	Library = tinyXmlDoc->RootElement();


	TiXmlElement* pItem = Library->FirstChildElement("Book1");
	for (; pItem != NULL; pItem = pItem->NextSiblingElement("Book1")) {

		// 找到属性ID = 1的节点
		if (strcmp(pItem->Attribute("ID"), "1") == 0) {
			// 设置Book1的子节点Description的值
			TiXmlElement* Description = pItem->FirstChildElement("Description");	// 获得<Description>108个没房住</Description>
			TiXmlNode* des = Description->FirstChild();	// 获取元素指针		// 获得存储 108个没房住 的指针
			des->SetValue("108个没房住");	// 重新为其设置值				

			TiXmlElement *Page = pItem->FirstChildElement("Page");
			TiXmlNode *page = Page->FirstChild();
			page->SetValue("999页");
		}

		// 设置属性
		if (strcmp(pItem->Attribute("ID"), "3") == 0) {
			pItem->SetAttribute("Price", "33.33");
		}
	}


	// 保存到文件	
	bool result = tinyXmlDoc->SaveFile(FILE_NAME);
	if (result == true) printf("文件写入成功!\n");
	else printf("文件写入失败!\n");
	//printf("%s\n", tinyXmlDoc->Value());
	// 打印出来看看
	tinyXmlDoc->Print();
}

执行完如下效果:
在这里插入图片描述


六、解析

解析指定节点中值

1. 定义一个xml文件类,并读取文件中的xml内容初始化它

和上面 三、添加 的第1步骤 一样…

2. 获取根节点

和上面 三、添加 的第2步骤 一样…

3. 解析Book节点

当然,前面已将Book节点删掉了,所以获取到的Book为NULL

所以如果是指针,在使用前最好先判断一下再去使用!

TiXmlElement* Book = Library->FirstChildElement("Book");
if (Book) {
	printf("Book = %s\n\n", Book->GetText());
}

4. 解析所有的Book1节点的属性

直接调用Attribute,传入属性名即可获得属性的值;

/* 当有多个相同名字的节点时,可以使用循环进行读取解析 */
// 函数FirstChildElement()	:	找到指定名字的元素
// 函数NextSiblingElement	:	在同一级元素中查找下一个指定名字的元素
TiXmlElement* pItem = Library->FirstChildElement("Book1");
if (pItem) {
	for (; pItem != NULL; pItem = pItem->NextSiblingElement("Book1")) {

		// 解析属性
		printf("ID = %s\n", pItem->Attribute("ID"));
		printf("Name = %s\n", pItem->Attribute("Name"));
		printf("Price = %s\n", pItem->Attribute("Price"));

		printf("\n\n");
	}
}

5. 解析所有的Book1节点的子节点

获得对应解析的节点后,调用GetText可以获得里面的值;

/* 当有多个相同名字的节点时,可以使用循环进行读取解析 */
TiXmlElement* pItem = Library->FirstChildElement("Book1");
if (pItem) {
	for (; pItem != NULL; pItem = pItem->NextSiblingElement("Book1")) {
		// 解析Book1的子节点
		TiXmlElement* Description = pItem->FirstChildElement("Description");
		printf("Description = %s\n", Description->GetText());

		TiXmlElement *Page = pItem->FirstChildElement("Page");
		printf("Page = %s\n", Page->GetText());

		printf("\n\n");
	}
}

解析控制台输出如下
在这里插入图片描述

6. 解析xml节点值,代码汇总

void parse_XML() {
	printf("\n----- parse_XML -----\n");

/* 方式一:当读取有问题时,可以使用下面方式二

	// 定义一个TiXmlDocument类指针
	TiXmlDocument* tinyXmlDoc = new TiXmlDocument;

	// 读取文件中的xml
	if (!tinyXmlDoc->LoadFile(FILE_NAME)) {
		// 读取失败,打印失败原因
		printf("Could not load example xml file %s. Error='%s'\n", FILE_NAME, tinyXmlDoc->ErrorDesc());
		return ;
	}
*/

	// 定义一个TiXmlDocument类指针
	TiXmlDocument* tinyXmlDoc = new TiXmlDocument(FILE_NAME);
	tinyXmlDoc->LoadFile(TIXML_ENCODING_LEGACY);

	// 读取文档声明信息(也就是xml的头部信息:<?xml version="1.0" encoding="utf-8" ?>)
	TiXmlDeclaration* pDeclar = tinyXmlDoc->FirstChild()->ToDeclaration();
	if (pDeclar != NULL) {
		printf("头部信息:version is %s , encoding is %s\n", pDeclar->Version(), pDeclar->Encoding());
	}

	// 得到文件根节点
	TiXmlElement* Library = new TiXmlElement("Library");
	if (Library) {
		Library = tinyXmlDoc->RootElement();
	}
	

	// 解析Book节点
	TiXmlElement* Book = Library->FirstChildElement("Book");
	if (Book) {
		printf("Book = %s\n\n", Book->GetText());
	}
	


	/* 当有多个相同名字的节点时,可以使用循环进行读取解析 */
	// 函数FirstChildElement()	:	找到指定名字的元素
	// 函数NextSiblingElement	:	在同一级元素中查找下一个指定名字的元素
	TiXmlElement* pItem = Library->FirstChildElement("Book1");
	if (pItem) {
		for (; pItem != NULL; pItem = pItem->NextSiblingElement("Book1")) {

			// 解析属性
			printf("ID = %s\n", pItem->Attribute("ID"));
			printf("Name = %s\n", pItem->Attribute("Name"));
			printf("Price = %s\n", pItem->Attribute("Price"));

			// 解析Book1的子节点
			TiXmlElement* Description = pItem->FirstChildElement("Description");
			printf("Description = %s\n", Description->GetText());

			TiXmlElement *Page = pItem->FirstChildElement("Page");
			printf("Page = %s\n", Page->GetText());

			printf("\n\n");
		}
	}
}

七、总结

到此,使用tinyxml操作xml文件的教程已经完毕了,相信学到这里的童鞋们应该会如何使用了,那快做项目去吧!

代码中使用了很多指针,但是都没有进行释放,为什么呢?
我在网上找过了,网上都说,类结束后会自动释放,不知真假!

C++读取XML 本文主要介绍:C++利用库函数TinyXml,读取XML文件。 一、下载TinyXml库文件 TinyXml库文件比较简单,包含一个tinyxml.lib和两个tinyxml.h、tinystr.h文件,库文件下载地址: http://download.youkuaiyun.com/detail/hong__fang/8411043 二、配置VS 在工程目录下创建include文件夹,把两个.h 阅读详情

相关推荐

C++ 使用tinyxml库处理XML文件

TinyXML是一个开源的解析XML的解析库,能够用于C++,能够在Windows或Linux中编译。这个解析库的模型通过解析XML文件,然后在内存中生成DOM模型,从而让我们很方便的遍历这棵XML树。以上就是今天要讲的内容,本文仅仅简单介绍了tinyxml的使用,包括创建XML文件及增删改查的操作演示。

a_13572035650的博客 2173

C++ XML 库 TinyXML2 的基本使用

0.前言 TinyXML-2 是一个简单,小型,高效的 C ++ XML 解析器,可以轻松集成到其他程序中,直接引用源文件的话只需要包含两个文件(h 和 cpp,此外还有个测试文件里面带有 demo)。 TinyXML-2 解析 XML 文档,并以此为基础构建可读取,修改和保存的文档对象模型(DOM)。文档说,在解释 XML 时仅使用 UTF-8 ,假定所有 XML 为 UTF-8 (看了下使用 MSVC 编译器时生成的 XML 文件文本编码使用的本地编码)。该库还支持打印到文件或内存,使用 XMLPr

龚建波 1万+

C++ XML解析实战:TinyXML轻量库核心用法与避坑指南

XML作为一种通用的标记语言,在软件工程中广泛用于配置文件、数据交换和资源描述。其核心原理是基于树形结构的文档对象模型,通过标签和属性组织数据,具有良好的可读性和跨平台性。在C++开发领域,尤其是在嵌入式系统、游戏引擎或对依赖项敏感的项目中,选择一个轻量、高效的XML解析库至关重要。TinyXML正是为此场景设计的经典DOM解析器,它以极简的源码(通常仅两个文件)和零外部依赖著称,能快速集成并高效处理中小型XML文档。其技术价值在于平衡了功能与资源开销,通过直观的节点遍历API(如FirstChildEle

hideto 405

C++ 读取XML文件

c++解析XML文件

congjiaoyan3682的博客 950

osgearth使用tinyxml读写earth文件

【代码】osgearth使用tinyxml读写earth文件。

ljjjjjjjjjjj的博客 270

TinyXML2 实战:C++ 轻量级 XML 解析库集成与避坑指南

在 C++ 工程中,XML 解析常用于配置文件、协议报文等场景,而轻量级解析库能有效降低依赖与内存开销。TinyXML2 以约 2000 行代码实现 DOM 解析,通过内存池管理节点生命周期,避免手动释放,适合嵌入式与资源受限环境。其技术价值在于零依赖、易集成,支持源码直嵌、静态库和包管理器三种方式。应用场景包括游戏存档、嵌入式参数表等。集成时需注意 BOM 处理、属性转换陷阱及遍历删除安全,合理复用文档对象可提升性能。

weixin_33951761的博客 326

C++ XML文件读写及简单封装

C++ xml文件的读写以及简单封装

qq_45482587的博客 1万+

MFC工程中XML解析库选型与TinyXML2集成实践

在Windows平台进行C++开发时,XML作为一种结构化数据格式,常被用于配置文件存储与数据传输。MFC工程中解析XML,开发者往往面临COM接口复杂、内存管理繁琐等难题。从XML解析的基本原理出发,比较MSXML、TinyXML2、Xerces-C++等主流解析库的优劣,可以发现纯C++实现的TinyXML2在轻量集成、资源自动管理和跨平台支持上具有明显优势。它无需初始化COM对象,仅靠两个文件即可接入Visual Studio,贴合MFC原有的编程习惯。针对界面开发中的中文乱码问题,通过UTF-8与C

weixin_29185167的博客 4

tinyXML2

TinyXML-2 是一个简单,小型,高效的 C ++ XML 解析器,可以轻松集成到其他程序中,直接引用源文件的话只需要包含两个文件(h 和 cpp)TinyXML-2 解析 XML 文档,并以此为基础构建可读取,修改和保存的文档对象模型(DOM)。XMLDocument 是 TinyXML2 的核心对象,用于表示整个 XML 文档。它可以用于解析 XML 文件或从头开始创建新的 XML 文档。XMLElement 表示 XML 文档中的元素。每个元素可以包含其他元素、属性和文本内容。XMLElement

wyh3185780的博客 1586

C++读取XML文件

c++读取xml文件c++读取xml文件c++读取xml文件c++读取xml文件c++读取xml文件c++读取xml文件c++读取xml文件c++读取xml文件c++读取xml文件c++读取xml文件c++读取xml文件

c++操作xml文件

可对xml文件进行各种操作,有源代码,包括CXml,CXmlNode,CXmlNodes,CXsl四个类!

tinyxml删除,添加,修改xml文件

TinyXML是一个简单的、小的、最小的、C + + XML解析器,可以很容易地集成到其他项目。它读取XML和XML文档创建c++对象代表。可以操纵的对象,再次改变,并保存为XML。 可以从网站http://sourceforge.net/projects/tinyxml/?source=typ_redirect处下载源码。 下面说下使用: xml内容格式如下:    

DEV_linux的专栏 7282

深入解析V4L2框架与高通KMD在Camera驱动中的协同设计

本文深入解析了V4L2框架与高通KMD在Camera驱动中的协同设计。V4L2作为Linux内核标准视频驱动框架,提供了统一的设备抽象与数据流管理;而高通KMD则在其基础上,通过引入CRM等核心模块,构建了一套针对移动平台复杂相机系统的高效内核态驱动架构,实现了硬件配置与执行的解耦与智能调度。

qq_27496129的博客 1144

C++|读写xml文件开源库tingxml2的使用

C++读写xml文件

编程改变世界。想做一些改变世界的产品。感谢一键三连。 2181

SAP 物料账前期没有运行的解决方法

If you use the actual costing (material ledger), you must have completely closed all period-end closing operations in the actual costing for the penultimate period prior to the period shift. Use the '...

含笑饮砒霜死后更嚣张 3315

HybridCLR热更新打包报错全解析:从原理到实战解决方案

热更新技术是现代游戏和应用开发中实现动态内容交付与Bug修复的核心机制,它允许开发者在无需重新发布完整应用的情况下更新代码逻辑。其原理通常涉及在运行时加载并执行新的代码模块,这要求框架在底层实现安全的代码隔离、内存管理与元数据桥接。在Unity生态中,HybridCLR作为基于IL2CPP的高性能热更新解决方案,通过补充元数据和AOT泛型引用技术,实现了对C#代码的原生级热更支持,显著提升了开发迭代效率与线上问题修复能力。然而,在实际的工程实践中,尤其是在面向Android、iOS等多平台打包构建时,开发者

weixin_29017445的博客 308

C++读写XML文件(增删改查)

将数据库表student_table的增删改查用XML来实现: 其中,conditionMap存储条件语句,where "xxx" = "xxx"(where conditionMap.begin()-&gt;first == conditionMap.begin()-&gt;second) #include &lt;iostream&gt; #include "tinyxml.h" #incl...

浮生流年的博客 7656

平衡电桥检测高压绝缘电阻的原理

检测绝缘漏电的高压拓扑如下:BMU需要连接BAT+,BAT-和PE线,并测量电池总压(Ubatt)和负母线电压(Un),并计算出正母线电压(Up)。

booksyhay的专栏 1万+

轻量级TinyXml2的应用

TinyXML2 是 simple、small、efficient 的基于DOM (Document Object Model,文档对象模型) 的开源 C++ XML文件解析库,可以很方便地应用到现有的项目中。目前,TinyXML1 开发已经停止,所有的开发都转移到了 TinyXML2。TinyXML2 适用于大部分 C/C++ 的项目,经得住考验,是最好的选择。较 TinyXML1 而言,TinyXML2 化繁为简,使用时,而 TinyXML1 需要包含 6 个文件,一般生成静态链接库供项目使用。

WSTONECH的博客 503

Android 12 系统横屏时,开机动画有两秒显示不全

平板系统默认横屏时,开机会旋转90度,显示的分辨率WxH,会变成HxW.但又会很快被SurfaceFlinger的SurfaceFlinger::processDisplayChanged 娇正。所以为了保险,可以在开机动画没结束之前,禁止旋转事件。在Android 12 产品定制化开发中,由于系统默认方向为竖屏,平板电脑要横屏显示。系统在开机时,有时因为旋转,会出现动画只显示一部分。

448313096@qq.com 1174

基于Simulink的电力电子系统电磁兼容性(EMC)仿真

在电力电子系统中,由于高频开关器件的存在,会产生大量的电磁干扰(EMI),这对系统的稳定性和可靠性提出了挑战。Simulink 提供了一个强大的仿真环境,可以用来设计、分析和验证电力电子系统的电磁兼容性。本教程将详细介绍如何使用 Simulink 进行电力电子系统的电磁兼容性仿真。通过本教程,我们详细介绍了如何使用 Simulink 进行电力电子系统的电磁兼容性仿真。为了模拟电力电子系统中的电磁干扰(EMI),我们需要添加噪声源模块。为了更好地分析系统的电磁兼容性特性,可以在模型中添加频谱分析工具。

amy_mhd的博客 1126

TinyXML2完整指南:C++轻量XML解析库实战与最佳实践

XML作为一种通用的标记语言,在数据交换和配置存储领域应用广泛。其核心原理是通过标签定义数据结构,实现信息的层次化组织与跨平台传输。在C++开发中,高效处理XML数据是提升工程效率的关键技术之一。TinyXML2作为一款轻量级XML解析库,通过精简的API设计和明确的内存管理模型,为开发者提供了直观且高性能的解决方案。它在嵌入式系统、游戏开发、桌面应用等场景中,尤其适合处理配置文件、网络API数据交换等任务。本文聚焦于TinyXML2的核心API、内存管理策略及错误处理机制,通过实战案例展示如何构建一个完整

weixin_29191761的博客 334

【Bug已解决】NCCL timeout for validation 解决方案

训练用多卡 DDP / FSDP 正常,但一到或者进程直接 hang 在 eval 的某个集合通信上。最迷惑的是:训练阶段(有集合通信)完全正常,偏偏 eval 阶段(看起来更轻量)超时。因为 eval 阶段某些 rank 没参与 collective,导致参与的那部分 rank 永远等不到同伴。

一键难忘的博客 141

基于TinyXML的XML文档操作(部分测试代码)

#include &lt;stdio.h&gt; #include "tinyxml.h" #include "tinystr.h" //#pragma warning (disable : 4996) /*==============全局数据===============*/ const char *substr = "■■"; enum OBJTYPE{ON_CHOSE =4,ON_JUD...

hereson 187

五、MT8168 音频驱动之SPEAKER

本章主要讲解MT8168平台的内部SPEAKER驱动配置。分为HP接法和LINE OUT接法。2.1.3 audio_custom_exp.h设置。2.1.4 mixer_paths.xml设置。2.2.3 mixer_paths.xml设置。2.1.2 ProjectConfig 设置。2.2.2 ProjectConfig 设置。2.2.1 deconfig设置。2.1.1 DTS设置。......

Joon2020的博客 1664

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

上一篇: QT vs2017《五子棋》人机对战项目
下一篇: C/C++ 三种方式获得文件的大小
cpp_learners
博客等级 码龄7年 1526粉丝 274原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

cpp_learners

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

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

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

打赏作者

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

抵扣说明:

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

余额充值