C++ 使用 tinyxml2 解析&创建 xml

目录

1. github 地址

2. 使用

3. 解析xml demo

4. 注意点

5. 解析效果展示

6.创建xml

7.创建xml效果展示

8. 完整的示例,添加Vector

9. 参考


1. github 地址

GitHub - leethomason/tinyxml2: TinyXML2 is a simple, small, efficient, C++ XML parser that can be easily integrated into other programs.

2. 使用

直接把里面的 “tinyxml2.h” 和 “tinyxml2.cpp” 加到自己工程,使用include "tinyxml2.h" 头文件就好

3. 解析xml demo

xml内容如下:

<?xml version="1.0" encoding="utf-8"?>
<annotation>
	<folder>UAV_data</folder>
	<filename>NG0_202303032032377079.xml</filename>
	<size>
		<width>3070</width>
		<height>1600</height>
		<depth>3</depth>
	</size>
	<segmented>0</segmented>
	<object>
		<name>round</name>
		<location>0</location>
		<diffcult>0</diffcult>
		<diffcultt>3</diffcultt>
		<bndbox>
			<xmin>1405</xmin>
			<ymin>1237</ymin>
			<xmax>1628</xmax>
			<ymax>1421</ymax>
		</bndbox>
	</object>
	<object>
		<name>long</name>
		<diffcult>0</diffcult>
		<location>0</location>
		<bndbox>
			<xmin>2337</xmin>
			<ymin>1225</ymin>
			<xmax>2580</xmax>
			<ymax>1405</ymax>
		</bndbox>
	</object>
</annotation>

代码如下:

#include <iostream>  
#include"tinyxml2.h"  
using namespace std;
using namespace tinyxml2;

void decodeXml(std::string xmlPath)
{
	//声明
	XMLDocument xml;
	string value, text;
	//导入xml文件
	if (xml.LoadFile(xmlPath.c_str()) != XML_SUCCESS)
	{
		return;
	}
	//判断头文件是否为空
	XMLElement* rootNode = xml.RootElement();
	if (rootNode == NULL)
	{
		return;
	}
	XMLElement* surface = rootNode->FirstChildElement("object");
	while (surface)
	{
		XMLElement* surfaceChild = surface->FirstChildElement();
		while (surfaceChild)
		{
			// surfaceChild->Value() 是获取节点的名称
			value = surfaceChild->Value();
			if (value == "bndbox")
			{
				XMLElement* bndboxChild = surfaceChild->FirstChildElement();

				// 因为bndbox节点里面又是节点,所以需要进行循环以及找NextSiblingElement
				while (bndboxChild)
				{
					value = bndboxChild->Value();
					text = bndboxChild->GetText();
					bndboxChild = bndboxChild->NextSiblingElement();
					std::cout << value << ": " << text << std::endl;
				}
			}
			else
			{
				text = surfaceChild->GetText();
				std::cout << value << ": " << text << std::endl;
			}
			surfaceChild = surfaceChild->NextSiblingElement();
		}
		surface = surface->NextSiblingElement();
	}

}

int main()
{
	decodeXml("Z:/temp/cppSaveXml/NG0_202303032032377079.xml");
    return 0;
}

4. 注意点

1. 整体的逻辑其实就是一层一层的遍历,先找到需要遍历的那个节点,然后通过while和NextSiblingElement来进行循环;

2. surfaceChild->Value() 是获取节点的名称,如果 <name>round</name> 得到的是name。这里需要注意的就是,如果节点里面又有节点,这个时候就不能用 surfaceChild->GetText() 来获取里面的值,因为里面是节点,不是单纯的值,如果仍然使用GetText()会报错。
这个时候就需要用FirstChildElement() 这个方法来获取里面第一个节点的内容,然后再通过while进行循环遍历,如下

if (value == "bndbox")
{
	XMLElement* bndboxChild = surfaceChild->FirstChildElement();

	// 因为bndbox节点里面又是节点,所以需要进行循环以及找NextSiblingElement
	while (bndboxChild)
	{
		value = bndboxChild->Value();
		text = bndboxChild->GetText();
		bndboxChild = bndboxChild->NextSiblingElement();
	}
}

3. 总的来说,就是一层一层递归,递归的时候需要判断是否是单节点还是里面还包含节点

5. 解析效果展示

6.创建xml

逻辑就是创建一个根节点,然后再依次创建子节点,然后子节点的 text 属性值设置,然后再把属性值与对应的子节点绑定,然后子节点在与根节点绑定

需要创建如下xml:

