pugixml编写一个xml工具类并且满足事务以及数据一致性

使用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;
}
相关推荐
itachi-uchiha1 天前
awk处理xml文件&&封装集合变量和调用
xml·shell·awk
武子康4 天前
Java-39 深入浅出 Spring - AOP切面增强 核心概念 通知类型 XML+注解方式 附代码
xml·java·大数据·开发语言·后端·spring
Ll13045252985 天前
基于 COM 的 XML 解析技术(MSXML) 的总结
xml
在代码的海洋中寻找亚特兰蒂斯6 天前
AJAX对于XML和JSON的处理
xml·ajax·json
BinField7 天前
ToolsSet之:XML工具
xml·windows·microsoft
SEO-狼术7 天前
Connect Directly to Oracle XML Data
xml·数据库·oracle
YSoup8 天前
2025年目前最新版本Android Studio自定义xml预览的屏幕分辨率
android·xml·android studio
abcnull9 天前
mybatis的mapper对应的xml写法
xml·sql·spring·mybatis·mapper
Blue桃之夭夭9 天前
HTML、XML、JSON 是什么?有什么区别?又是做什么的?
xml·html·json
小于村9 天前
pom.xml 文件中配置你项目中的外部 jar 包打包方式
xml·java·jar