rapidxml 文件读写,增加删除节点

RapidXml是指 XML DOM解析工具包,是一个快速的读写xml文件的库文件(hpp)。本文旨在提供RapidXml文件读写操作,以及对节点的增加、删除、编译提供一个测试用例,以免忘记。

1. 读取XML

#include "rapidxml.hpp"
#include "rapidxml_utils.hpp"
#include "rapidxml_print.hpp"
#include <vector>
#include <string>
#include <map>
#include <set>
#include <iostream>
#include <sstream>
#include <io.h>


void str2int(int& int_tmp, const std::string& string_tmp)
{
	std::stringstream stream(string_tmp);
	stream >> int_tmp;
}

void str2float(float& float_tmp, const std::string& string_tmp)
{
	float_tmp = atof(string_tmp.c_str());
}

void splitLabels(const std::string& labels, std::vector<std::string>& splitalbelres)
{
	std::string result;
	std::stringstream input(labels);
	while (input >> result)
	{
		splitalbelres.push_back(result);
	}
}

void readFunctionParam(rapidxml::xml_node<char>* FunctionNode)
{
	rapidxml::xml_node<char>* DeteNode = FunctionNode->first_node("Detectors");
	if (DeteNode != nullptr)
	{
		for (rapidxml::xml_node<char>* node = DeteNode->first_node("iter"); node != nullptr; node = node->next_sibling())
		{
			std::string name = "";
			std::string version = "";
			std::string label = "";
			float fConfidence = 0.0;
			int	iShowWin = 0;
			int iIsStandard = 0;
			std::set<int> setUsefulLabel;

			rapidxml::xml_node<>* pName = node->first_node("name");
			if (pName != nullptr)
			{
				name = pName->value();
			}

			rapidxml::xml_node<>* pVersion = node->first_node("version");
			if (pVersion != nullptr)
			{
				version = pVersion->value();
			}

			rapidxml::xml_node<>* pConf = node->first_node("confidence");
			if (pConf != nullptr)
			{
				str2float(fConfidence, pConf->value());
			}

			rapidxml::xml_node<>* pShowWin = node->first_node("bshowDebugWin");
			if (pShowWin != nullptr)
			{
				str2int(iShowWin, pShowWin->value());
			}

			rapidxml::xml_node<>* pIsStandard = node->first_node("bStandard");
			if (pIsStandard != nullptr)
			{
				str2int(iIsStandard, pIsStandard->value());
			}

			rapidxml::xml_node<>* pUsefulLabel = node->first_node("usefulLabel");
			if (pUsefulLabel != nullptr)
			{
				label = pUsefulLabel->value();

				std::vector<std::string> splitlabelres;
				splitLabels(label, splitlabelres);
				for (int i = 0; i < splitlabelres.size(); i++)
				{
					setUsefulLabel.insert(std::atoi(splitlabelres[i].c_str()));
				}
			}
		}

		rapidxml::xml_node<char>* pShowreportNode = FunctionNode->first_node("ShowReportWin");
		if (pShowreportNode != nullptr)
		{
			int	iShowReportWin = 0;
			str2int(iShowReportWin, pShowreportNode->value());
		}
	}
}

void ReadParam(const rapidxml::xml_document<>& pDoc)
{
	//获取根节点
	rapidxml::xml_node<char>* root = pDoc.first_node("config");

	//找到采样帧率节点
	int iSampleFrequency;
	rapidxml::xml_node<>* samplefre = root->first_node("SampleFrequency");
	str2int(iSampleFrequency, samplefre->value());

	//找到功能节点
	std::string sFunctionName = "SMOKEFireDetection";
	rapidxml::xml_node<>* intrusion = root->first_node(sFunctionName.c_str());
	if (intrusion != nullptr)
	{
		readFunctionParam(intrusion);
	}

}