<?xml version="1.0" encoding="utf-8"?>
<annotation>
	<filename>NG0_202303032032377079.xml</filename>
	<size>
		<width>3070</width>
		<height>1600</height>
		<depth>3</depth>
	</size>
	<object>
		<name>round</name>
		<bndbox>
			<xmin>1405</xmin>
			<ymin>1237</ymin>
			<xmax>1628</xmax>
			<ymax>1421</ymax>
		</bndbox>
	</object>
	<object>
		<name>long</name>
		<bndbox>
			<xmin>2337</xmin>
			<ymin>1225</ymin>
			<xmax>2580</xmax>
			<ymax>1405</ymax>
		</bndbox>
	</object>
</annotation>

创建代码如下:

XMLElement* getNeedNode(XMLDocument& xml, const char* nodeName, const char* nodeText)
{
	XMLElement* node = xml.NewElement(nodeName);
	XMLText* node_text = xml.NewText(nodeText);
	node->InsertFirstChild(node_text);
	return node;
}

void encode()
{
	XMLDocument xml;
	// 插入声明
	XMLDeclaration* declaration = xml.NewDeclaration();
	xml.InsertFirstChild(declaration);

	// 插入根节点
	XMLElement* rootNode = xml.NewElement("annotation");
	xml.InsertEndChild(rootNode);

	/*------------------新建一个filename节点--------------------------*/
	XMLElement* filename = xml.NewElement("filename");
	// 设置节点中的值
	XMLText* filename_text = xml.NewText("NG0_202303032032377079.xml");
	// 把节点中的值与filename节点链接起来
	filename->InsertFirstChild(filename_text);
	// 将 filename 节点与根节点绑定起来
	rootNode->InsertEndChild(filename);

	/*------------------新建一个size节点--------------------------*/
	XMLElement* size = xml.NewElement("size");

	/*------------------新建一个width节点--------------------------*/
	XMLElement* width = xml.NewElement("width");
	XMLText* width_text = xml.NewText("3070");
	width->InsertFirstChild(width_text);

	/*------------------新建一个height节点--------------------------*/
	XMLElement* height = xml.NewElement("height");
	XMLText* height_text = xml.NewText("1600");
	height->InsertFirstChild(height_text);

	/*------------------新建一个depth节点--------------------------*/
	XMLElement* depth = xml.NewElement("depth");
	XMLText* depth_text = xml.NewText("3");
	depth->InsertFirstChild(depth_text);

	// 将 width,height,depth 与 size 节点绑在一起
	size->InsertEndChild(width);
	size->InsertEndChild(height);
	size->InsertEndChild(depth);

	/*------------------新建第一个object节点--------------------------*/
	XMLElement* object = xml.NewElement("object");

	XMLElement* name = xml.NewElement("name");
	XMLText* name_text = xml.NewText("round");
	name->InsertFirstChild(name_text);

	XMLElement* bndbox = xml.NewElement("bndbox");

	// getNeedNode 方法为啥是引用,因为是要同一个 XMLDocument 这样才可以绑定, 所以传引用
	XMLElement* xmin = getNeedNode(xml, "xmin", "1405");
	XMLElement* ymin = getNeedNode(xml, "ymin", "1237");
	XMLElement* xmax = getNeedNode(xml, "xmax", "1628");
	XMLElement* ymax = getNeedNode(xml, "ymax", "1421");
	bndbox->InsertEndChild(xmin);
	bndbox->InsertEndChild(ymin);
	bndbox->InsertEndChild(xmax);
	bndbox->InsertEndChild(ymax);

	object->InsertEndChild(name);
	object->InsertEndChild(bndbox);
	rootNode->InsertEndChild(object);

	/*------------------新建第二个object节点--------------------------*/
	object = xml.NewElement("object");

	name = xml.NewElement("name");
	name_text = xml.NewText("long");
	name->InsertFirstChild(name_text);

	bndbox = xml.NewElement("bndbox");
	xmin = getNeedNode(xml, "xmin", "2337");
	ymin = getNeedNode(xml, "ymin", "1225");
	xmax = getNeedNode(xml, "xmax", "2580");
	ymax = getNeedNode(xml, "ymax", "1405");
	bndbox->InsertEndChild(xmin);
	bndbox->InsertEndChild(ymin);
	bndbox->InsertEndChild(xmax);
	bndbox->InsertEndChild(ymax);

	object->InsertEndChild(name);
	object->InsertEndChild(bndbox);
	rootNode->InsertEndChild(object);

	
	xml.SaveFile("Z:/temp/cppSaveXml/temp.xml");

}

int main()
{
	encode();
    return 0;
}

