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

Posted cpp_learners

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++ 使用 tinyxml库 操作XML格式文件(创建插入删除修改解析)相关的知识,希望对你有一定的参考价值。

前段时间学习了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 = tempor

以上是关于C/C++ 使用 tinyxml库 操作XML格式文件(创建插入删除修改解析)的主要内容,如果未能解决你的问题,请参考以下文章

C++使用TinyXml(开源库)读取*.XMl文件

windows客户端开发--使用tinyxml库解析xml文件

C++ 使用TinyXML详解

使用TinyXML进行XML操作

无法打开输入文件tinyxml_STL.lib

熊二做了一个xml报文处理的开源库easyxml