使用pugixml编写一个xml工具类满足以下要求:1.可以依据xpath对xml进行增删改查。2.操作时必须保证数据的一致性。3.满足事务
cpp
#include <iostream>
#include <string>
#include <vector>
#include "pugixml.hpp"
class XmlTool {
public:
explicit XmlTool(const std::string& xmlContent) {
try {
if (!doc.load_string(xmlContent.c_str())) {
throw std::runtime_error("Failed to load XML content.");
}
originalDoc.reset(doc); // 保存原始文档副本
} catch (const std::bad_alloc& e) {
throw std::runtime_error(std::string("Memory allocation failed: ") + e.what());
}
}
void add(const std::string& xpath, const std::string& newNode) {
try {
pugi::xpath_node node = doc.select_node(xpath.c_str());
if (!node) {
throw std::runtime_error("XPath not found.");
}
pugi::xml_node parentNode = node.node();
pugi::xml_document tempDoc;
tempDoc.load_string(newNode.c_str());
parentNode.append_copy(tempDoc.first_child());
} catch (const std::bad_alloc& e) {
throw std::runtime_error(std::string("Memory allocation failed during add: ") + e.what());
} catch (const std::exception& e) {
throw;
}
}
void remove(const std::string& xpath) {
try {
pugi::xpath_node node = doc.select_node(xpath.c_str());
if (!node) {
throw std::runtime_error("XPath not found.");
}
pugi::xml_node targetNode = node.node();
targetNode.parent().remove_child(targetNode);
} catch (const std::exception& e) {
throw;
}
}
void modify(const std::string& xpath, const std::string& newValue) {
try {
pugi::xpath_node node = doc.select_node(xpath.c_str());
if (!node) {
throw std::runtime_error("XPath not found.");
}
// 分段处理属性值
const size_t chunkSize = 1000; // 每次处理的字符数,可以根据需要调整
pugi::xml_node xmlNode = node.node();
xmlNode.text().set(""); // 清空原有内容
for (size_t i = 0; i < newValue.size(); i += chunkSize) {
std::string chunk = newValue.substr(i, chunkSize);
xmlNode.text().append_buffer(chunk.c_str(), chunk.size());
}
} catch (const std::bad_alloc& e) {
throw std::runtime_error(std::string("Memory allocation failed during modify: ") + e.what());
} catch (const std::exception& e) {
throw;
}
}
void commit() {
try {
originalDoc.reset(doc);
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to commit changes: ") + e.what());
}
}
void rollback() {
try {
doc.reset(originalDoc);
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to rollback changes: ") + e.what());
}
}
std::string getXml() const {
try {
std::ostringstream oss;
doc.save(oss);
return oss.str();
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to retrieve XML content: ") + e.what());
}
}
private:
pugi::xml_document doc;
pugi::xml_document originalDoc;
};
class XmlManager {
public:
void addXmlDocument(const std::string& xmlContent) {
try {
xmlTools.emplace_back(xmlContent);
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to add XML document: ") + e.what());
}
}
void add(const std::string& xpath, const std::string& newNode, size_t docIndex) {
try {
if (docIndex >= xmlTools.size()) {
throw std::out_of_range("Document index out of range.");
}
xmlTools[docIndex].add(xpath, newNode);
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to add node: ") + e.what());
}
}
void remove(const std::string& xpath, size_t docIndex) {
try {
if (docIndex >= xmlTools.size()) {
throw std::out_of_range("Document index out of range.");
}
xmlTools[docIndex].remove(xpath);
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to remove node: ") + e.what());
}
}
void modify(const std::string& xpath, const std::string& newValue, size_t docIndex) {
try {
if (docIndex >= xmlTools.size()) {
throw std::out_of_range("Document index out of range.");
}
xmlTools[docIndex].modify(xpath, newValue);
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to modify node: ") + e.what());
}
}
void commitAll() {
try {
for (auto& xmlTool : xmlTools) {
xmlTool.commit();
}
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to commit changes: ") + e.what());
}
}
void rollbackAll() {
try {
for (auto& xmlTool : xmlTools) {
xmlTool.rollback();
}
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to rollback changes: ") + e.what());
}
}
void printAllXml() const {
try {
for (size_t i = 0; i < xmlTools.size(); ++i) {
std::cout << "XML Document " << i + 1 << ":\n" << xmlTools[i].getXml() << std::endl;
}
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Failed to print XML documents: ") + e.what());
}
}
private:
std::vector<XmlTool> xmlTools;
};
int main() {
std::string xmlContent1 = R"(
<root>
<item id="1">First</item>
<item id="2">Second</item>
</root>
)";
std::string xmlContent2 = R"(
<data>
<entry id="a">Alpha</entry>
<entry id="b">Beta</entry>
</data>
)";
XmlManager xmlManager;
try {
xmlManager.addXmlDocument(xmlContent1);
xmlManager.addXmlDocument(xmlContent2);
std::cout << "Original XMLs:\n";
xmlManager.printAllXml();
xmlManager.add("/root/item[@id='1']", R"(<item id="3">Third</item>)", 0);
// 处理一个非常大的属性值
xmlManager.modify("/root/item[@id='2']", std::string(1000001, 'X'), 0);
xmlManager.add("/data/entry[@id='a']", R"(<entry id="c">Gamma</entry>)", 1);
xmlManager.modify("/data/entry[@id='b']", "Updated Beta", 1);
xmlManager.commitAll();
std::cout << "\nCommitted XMLs:\n";
xmlManager.printAllXml();
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << "\nRolling back all changes..." << std::endl;
xmlManager.rollbackAll();
std::cout << "\nRolled back XMLs:\n";
xmlManager.printAllXml();
}
return 0;
}