7.创建xml效果展示

8. 完整的示例,添加Vector

生成xml,使用传入vector,然后循环遍历vector

#include <iostream>  
#include <vector>
#include <string>
#include"tinyxml2.h"  
//#include "xmlNode.h"

using namespace tinyxml2;

struct Node
{
	int imageW;
	int imageH;
	int channel = 3;
	int xmin;
	int ymin;
	int xmax;
	int ymax;
	std::string label;
	float prob;
	Node(int in_w, int in_h, int in_xmin, int in_ymin, int in_xmax, int in_ymax, std::string in_label, float in_prob)
	{
		imageW = in_w;
		imageH = in_h;
		xmin = in_xmin;
		ymin = in_ymin;;
		xmax = in_xmax;;
		ymax = in_ymax;;
		label = in_label;;
		prob = in_prob;;
	}
};

void decodeXml(std::string xmlPath)
{
	//声明
	XMLDocument xml;
	std::string value, text;
	//导入xml文件
	if (xml.LoadFile(xmlPath.c_str()) != XML_SUCCESS)
	{
		return;
	}
	//判断头文件是否为空
	XMLElement* rootNode = xml.RootElement();
	if (rootNode == NULL)
	{
		return;
	}
	XMLElement* filename = rootNode->FirstChildElement("filename");
	const char* getFileName = filename->GetText();
	std::cout << getFileName << std::endl;

	XMLElement* surface = rootNode->FirstChildElement("object");
	while (surface)
	{
		XMLElement* surfaceChild = surface->FirstChildElement();
		while (surfaceChild)
		{
			// surfaceChild->Value() 是获取节点的名称
			value = surfaceChild->Value();
			if (value == "bndbox")
			{
				XMLElement* bndboxChild = surfaceChild->FirstChildElement();

				// 因为bndbox节点里面又是节点,所以需要进行循环以及找NextSiblingElement
				while (bndboxChild)
				{
					value = bndboxChild->Value();
					text = bndboxChild->GetText();
					bndboxChild = bndboxChild->NextSiblingElement();
					std::cout << value << ": " << text << std::endl;
				}
			}
			else
			{
				text = surfaceChild->GetText();
				std::cout << value << ": " << text << std::endl;
			}
			surfaceChild = surfaceChild->NextSiblingElement();
		}
		surface = surface->NextSiblingElement();
	}

}

XMLElement* getNeedNode(XMLDocument& xml, const char* nodeName, const char* nodeText)
{
	XMLElement* node = xml.NewElement(nodeName);
	XMLText* node_text = xml.NewText(nodeText);
	node->InsertFirstChild(node_text);
	return node;
}

void encodeXml(const char* inSaveXmlDir, int inW, int inH, std::vector<Node> inAllNode)
{
	XMLDocument xml;
	// 插入声明
	XMLDeclaration* declaration = xml.NewDeclaration();
	xml.InsertFirstChild(declaration);

	// 插入根节点
	XMLElement* rootNode = xml.NewElement("annotation");
	xml.InsertEndChild(rootNode);

	/*------------------新建一个filename节点--------------------------*/
	XMLElement* filename = xml.NewElement("filename");
	// 设置节点中的值
	XMLText* filename_text = xml.NewText(inSaveXmlDir);
	// 把节点中的值与filename节点链接起来
	filename->InsertFirstChild(filename_text);
	// 将 filename 节点与根节点绑定起来
	rootNode->InsertEndChild(filename);

	/*------------------新建一个size节点--------------------------*/
	XMLElement* size = xml.NewElement("size");

	/*------------------新建一个width节点--------------------------*/
	XMLElement* width = xml.NewElement("width");
	XMLText* width_text = xml.NewText(std::to_string(inW).c_str());
	width->InsertFirstChild(width_text);

	/*------------------新建一个height节点--------------------------*/
	XMLElement* height = xml.NewElement("height");
	XMLText* height_text = xml.NewText(std::to_string(inH).c_str());
	height->InsertFirstChild(height_text);

	/*------------------新建一个depth节点--------------------------*/
	XMLElement* depth = xml.NewElement("depth");
	XMLText* depth_text = xml.NewText("3");
	depth->InsertFirstChild(depth_text);

	// 将 width,height,depth 与 size 节点绑在一起
	size->InsertEndChild(width);
	size->InsertEndChild(height);
	size->InsertEndChild(depth);

	rootNode->InsertEndChild(filename);
	rootNode->InsertEndChild(size);

	/*------------------新建第一个object节点--------------------------*/
	for (auto node : inAllNode)
	{
		XMLElement* object = xml.NewElement("object");

		XMLElement* name = xml.NewElement("name");
		XMLText* name_text = xml.NewText(node.label.c_str());
		name->InsertFirstChild(name_text);

		XMLElement* bndbox = xml.NewElement("bndbox");

		// getNeedNode 方法为啥是引用,因为是要同一个 XMLDocument 这样才可以绑定, 所以传引用
		XMLElement* xmin = getNeedNode(xml, "xmin", std::to_string(node.xmin).c_str());
		XMLElement* ymin = getNeedNode(xml, "ymin", std::to_string(node.ymin).c_str());
		XMLElement* xmax = getNeedNode(xml, "xmax", std::to_string(node.xmax).c_str());
		XMLElement* ymax = getNeedNode(xml, "ymax", std::to_string(node.ymax).c_str());
		bndbox->InsertEndChild(xmin);
		bndbox->InsertEndChild(ymin);
		bndbox->InsertEndChild(xmax);
		bndbox->InsertEndChild(ymax);

		object->InsertEndChild(name);
		object->InsertEndChild(bndbox);
		rootNode->InsertEndChild(object);
	}
	
	xml.SaveFile(inSaveXmlDir);

}