void readXMLByFile(const std::string& xmlpath)
{
	/************************************************************************
	file类
	data()				返回 char* 的xml文本内容
	size()				返回 unsigned int的文本数据长度
	定义:				rapidxml::file<0> valName("xmlpath");

	xml_document类
	parse(Ch *text)		将文本数据解析为DOM tree
	clear()				清空DOM tree
	定义:				rapidxml::xml_document<0> doc;
	************************************************************************/
	try
	{
		// 用file文件读入缓冲区
		rapidxml::file<> fdoc(xmlpath.c_str());
		// 打印从文件中读取的内容
		std::cout << fdoc.data();
		// 解析获取DOM实例
		rapidxml::xml_document<> doc;
		doc.parse<0>(fdoc.data());

		ReadParam(doc);

		doc.clear();
	}
	catch (rapidxml::parse_error e)
	{
		std::cout << e.what() << std::endl;

		return;
	}

}

static const int buf_len = 2048;
static char buf[buf_len] = { 0 };
void readXMLByStream(const std::string& xmlpath)
{
	try
	{
		// 清空缓冲区
		memset(buf, 0, buf_len);

		// 判断文件是否存在
		if (_access(xmlpath.c_str(), 0) == -1)
		{
			std::cout << "xml file " << xmlpath << "is not exits!" << std::endl;
			return;
		}

		// 实例化文件读取流
		std::ifstream infile(xmlpath, std::ios::in);
		if (!infile)
		{
			std::cout << "file stream instance error!" << std::endl;
			return;
		}

		// 读取文件内容到缓冲区
		infile.read(buf, buf_len);

		// 输出文件内容
		std::cout << buf << std::endl;

		// 实例化DOM
		rapidxml::xml_document<> doc;
		doc.parse<0>(buf);

		ReadParam(doc);

		doc.clear();
		infile.close();
	}
	catch (rapidxml::parse_error e)
	{
		std::cout << e.what() << std::endl;

		return;
	}

}

void main()
{
	std::string xmlpath = "ReadExample.xml";

	readXMLByFile(xmlpath);
	
	readXMLByStream(xmlpath);

	std::system("pause");
	
}

其对应的xml文件如下所示:

<config>
<SampleFrequency>25</SampleFrequency>

<SMOKEFireDetection>
  <Detectors>
    <iter>
      <name>fire</name>
      <version>1.3.0</version>
      <confidence>0.5</confidence>
      <bshowDebugWin>1</bshowDebugWin>
      <usefulLabel>
        3 4 5
      </usefulLabel>
	  <bStandard>1</bStandard>
    </iter>
    <iter>
      <name>smoke</name>
      <version>1.6.0</version>
      <confidence>0.2</confidence>
      <bshowDebugWin>1</bshowDebugWin>
      <usefulLabel>
        4
      </usefulLabel>
      <bStandard>1</bStandard>
    </iter>
	<iter>
      <name>motionanalyze</name>
      <version></version>
      <confidence></confidence>
      <bshowDebugWin>1</bshowDebugWin>
      <usefulLabel>
      </usefulLabel>
    </iter>
  </Detectors>
  
  <ShowReportWin>1</ShowReportWin>
</SMOKEFireDetection>

</config>

2. 创建XML文件

#include "rapidxml.hpp"
#include "rapidxml_utils.hpp"
#include "rapidxml_print.hpp"
#include <iostream>
#include <string>
#include <fstream>
#include <io.h>
#include <stdlib.h>

