Boost库XML 不用指定路径遍历所有内容

Boost库实现XML文件 不用指定路径遍历所有内容

XML:可扩展标记语言,互联网数据传输的重要工具,用来标记数据、定义数据类型。
Boost库中的property_tree是一个保存了多个属性值的树形结构,用类似路径的的方式访问任意节点,且每个节点可以用迭代器的的方式遍历子节点。
目的:现在想做一个工具,在不知道XML根节点的情况下遍历出所有的内容,再进行对某个节点的内容更新并写入
自己以前对XML只是了解,简单的读取数据进行处理。在书上和网上找的相关例子均是已经知道根节点在遍历获取其内容的,自己参考了《Boost程序库完全开发指南》和网上的博客实现了自己想要的功能,特此记录。

Boost库:包含头文件:

#include "boost/property_tree/ptree.hpp"
#include "boost/property_tree/xml_parser.hpp"
using namespace boost::property_tree;

因为要重新生成XML文件,所以读取到的每个节点都需要保存信息,定义结构如下:

//保存节点信息
struct  XmlNode_s
{
	std::string strNodeName; //当前节点名字
	std::unordered_map<std::string, std::string>  xmlattr; //当前节点的属性
	list<std::string>  listSubName; //子节点名字
	std::string strParentName; //父节点 记录了从根节点到上一个节点的名字,用"."隔开 
	std::string strValue; //当前节点的值
};

参见Boost的property_tree库的核心类basic_ptree摘要,value_type是一个std::pair,节点的数据结构,first是节点的属性,second是节点自身。获取属性值是需要在属性名字前加上:"<xmlattr>."

递归解析XML,在读XML文件时,传入的ptree对象直接传给解析函数

list<XmlNode_s> listNode;
ptree pxml;
std::string strFile = "./1.xml";
//xml格式化
read_xml(strFile, pxml, boost::property_tree::xml_parser::trim_whitespace); 
XMLParse(pxml, listNode);
//boost::property_tree::xml_parser::trim_whitespace 
//读的时候传入这个参数可以忽略空格换行符等,    在生成XML的时候可以生成标准格式的XML文件
    
//递归解析xml文件
void XMLParse(const ptree &pxml, std::list<XmlNode_s> &listNode, std::string strNode = "")
{
	for (const auto &node : pxml)
	{
		std::string  NodeKey = node.first.data(); //属性或者子节点
		if (NodeKey == "<xmlattr>") //判断是否是属性
		{
			continue; //属性已经在父节点中做了保存
		}
		XmlNode_s xmlnode;
		xmlnode.strNodeName = std::string(node.first.data()); //节点名
		xmlnode.strValue = node.second.data(); //值
		xmlnode.strParentName = strNode; //父节点是外面传入进来的
	//获取该节点的属性
	for (const auto &attr : node.second)
	{
		std::string strAttr = attr.first.data();
		if (std::string(strAttr) == "<xmlattr>") //是属性
		{
			//获取属性的值
			for (auto &att : attr.second)
			{
				cout << att.first.data() << endl; //属性名字
				cout << att.second.data() << endl; //属性值
				xmlnode.xmlattr[att.first.data()] = att.second.data();
			}
		}
		else //节点自身
		{
			xmlnode.listSubName.emplace_back(strAttr); //当前节点的子节点名字
		}
	}
	listNode.emplace_back(xmlnode); //保存当前节点
	if (!NodeKey.empty()) //当前节点
	{
		xmlnode.xmlattr.clear();
		//获取子节点信息 递归
		std::string strParentName;
		if (!xmlnode.strParentName.empty())
		{
			strParentName += xmlnode.strParentName + "." + xmlnode.strNodeName;
		}
		else
		{
			strParentName = xmlnode.strNodeName;
		} 
		//生成父节点 写入XML的时候需要知道父节点
		XMLParse(node.second, listNode, strParentName); //递归遍历
	}
}

}

生成XML文件

//设置节点内容
void MakeXmlNode(ptree &pt, XmlNode_s &node)
{
	pt.put_value(node.strValue); //添加值
	for (auto &itA : node.xmlattr)
	{
		std::string strA = "<xmlattr>.";
		pt.add(strA + itA.first, itA.second); //设置属性
	}
}