int main()
{
	const char* saveXmlDir = "Z:/temp/cppSaveXml/1.xml";
	std::vector<Node> allNode;
	Node nodeOne = { 1, 2, 3, 4, 5, 6, "1", 0.1 };
	Node nodeTwo = { 1, 2, 3, 4, 5, 6, "2", 0.1 };
	allNode.push_back(nodeOne);
	allNode.push_back(nodeTwo);
	encodeXml(saveXmlDir, 3070, 1600, allNode);
    return 0;
}

效果展示

9. 参考

1. C++解析XML文件_c++ xml解析_时·风·人的博客-CSDN博客

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: tinyxml2是一个开源的、轻量级的XML解析库。它是对C++标准库的简单封装,用于处理XML文件的读取、解析以及创建和修改XML文件。 tinyxml2库具有以下特点和功能: 1. 易于使用tinyxml2库的API设计简单、易于理解和操作,可以方便地读取和解析XML文件中的数据。 2. 快速且内存占用低:tinyxml2库使用了基于迭代器的解析算法,解析速度快,而且内存占用较小。 3. 跨平台兼容性:tinyxml2库可以在不同的操作系统和编译器上运行,具有良好的跨平台兼容性。 4. 支持Unicode:tinyxml2库支持Unicode编码的XML文件,可以正确地处理各种国际化字符。 5. 支持创建和修改XML文件:tinyxml2库可以方便地创建和修改XML文件,可以添加、删除和修改XML节点及其属性。 6. 错误处理能力强:tinyxml2库提供了丰富的错误处理机制,可以捕获和处理解析XML文件中的错误。 7. 可靠性高:tinyxml2库在解析XML文件时具有良好的鲁棒性,可以处理复杂的XML文件结构和错误格式的XML文件。 总之,tinyxml2是一个功能强大、可靠高效的XML解析库,适用于各种C++项目中需要处理XML文件的场景。无论是读取、解析创建还是修改XML文件,tinyxml2都提供了简单易用的API,并且具有较好的跨平台兼容性和Unicode支持。 ### 回答2: TinyXML2是一个轻量级的C++库,用于解析和生成XML文档。它是TinyXML库的升级版本,提供了更好的性能和易于使用的API。 TinyXML2具有简单直观的接口,支持XML的基本操作,如加载、解析、访问和修改XML文档。它提供了一些类和函数,可以方便地在代码中处理XML数据。 TinyXML2支持从文件、字符串和内存中加载XML文档。它可以解析XML元素、属性、文本内容和注释,并提供了访问和修改这些数据的接口。用于访问和修改XML数据的API是面向对象的,使得操作XML文档更加方便和直观。 TinyXML2还提供了将XML文档序列化为字符串的功能,以及将XML数据写入到文件中的功能。这使得可以方便地将XML文档保存到文件或其他储存介质中,或者将XML数据通过网络传输。 TinyXML2使用C++语言编写,具有良好的可移植性和跨平台性。它不依赖于任何外部库,只需要包含头文件即可使用。这使得它非常适合用于嵌入式系统或其他资源有限的环境中。 总之,TinyXML2是一个功能强大、易于使用的C++库,用于解析和生成XML文档。它提供了简单直观的API,支持XML的基本操作,同时具有良好的可移植性和跨平台性。无论是在桌面应用程序、嵌入式系统还是其他需要处理XML的项目中,TinyXML2都是一个很好的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值