Boost读写xml

Boost读写xml

文章目录

  • Boost读写xml
    • 写在前面
    • 准备工作
    • 简单读写
      • 写xml
      • 读xml
        • 键值查找
        • 遍历
      • 设置默认值
      • 异常处理
    • 具有属性的xml
      • 写xml
      • 读xml
        • 键值查找
        • 遍历
    • 知识补充

写在前面

​ 前面我们讲过了如何使用Boost读写ini文件,这一篇我们将介绍如何用Boost读写xml文件。

​ XML (Extensible Markup Language) 是一种通用的数据描述语言,它提供了一种独立于平台和编程语言的方式来存储和交换结构化数据。XML 文件采用标签的形式描述数据,使得数据具有自我描述的特点,更易于理解和管理。XML 广泛应用于各种领域,如 Web 开发、配置管理、数据交换等,它支持数据验证、数据转换等功能,并提供了丰富的编程接口,方便开发人员在应用程序中解析和操作 XML 数据。

  • 测试环境:Win11 + Vs2015 + Boost1.80
  • 这里默认读者已经安装好Boost库,不知道如何安装可查看Boost编译使用_boost 编译 使用

准备工作

  • 需要用到的头文件
#include <boost/property_tree/xml_parser.hpp>
#include <boost/property_tree/ptree.hpp>

简单读写

  • Boost中读写xmlini文件都是使用property_tree来完成的,所以大部分东西是通用的。
  • 需要注意的是ini文件没有节点嵌套,所有节点都在根节点下的一级节点,xml是有多级节点的,且允许多级嵌套,但根节点只有一个。
  • 下面将展示简单的xml文件的读写功能,进阶用法请看具有属性的xml

写xml

void write_xml_file_test() {
    using	boost::property_tree::ptree;

	ptree root;	// 创建根节点

	ptree student_pt;
	student_pt.put<std::string > ("Name", "Xiao Ming");
	student_pt.put<uint8_t>("Age", 15);
	student_pt.put<std::string>("Sex", "man");
	student_pt.put<uint8_t>("Class", 1);

	root.add_child("XmlTest.Student", student_pt);	// 将子节点添加到根节点中
	// 添加setting 确保输出文件内容有缩进
	auto setting = boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
	write_xml("example2.xml", root, std::locale(), setting);
}

<?xml version="1.0" encoding="utf-8"?>
<XmlTest>
	<Student>
		<Name>Xiao Ming</Name>
		<Age>15</Age>
		<Sex>man</Sex>
		<Class>1</Class>
	</Student>
</XmlTest>

读xml

键值查找
void read_xml_from_key(std::string fileName) {
	using	boost::property_tree::ptree;
	ptree root;
	read_xml(fileName, root);
	
	// 这里的root是根节点,想要直接访问元素,需要全名称描述(XmlTest.Student.Name)
	// 键值查找,如果键不存在,则触发异常
	std::string st_name = root.get<std::string>("XmlTest.Student.Name");	
	int st_age = root.get<int>("XmlTest.Student.Age");
	std::string st_sex = root.get<std::string>("XmlTest.Student.Sex");
	int st_class = root.get<int>("XmlTest.Student.Class");

	std::cout << "Name: " << st_name << std::endl;
	std::cout << "Age: " << st_age << std::endl;
	std::cout << "Sex: " << st_sex << std::endl;
	std::cout << "Class: " << st_class << std::endl;

	// student_node节点下是Student的元素,可直接获取(Name)
	ptree student_node = root.get_child("XmlTest.Student");  // 获取 Student 子节点
	st_name = student_node.get<std::string>("Name");
	std::cout << "Name: " << st_name << std::endl;
}

/* output:
Name: Xiao Ming
Age: 15
Sex: man
Class: 1
Name: Xiao Ming
*/
遍历
void read_xml_file_text(std::string fileName) {
	using	boost::property_tree::ptree;
	ptree root;
	read_xml(fileName, root);
	ptree student_node(root.get_child("XmlTest.Student"));	// 获取 Student 子节点

	// 遍历子节点
	std::cout << "method 1:\n";
	for (ptree::iterator it = student_node.begin(); it != student_node.end(); ++it) {
		std::cout << "\t" << it->first;
		std::cout << ":" << it->second.data() << std::endl;
	}
	std::cout << "method 2:\n";
	for (const auto &t : student_node) {
		std::cout << "\t" << t.first;
		std::cout << ":" << t.second.data() << std::endl;
	}
}

/* output:
method 1:
        Name:Xiao Ming
        Age:15
        Sex:man
        Class:1
method 2:
        Name:Xiao Ming
        Age:15
        Sex:man
        Class:1
*/

设置默认值

  • property_tree设置默认的方式是一样的,我们在Boost读写ini文件中已经说明过了。

    // 获取当前节点不存在的节点时,无默认值,引发程序异常
    int st_heigh = student_node.get<int>("Height");
    // 获取当前节点不存在的节点时,有默认值,不会引发异常
    int st_heigh = student_node.get<int>("Height"175);
    

