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;
}
相关推荐
AI产品实战13 小时前
Gradle打包生成dependencies.xml详解
xml·java·gradle
斯特凡今天也很帅2 天前
xml页面可以打开,不报错,但是显示数据的地方也不显示,我是怎么解决的
xml·vue.js
前网易架构师-高司机3 天前
带标注的21种中药材识别数据集,识别率73.8%数据集,2237张图,支持yolo,coco json,voc xml,文末有模型训练代码
xml·yolo·json·数据集·中药·药材·中草药
snow@li3 天前
Java:pom.xml全景深度分析 / 机制、标签、依赖、打包、生产避坑全解 / 工程基石
xml·java·开发语言
田里的水稻3 天前
EP_XML\JSON配置文件和YAML
xml·运维·人工智能·机器人·自动驾驶·json
xiangji4 天前
开源完美模块组件化可扩展的Xml解析器Hand.ParseXml
xml·模块化·组件化·可扩展
我命由我123456 天前
Android 构建项目问题:XML 片段出错,com.ctc.wstx.exc.WstxUnexpectedCharException
android·xml·android studio·android jetpack·android-studio·android runtime
PixelBai7 天前
JSON转XML使用教程:从入门到精通
xml·json
脑子运行超载9 天前
Jackson处理和mybatis的xml转换问题
xml·jackson·mybatis·javatype
tianyuanwo1 个月前
深入解析 RISC-V 虚拟化中的 UEFI 固件配置:从 XML 到 NVRAM 的生命周期管理
xml·linux·risc-v