//添加节点
void AddXmlNode(ptree &pt, XmlNode_s &node, std::string &strPreNode)
{
	auto itPos = strPreNode.find("."); //如果没有"."表示根节点
	if (itPos == std::string::npos)
	{
		ptree tmp;
		MakeXmlNode(tmp, node);
		if (pt.size() == 0) //节点第一次出现,直接添加
		{
			pt.add_child(node.strNodeName, tmp);
		}
		else
		{//有多个相同节点,取最后一个,否则数据将只会放在第一个  因为遍历的时候是先把当前节点遍历完了再回来遍历的。类似于二叉树的先序遍历
			pt.back().second.add_child(node.strNodeName, tmp); //取最后一个节点  
		}
	}
	else
	{
		std::string strSub = strPreNode.substr(itPos + 1);
		auto &ptTmp = pt.back().second; //要引用,否则写入的信息将不会在父节点上
		AddXmlNode(ptTmp, node, strSub); //递归写入  
	}
}

//生成XML
void WriteXML(std::string &strFile, std::list<XmlNode_s> &listNode)
{
	ptree ptRoot; //根节点
	for (auto it = listNode.begin(); it != listNode.end(); ++it)
	{
		AddXmlNode(ptRoot, *it, it->strParentName); //添加节点
	}
	auto settings = boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
	write_xml(strFile, ptRoot, std::locale(), settings);
}

XML文件内容:

<?xml version="1.0" encoding="utf-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
	<Events>
		<Event Name="SalesWareHouseOut" MainAction="WareHouseOut">
			<DataField>
				<Data Code="81302280400502614672" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400502623396" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400502630200" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400502643774" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400502663146" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400499127973" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
			</DataField>
		</Event>
	</Events>
	<Events>
		<Event Name="SalesWareHouseOut" MainAction="WareHouseOut">
			<DataField>
				<Data Code="81302280400502614672" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400502623396" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400502630200" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400502643774" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400502663146" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
				<Data Code="81302280400499127973" CorpOrderID="20190527102500" Actor="1111" ActDate="2019-05-27 10:26:54" WrongCode="False" ToCorpID=""/>
			</DataField>
		</Event>
	</Events>
</Document>
Boost中,可以使用boost::graph中的深度优先搜索算法(Depth-First Search,DFS)来遍历点到点之间的所有路径。下面是一个简单的示例代码,演示了如何使用Boost来实现这个功能: ```cpp #include <iostream> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/depth_first_search.hpp> // 定义图类型 typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS> Graph; // 定义DFS访问器 struct DFSVisitor : public boost::default_dfs_visitor { void discover_vertex(Graph::vertex_descriptor v, const Graph& g) const { std::cout << v << " "; // 输出访问到的顶点 } }; int main() { // 创建图 Graph g; // 添加顶点 Graph::vertex_descriptor v0 = boost::add_vertex(g); Graph::vertex_descriptor v1 = boost::add_vertex(g); Graph::vertex_descriptor v2 = boost::add_vertex(g); Graph::vertex_descriptor v3 = boost::add_vertex(g); // 添加边 boost::add_edge(v0, v1, g); boost::add_edge(v1, v2, g); boost::add_edge(v2, v3, g); boost::add_edge(v0, v3, g); // 遍历点到点的所有路径 DFSVisitor visitor; boost::depth_first_search(g, visitor); return 0; } ``` 在上述示例代码中,首先我们定义了一个简单的有向图类型Graph,使用`boost::adjacency_list`表示图的结构。然后,我们添加了一些顶点和边,用于构建一个简单的图。 接下来,我们定义了一个DFSVisitor类,继承自`boost::default_dfs_visitor`,重写了其中的`discover_vertex`方法,在该方法中输出访问到的顶点。 最后,在主函数中,我们创建了一个DFSVisitor对象visitor,并使用`boost::depth_first_search`函数来执行深度优先搜索算法。通过这个遍历过程,我们可以输出点到点之间的所有路径。 请注意,这只是一个简单的示例,您可以据具体需求进行修改和扩展。此外,在实际应用中,您可能还需要处理图中可能存在的环路、路径搜索的终止条件等情况,以获取更加准确和完整的路径信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值