异常处理

  • 读写xml异常一般有以下几种:

    • 读取文件不存在
    • 读取节点、属性等不存在
    • 属性内容转换失败
  • 最简单的方式是使用 std::exception 捕获所有的异常,但不利于异常分开处理

try{
	...    
	int st_heigh = student_node.get<int>("Height"); // 引发异常
    ...    
}
catch (const boost::property_tree::ptree_bad_path& e) {			//无法访问节点异常
    std::cerr << "Node access error: " << e.what() << std::endl;
}
catch (const boost::property_tree::xml_parser_error& e) {		// 语法错误异常
    std::cerr << "XML parsing error: " << e.what() << std::endl;
}
catch (std::exception &e) {	
    std::cerr << e.what() << "\n";
}
/* output:
No such node (Height)
*/

具有属性的xml

  • xml文件除了多级节点外,每个节点、元素都可以设置属性值,类似于以下这种,一个元素可有多个属性。

    <Name type="string">Xiao xiao</Name>
    
  • 属性值必须被引号包围,单双引号都可,更多详细的关于xml的文件格式可参考知识补充

写xml

void write_xml_has_property(std::string fileName) {
	using	boost::property_tree::ptree;
	ptree root;
   
	// 创建Student 子节点
	ptree student_node;
	student_node.put<std::string>("Name", "Xiao xiao");
	student_node.put("Name.<xmlattr>.type", "string");
	student_node.put<int>("Age",  16);
	student_node.put("Age.<xmlattr>.type", "int");
	student_node.put<std::string>("Sex", "man");
	student_node.put("Sex.<xmlattr>.type", "string");
	student_node.put<int>("Class", 1);
	student_node.put("Class.<xmlattr>.type", "int");
	root.add_child("XmlTest.Student",student_node);

	auto setting = boost::property_tree::xml_writer_make_settings<std::string>('\t', 1);
	write_xml(fileName, root, std::locale(), setting);
}
<?xml version="1.0" encoding="utf-8"?>
<XmlTest>
	<Student>
		<Name type="string">Xiao xiao</Name>
		<Age type="int">16</Age>
		<Sex type="string">man</Sex>
		<Class type="int">1</Class>
	</Student>
</XmlTest>

读xml

键值查找
void read_xml_has_property(std::string fileName) {
	try {
		using	boost::property_tree::ptree;
		ptree root_node;
		read_xml(fileName, root_node);

		ptree student_node(root_node.get_child("XmlTest.Student"));

		std::string st_name = student_node.get<std::string>("Name");
		std::string st_name_type = student_node.get<std::string>("Name.<xmlattr>.type");
		int st_age = student_node.get<int>("Age");
		std::string st_age_type = student_node.get<std::string>("Age.<xmlattr>.type");
		std::string st_sex = student_node.get<std::string>("Sex");
		std::string st_sex_type = student_node.get<std::string>("Sex.<xmlattr>.type");
		int st_class = student_node.get<int>("Class");
		std::string st_class_type = student_node.get<std::string>("Class.<xmlattr>.type");

		std::cout << "Name: "<<st_name_type<<" "<< st_name << std::endl;
		std::cout << "Age: " << st_age_type << " " << st_age << std::endl;
		std::cout << "Sex: " << st_sex_type << " " << st_sex << std::endl;
		std::cout << "Class: " << st_class_type << " " << st_class << std::endl;
	}
	catch (std::exception &e) {
		std::cerr << e.what() << "\n";
	}
}

/* output:
Name: string Xiao xiao
Age: int 16
Sex: string man
Class: int 1
*/
遍历
void read_xml_has_property2(std::string fileName) {
	try {
		using	boost::property_tree::ptree;
		ptree root_node;
		read_xml(fileName, root_node);
        
		ptree student_node(root_node.get_child("XmlTest.Student"));
		// 遍历 Student节点和属性
		for (const auto &t : student_node) {
			std::cout << t.first << ": " <<
				t.second.get<std::string >("<xmlattr>.type") << " "<<
				t.second.data() << "\n";
		}
	}
	catch (std::exception &e) {
		std::cerr << e.what() << "\n";
	}
}

/* output:
Name: string Xiao xiao
Age: int 16
Sex: string man
Class: int 1
*/

知识补充

  • 这里对xml语法进行一个简要介绍

  • xml文件语法类似于HTML文件格式通过标签表示节点或者元素。

    <a>name</a>
    
  • 允许多层嵌套,可设置属性对元素进行描述。

  • 更多详细可参考网络上的xml文件格式等。

  • XML 语法

上一篇:微信小程序播放编码为 video/mp4;codecs=vp8 opus 的视频没有声音


下一篇:MongoDB聚合运算符:$sqrt