void CreateXml(const std::string& XMLFileName)
{
	//保存Annotation, 把识别结果写进xml

	// DOM
	rapidxml::xml_document<> doc;

	// node_declaration
	//rapidxml::xml_node<>* declaration = doc.allocate_node(rapidxml::node_declaration);
	//declaration->append_attribute(doc.allocate_attribute("version", "1.0"));
	//declaration->append_attribute(doc.allocate_attribute("encoding", "utf-8"));
	//doc.append_node(declaration);

	// node_pi
	rapidxml::xml_node<>* root = doc.allocate_node(rapidxml::node_pi, doc.allocate_string("xml version='1.0' encoding='utf-8'"));
	doc.append_node(root);

	// node_comment
	rapidxml::xml_node<>* comment = doc.allocate_node(rapidxml::node_comment, 0, " 这是对目标的Annotation保存格式 ");
	doc.append_node(comment);

	// node_element 
	rapidxml::xml_node<>* node = doc.allocate_node(rapidxml::node_element, "annotation", "information");
	doc.append_node(node);

	// node_data
	rapidxml::xml_node<>* folder = doc.allocate_node(rapidxml::node_element, "folder", "VOC2007");
	node->append_node(folder);

	rapidxml::xml_node<>* filename = doc.allocate_node(rapidxml::node_element, "filename", XMLFileName.c_str());
	node->append_node(filename);

	// node_element with value
	rapidxml::xml_node<>* source = doc.allocate_node(rapidxml::node_element, "source", nullptr);
	source->append_node(doc.allocate_node(rapidxml::node_element, "database", "My VOC2007 Databas"));
	source->append_node(doc.allocate_node(rapidxml::node_element, "annotation", "VOC2007"));
	source->append_node(doc.allocate_node(rapidxml::node_element, "image", "flickr"));
	source->append_node(doc.allocate_node(rapidxml::node_element, "flickrid", "nullptr"));
	node->append_node(source);

	rapidxml::xml_node<>* owner = doc.allocate_node(rapidxml::node_element, "owner", nullptr);
	owner->append_node(doc.allocate_node(rapidxml::node_element, "flickrid", "nullptr"));
	owner->append_node(doc.allocate_node(rapidxml::node_element, "name", "aware"));
	node->append_node(owner);

	rapidxml::xml_node<>* size = doc.allocate_node(rapidxml::node_element, "size", nullptr);
	int width = 1920;
	char cw[128];
	_itoa_s(width, cw, 128, 10);
	size->append_node(doc.allocate_node(rapidxml::node_element, "width", cw));
	int height = 1080;
	char ch[128];
	_itoa_s(height, ch, 128, 10);
	size->append_node(doc.allocate_node(rapidxml::node_element, "height", ch));
	size->append_node(doc.allocate_node(rapidxml::node_element, "depth", "3"));
	node->append_node(size);

	rapidxml::xml_node<>* segmented = doc.allocate_node(rapidxml::node_element, "segmented", "0");
	node->append_node(segmented);

	for (int i = 0; i < 2; i++)
	{
		// node_comment
		rapidxml::xml_node<>* comment = doc.allocate_node(rapidxml::node_comment, 0, " 目标的位置状态信息 ");
		node->append_node(comment);

		rapidxml::xml_node<>* object = doc.allocate_node(rapidxml::node_element, "object", nullptr);
		node->append_node(object);

		object->append_node(doc.allocate_node(rapidxml::node_element, "name", doc.allocate_string("example")));
		object->append_node(doc.allocate_node(rapidxml::node_element, "pose", "Unspecified"));
		object->append_node(doc.allocate_node(rapidxml::node_element, "truncated", "0"));
		object->append_node(doc.allocate_node(rapidxml::node_element, "difficult", "0"));

		rapidxml::xml_node<>* bndbox = doc.allocate_node(rapidxml::node_element, "bndbox", nullptr);
		object->append_node(bndbox);
		bndbox->append_node(doc.allocate_node(rapidxml::node_element, "xmin", "11"));
		bndbox->append_node(doc.allocate_node(rapidxml::node_element, "ymin", "20"));
		bndbox->append_node(doc.allocate_node(rapidxml::node_element, "xmax", "1000"));
		bndbox->append_node(doc.allocate_node(rapidxml::node_element, "ymax", "600"));

		//打印整个XML内容
		std::string text;
		rapidxml::print(std::back_inserter(text), doc, 0);
		std::cout << text << std::endl;
	}
	
	//打印整个XML内容
	std::string text;
	rapidxml::print(std::back_inserter(text), doc, 0);
	std::cout << text << std::endl;

	// 输出DOM到文件
	std::ofstream outfile(XMLFileName.c_str(), std::ios::out);	//ofstream默认时,如果文件存在则覆盖原来的内容,不存在则新建
	if (outfile)
	{
		outfile << doc;
		outfile.close();
	}

	doc.clear();
}


void main()
{
	const std::string Xmlfilename = "WriteExample.xml";

	CreateXml(Xmlfilename);

	std::system("pause");

}

其结果如下图所示:

<?xml version='1.0' encoding='utf-8' ?>
<!--这是对目标的Annotation保存格式-->
<annotation>
	<folder>VOC2007</folder>
	<filename>WriteExample.xml</filename>
	<source>
		<database>My VOC2007 Databas</database>
		<annotation>VOC2007</annotation>
		<image>flickr</image>
		<flickrid>nullptr</flickrid>
	</source>
	<owner>
		<flickrid>nullptr</flickrid>
		<name>aware</name>
	</owner>
	<size>
		<width>1920</width>
		<height>1080</height>
		<depth>3</depth>
	</size>
	<segmented>0</segmented>
	<!--目标的位置状态信息 -->
	<object>
		<name>example</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>11</xmin>
			<ymin>20</ymin>
			<xmax>1000</xmax>
			<ymax>600</ymax>
		</bndbox>
	</object>
	<!--目标的位置状态信息 -->
	<object>
		<name>example</name>
		<pose>Unspecified</pose>
		<truncated>0</truncated>
		<difficult>0</difficult>
		<bndbox>
			<xmin>11</xmin>
			<ymin>20</ymin>
			<xmax>1000</xmax>
			<ymax>600</ymax>
		</bndbox>
	</object>
</annotation>

3. 修改及增加删除

首先是一些对xml的节点解释:
xml_node类
1)node_type type() const; 获取结点类型 获取的类型是枚举的
2)Ch* name() const; 获取结点名
3)std::size_t name_size() const; 获取结点名长度
4)Ch* value() const; 获取结点值
5)std::size_t value_size() const; 获取结点值长度
6)xml_node* first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取DOM Tree第一个子结点的指针
第一个参数为节点名,如果给定第一个参数为”a”, 则该函数寻找结点名为a的第一个子结点;第二个参数为结点名长度
7)xml_node* last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取DOM Tree最后一个子结点的指针
参数含义同上
8)xml_attribute* first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取结点的第一个属性指针
9)xml_attribute* next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取结点的下一个属性指针
10)xml_attribute* last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取结点的最后一个属性指针
11)xml_node* previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取上一个同级结点的指针
12)xml_node* next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取下一个同级结点的指针
13)xml_attribute* first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取第一个同级结点的指针
14)xml_attribute* last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取最后一个同级结点的指针
15)void insert_node(xml_node< Ch > *where, xml_node< Ch > *child); 在第一个参数指向的结点之前,插入一个结点
xml_attribute类
1)xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const; 获取前一个属性
2)xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const;获取后一个属性

 

#include <iostream>
#include <string>
#include <fstream>
#include "string.h"
#include "rapidxml.hpp"
#include "rapidxml_print.hpp"
#include "rapidxml_utils.hpp"


