使用 RapidXML 实现 C++ 中的 XML 文件读取与生成,特别适合需要快速处理 XML 的场景
使用 RapidXML 实现 C++ 中的 XML 文件读取与生成
RapidXML 是一个轻量级、高性能的 C++ XML 解析器,特别适合需要快速处理 XML 的场景。下面我将展示如何使用 RapidXML 进行 XML 文件的读取和生成。
1. 准备工作
首先需要下载 RapidXML 头文件,它只有头文件,无需编译。
cpp
// 下载 rapidxml.hpp 并包含在项目中 #include "rapidxml.hpp" #include "rapidxml_utils.hpp" #include "rapidxml_print.hpp" #include <iostream> #include <fstream> #include <vector> #include <string>
2. 读取 XML 文件
cpp
// 定义数据结构来存储解析的 XML 内容
struct Person {std::string name;int age;std::string email;
};class XMLReader {
public:// 解析 XML 文件static std::vector<Person> parsePeople(const std::string& filename) {std::vector<Person> people;try {// 读取文件内容rapidxml::file<> xmlFile(filename.c_str());rapidxml::xml_document<> doc;// 解析 XMLdoc.parse<0>(xmlFile.data());// 获取根节点rapidxml::xml_node<>* root = doc.first_node("people");if (!root) {std::cerr << "根节点 'people' 未找到!" << std::endl;return people;}// 遍历所有 person 节点for (rapidxml::xml_node<>* personNode = root->first_node("person");personNode; personNode = personNode->next_sibling()) {Person person;// 读取属性rapidxml::xml_attribute<>* idAttr = personNode->first_attribute("id");if (idAttr) {std::cout << "处理 ID: " << idAttr->value() << std::endl;
rd.xjyl.gov.cn/upload/1982074954433658880.html
rd.xjyl.gov.cn/upload/1982074954467213312.html
rd.xjyl.gov.cn/upload/1982074954488184832.html
rd.xjyl.gov.cn/upload/1982074954521739264.html
rd.xjyl.gov.cn/upload/1982074954664345600.html
rd.xjyl.gov.cn/upload/1982074954785980416.html
rd.xjyl.gov.cn/upload/1982074954790174720.html
rd.xjyl.gov.cn/upload/1982074954962141185.html
rd.xjyl.gov.cn/upload/1982074954962141184.html
rd.xjyl.gov.cn/upload/1982074955008278528.html
rd.xjyl.gov.cn/upload/1982074955121524736.html
rd.xjyl.gov.cn/upload/1982074955104747520.html
rd.xjyl.gov.cn/upload/1982074955180244992.html
rd.xjyl.gov.cn/upload/1982074955201216512.html
rd.xjyl.gov.cn/upload/1982074955197022208.html
rd.xjyl.gov.cn/upload/1982074955314462720.html
rd.xjyl.gov.cn/upload/1982074955348017152.html
rd.xjyl.gov.cn/upload/1982074955431903232.html
rd.xjyl.gov.cn/upload/1982074955608064000.html
rd.xjyl.gov.cn/upload/1982074955624841216.html
rd.xjyl.gov.cn/upload/1982074955771641856.html
rd.xjyl.gov.cn/upload/1982074955775836160.html
rd.xjyl.gov.cn/upload/1982074955771641857.html
rd.xjyl.gov.cn/upload/1982074955838750720.html}// 读取子节点for (rapidxml::xml_node<>* child = personNode->first_node();child; child = child->next_sibling()) {std::string nodeName = child->name();std::string nodeValue = child->value();if (nodeName == "name") {person.name = nodeValue;} else if (nodeName == "age") {person.age = std::stoi(nodeValue);} else if (nodeName == "email") {person.email = nodeValue;}}people.push_back(person);}} catch (const std::exception& e) {std::cerr << "解析 XML 时出错: " << e.what() << std::endl;}return people;}// 打印解析结果static void printPeople(const std::vector<Person>& people) {for (const auto& person : people) {std::cout << "姓名: " << person.name << ", 年龄: " << person.age << ", 邮箱: " << person.email << std::endl;}}
};3. 生成 XML 文件
cpp
class XMLWriter {
public:// 创建 XML 文档static void createPeopleXML(const std::vector<Person>& people, const std::string& filename) {rapidxml::xml_document<> doc;// 创建 XML 声明rapidxml::xml_node<>* decl = doc.allocate_node(rapidxml::node_declaration);decl->append_attribute(doc.allocate_attribute("version", "1.0"));decl->append_attribute(doc.allocate_attribute("encoding", "UTF-8"));doc.append_node(decl);// 创建根节点rapidxml::xml_node<>* root = doc.allocate_node(rapidxml::node_element, "people");doc.append_node(root);int id = 1;for (const auto& person : people) {// 创建 person 节点rapidxml::xml_node<>* personNode = doc.allocate_node(rapidxml::node_element, "person");// 添加 id 属性char* idStr = doc.allocate_string(std::to_string(id++).c_str());personNode->append_attribute(doc.allocate_attribute("id", idStr));// 创建子节点addChildNode(doc, personNode, "name", person.name);char* ageStr = doc.allocate_string(std::to_string(person.age).c_str());addChildNode(doc, personNode, "age", ageStr);addChildNode(doc, personNode, "email", person.email);root->append_node(personNode);}// 保存到文件saveToFile(doc, filename);}private:// 添加子节点辅助函数static void addChildNode(rapidxml::xml_document<>& doc, rapidxml::xml_node<>* parent, const std::string& name, const std::string& value) {char* nodeName = doc.allocate_string(name.c_str());char* nodeValue = doc.allocate_string(value.c_str());rapidxml::xml_node<>* child = doc.allocate_node(rapidxml::node_element, nodeName, nodeValue);parent->append_node(child);}// 保存文件辅助函数static void saveToFile(rapidxml::xml_document<>& doc, const std::string& filename) {std::ofstream file(filename);if (!file.is_open()) {std::cerr << "无法创建文件: " << filename << std::endl;return;}file << doc;file.close();std::cout << "XML 文件已保存: " << filename << std::endl;}
};4. 完整示例
cpp
#include <iostream>
#include <vector>
#include <string>// 假设已经包含了 RapidXML 头文件int main() {// 示例数据std::vector<Person> people = {{"张三", 25, "zhangsan@example.com"},{"李四", 30, "lisi@example.com"},{"王五", 28, "wangwu@example.com"}};// 生成 XML 文件std::string outputFile = "people.xml";XMLWriter::createPeopleXML(people, outputFile);// 读取并解析 XML 文件std::vector<Person> parsedPeople = XMLReader::parsePeople(outputFile);// 打印解析结果std::cout << "\n解析结果:" << std::endl;XMLReader::printPeople(parsedPeople);return 0;
}5. 示例 XML 文件
生成的 people.xml 文件内容如下:
xml
<?xml version="1.0" encoding="UTF-8"?> <people><person id="1"><name>张三</name><age>25</age><email>zhangsan@example.com</email></person><person id="2"><name>李四</name><age>30</age><email>lisi@example.com</email></person><person id="3"><name>王五</name><age>28</age><email>wangwu@example.com</email></person> </people>
6. 关键要点
内存管理: RapidXML 使用原地解析,不复制字符串数据,因此源数据必须保持有效
性能: RapidXML 是性能最优的 XML 解析器之一
简单性: API 设计简洁,学习曲线平缓
局限性: 不支持 DTD 验证和 XPath
7. 错误处理增强版
cpp
class SafeXMLParser {
public:static std::vector<Person> safeParse(const std::string& filename) {std::vector<Person> people;try {rapidxml::file<> xmlFile(filename.c_str());rapidxml::xml_document<> doc;doc.parse<0>(xmlFile.data());rapidxml::xml_node<>* root = doc.first_node("people");if (!root) {throw std::runtime_error("缺少根节点 'people'");}for (rapidxml::xml_node<>* personNode = root->first_node("person");personNode; personNode = personNode->next_sibling()) {Person person;bool hasName = false;bool hasAge = false;for (rapidxml::xml_node<>* child = personNode->first_node();child; child = child->next_sibling()) {std::string nodeName = child->name();std::string nodeValue = child->value();if (nodeName == "name") {person.name = nodeValue;hasName = true;} else if (nodeName == "age") {try {person.age = std::stoi(nodeValue);hasAge = true;} catch (const std::exception&) {std::cerr << "警告: 无效的年龄值: " << nodeValue << std::endl;
rd.xjyl.gov.cn/upload/1982074955859722240.html
rd.xjyl.gov.cn/upload/1982074955905859584.html
rd.xjyl.gov.cn/upload/1982074955935219712.html
rd.xjyl.gov.cn/upload/1982074956027494401.html
rd.xjyl.gov.cn/upload/1982074956027494400.html
rd.xjyl.gov.cn/upload/1982074956035883008.html
rd.xjyl.gov.cn/upload/1982074956061048832.html
rd.xjyl.gov.cn/upload/1982074956069437440.html
rd.xjyl.gov.cn/upload/1982074956228820992.html
rd.xjyl.gov.cn/upload/1982074956249792512.html
rd.xjyl.gov.cn/upload/1982074956404981760.html
rd.xjyl.gov.cn/upload/1982074956421758976.html
rd.xjyl.gov.cn/upload/1982074956442730496.html
rd.xjyl.gov.cn/upload/1982074956627279872.html
rd.xjyl.gov.cn/upload/1982074956656640001.html
rd.xjyl.gov.cn/upload/1982074956656640000.html
rd.xjyl.gov.cn/upload/1982074956866355200.html
rd.xjyl.gov.cn/upload/1982074956866355201.html
rd.xjyl.gov.cn/upload/1982074957042515968.html
rd.xjyl.gov.cn/upload/1982074957122207744.html
rd.xjyl.gov.cn/upload/1982074957151567872.html
rd.xjyl.gov.cn/upload/1982074957273202688.html
rd.xjyl.gov.cn/upload/1982074957269008384.html
rd.xjyl.gov.cn/upload/1982074957285785600.html
rd.xjyl.gov.cn/upload/1982074957285785601.html
rd.xjyl.gov.cn/upload/1982074957357088769.html}} else if (nodeName == "email") {person.email = nodeValue;}}if (hasName && hasAge) {people.push_back(person);} else {std::cerr << "警告: 跳过不完整的 person 记录" << std::endl;}}} catch (const std::exception& e) {std::cerr << "XML 解析错误: " << e.what() << std::endl;}return people;}
};这个完整的示例展示了如何使用 RapidXML 进行 XML 文件的读取和生成,包括错误处理、内存管理和数据结构的封装。