void modifyXML(const char * file_name)
{
	std::string text;

	//用file解析DOM时必须是绝对路径
	rapidxml::file<> fdoc(file_name);

	//打印读取的文件
	std::cout<<fdoc.data();

	rapidxml::xml_document<> doc;
	doc.parse<0>(fdoc.data());

	//取得根节点
	rapidxml::xml_node<>* root = doc.first_node("config");
	//删除第一个元素
	if (root->first_node() != nullptr)
		root->remove_first_node();
	text = "\r\n移除根节点下的第一个元素节点\r\n";
	rapidxml::print(std::back_inserter(text), doc, 0);		//doc内容输出到text尾处
	std::cout << text << std::endl;


	rapidxml::xml_node<>* FunctionNode = root->first_node("SMOKEFireDetection");
	if (FunctionNode != nullptr)
		std::cout << "SMOKEFireDetection is not null" << std::endl;
	else
		return;

	//删除FunctionNode节点的最后一个元素
	if (FunctionNode->last_node() != nullptr)
		FunctionNode->remove_last_node();
	text = "\r\n移除根节点下的FunctionNode的最后一个元素节点\r\n";
	rapidxml::print(std::back_inserter(text), doc, 0);
	std::cout << text << std::endl;

	rapidxml::xml_node<char>* DeteNode = FunctionNode->first_node("Detectors");
	if (DeteNode != nullptr)
	{
		for (rapidxml::xml_node<char>* node = DeteNode->first_node("iter"); node != nullptr; node = node->next_sibling())
		{
			rapidxml::xml_node<>* pName = node->first_node("name");
			if (pName != nullptr && std::string(pName->value()) == "fire")
			{
				//移除根节点下的FunctionNode结点下第一个循环节点下的bStandardNode节点
				rapidxml::xml_node<> *bStandardNode = node->first_node("bStandard");
				if (bStandardNode != nullptr)
				{
					node->remove_node(bStandardNode);
				}

				//移除根节点下的FunctionNode结点下第一个循环节点下的的usefulLabelNode节点
				rapidxml::xml_node<> *usefulLabelNode = node->first_node("usefulLabel");
				if (usefulLabelNode != nullptr)
				{
					node->remove_node(usefulLabelNode);
				}
				text = "\r\n移除根节点下的FunctionNode结点下第一个循环节点下的bStandardNode节点和usefulLabelNode节点\r\n";
				rapidxml::print(std::back_inserter(text), doc, 0);
				std::cout << text << std::endl;
				continue;
			}
			else if (pName != nullptr && std::string(pName->value()) == "motionanalyze")
			{
				//移除根节点下的FunctionNode结点下第三个循环节点下的所有节点
				DeteNode->remove_node(node);
					break;
			}
		}
	}
	text = "\r\n移除根节点下的FunctionNode结点下第三个循环节点下的所有节点\r\n";
	rapidxml::print(std::back_inserter(text), doc, 0);
	std::cout << text << std::endl;



	//在FunctionNode的Detectors节点处插入一个KeyBorad节点
	rapidxml::xml_node<>* Graphics = FunctionNode->first_node("Detectors");//找到Graphics节点
	rapidxml::xml_node<>* new_node = doc.allocate_node(rapidxml::node_element, "KeyBorad", "Logitech");
	new_node->append_attribute(doc.allocate_attribute("Interface", "USB"));
	FunctionNode->insert_node(Graphics, new_node);

	text = "\r\n在FunctionNode的Detectors节点下面插入一个KeyBorad节点\r\n";
	rapidxml::print(std::back_inserter(text), doc, 0);
	std::cout << text << std::endl;

	写入文件
	std::ofstream out("1.xml");
	out << doc;
}

int main()
{
	const char *file_name = "E:\\VS2015Project\\ReadXmlWriteXml\\ReadXmlWriteXml\\RapidExample.xml";

	modifyXML(file_name);

	std::system("pause");

	return 0;
}

原始数据为:

<config>
<SampleFrequency>25</SampleFrequency>

<SMOKEFireDetection>
  <Detectors>
    <iter>
      <name>fire</name>
      <version>1.3.0</version>
      <confidence>0.5</confidence>
      <bshowDebugWin>1</bshowDebugWin>
      <usefulLabel>3 4 5</usefulLabel>
	  <bStandard>1</bStandard>
    </iter>
    <iter>
      <name>smoke</name>
      <version>1.6.0</version>
      <confidence>0.2</confidence>
      <bshowDebugWin>1</bshowDebugWin>
      <usefulLabel>4</usefulLabel>
      <bStandard>1</bStandard>
    </iter>
	<iter>
      <name>motionanalyze</name>
      <version></version>
      <confidence></confidence>
      <bshowDebugWin>1</bshowDebugWin>
      <usefulLabel>
      </usefulLabel>
    </iter>
  </Detectors>
  
  <ShowReportWin>1</ShowReportWin>
</SMOKEFireDetection>

</config>

修改后为:

<config>
	<SMOKEFireDetection>
		<KeyBorad Interface="USB">Logitech</KeyBorad>
		<Detectors>
			<iter>
				<name>fire</name>
				<version>1.3.0</version>
				<confidence>0.5</confidence>
				<bshowDebugWin>1</bshowDebugWin>
			</iter>
			<iter>
				<name>smoke</name>
				<version>1.6.0</version>
				<confidence>0.2</confidence>
				<bshowDebugWin>1</bshowDebugWin>
				<usefulLabel>4</usefulLabel>
				<bStandard>1</bStandard>
			</iter>
		</Detectors>
	</SMOKEFireDetection>
</config>

感谢 https://www.cnblogs.com/MenAngel/p/11552588.html

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值