看啥推荐读物
专栏名称: Zbertj
本人笔记纯属虚构 如若雷同 en.. 那...
今天看啥  ›  专栏  ›  Zbertj

C++ 读写较复杂的XML

Zbertj  · 简书  ·  · 2019-01-10 18:02

  这里提供一个稍微复杂点的xml解析过程,只涉及到读取,和修改,一般读取什么简单的配置文件已经足够了,只为了不想用xml的库。

  头文件需要事先配置好配置文件路径和根节点结束标签,多层解析里面的可以不需要结束标签,使用方法可以看注释,很简单。

#ifndef MYXMLPARSER_H
#define MYXMLPARSER_H
#include <iostream>
#include <string>
#include <fstream>
#include <vector>

//只适合单层的xml
namespace MyXmlParser
{
    const std::string xml_path_file = "/mnt/hgfs/MyWork/Template/wmbaseinfo.conf";  //配置文件路径
    const std::string end_root_node = "</DBaseInfo>";   //根节点的结束标签

    // std::string a = MyXmlParser::getXmlValue("<ooo>");
    std::string getXmlValue(const std::string& label);

    // std::string a = MyXmlParser::getXmlValue2("<DBaseInfo> <name>:2 <age>", " ");
    std::string getXmlValue2(std::string label, const std::string& tag);    //单行
    std::string getXmlValue3(std::string label, const std::string& tag);    //整个文件

    //auto a = MyXmlParser::setXmlValue("<age>", "ppppp");
    bool setXmlValue(const std::string& label, const std::string& value);

    // auto a = MyXmlParser::setXmlValue2("<DBaseInfo> <name>:2 <age>", " ", "ppppp");
    bool setXmlValue2(std::string label, const std::string& tag, const std::string& value);
};

#endif // MYXMLPARSER_H
/*
#include <iostream>
#include <string>
#include "tools/MyXmlParser.h"

int main(int argc, char const *argv[])
{
    std::string a = MyXmlParser::getXmlValue("<ooo>");
    std::cout <<"ooo: "<< a <<std::endl;
    MyXmlParser::setXmlValue("<test222>", "hahahha");
    MyXmlParser::setXmlValue("<ooo>", "rrrrrrr");
    return 0;
}
*/
#include "MyXmlParser.h"


//<root> <html> <div>:2 <p>    tag = " "
//<ooo> <77> <dd>
static std::vector<std::string> strSplit(const std::string& str, const std::string& tag)
{
    std::string str_tmp = str + tag;
    std::vector<std::string> str_v;
    int index = 0; 
    while(str_tmp.find(tag, index) != std::string::npos )
    {
        auto pos = str_tmp.find(tag, index);
        // std::cout << "pos:" << pos << std::endl;
        std::string a = str_tmp.substr(index, pos - index);
        // std::cout << "a:" << a << std::endl; 
        str_v.push_back(a);
        index = pos + 1;
    } 
    return str_v;
}

//转换传进来的字符串格式:<A> <B>:2 <C>=====><A> <B> <B> <C>            <DBaseInfo> <name>:3 <age>
static void change_format(std::string& label, const std::string& tag)
{
    auto off = 0; 
    std::string ltag = ":";
    while(true)
    {
        std::string new_str = "";   //  

        auto pos1 = label.find(ltag, off);  //冒号的起始位置
        if(pos1 != std::string::npos)
        {
            auto pos0 = label.rfind(tag, pos1);     // 冒号前第一个空格的起始位置
            if(pos0 != std::string::npos)
            {
                new_str = label.substr(pos0, pos1 - pos0);      //new_str=" <name>"
            }
            auto pos2 = label.find(tag, pos1);      //冒号后第一个空格的起始位置
            if(pos2 != std::string::npos)
            {
                auto count = std::stoi(label.substr(pos1 + ltag.length(), pos2 - pos1 - ltag.length()));    //个数=空格开始位置-冒号结束位置
                std::string insert_str = "";
                while(count--)
                {
                    insert_str += new_str;
                }
                // std::cout << "insert_str:" << insert_str << std::endl;//insert_str为覆盖冒号对应标签的字符串
                label.replace(pos0, pos2 - pos0, insert_str);
            }
            off = pos1 + ltag.length();
        }
        else
        {
            break;
        }
    }
}

std::string MyXmlParser::getXmlValue(const std::string& label)
{
    if(label.empty())
    {
        return "";
    }

    std::ifstream xmlin(MyXmlParser::xml_path_file, std::ios::in);
    if(xmlin.is_open())
    {
        std::string line = "";
        while(getline(xmlin, line))
        {
            if(line.find(label) != std::string::npos && line.find("</") != std::string::npos)
            {
                line = line.substr(line.find(label) + label.length(), std::string::npos);
                xmlin.close();
                return line.substr(0, line.find("</"));
            }
        }
    }
    else
    {
        std::cout << "open "<< MyXmlParser::xml_path_file << " error" << std::endl;
    }
    return "";
}

//<root> <html> <mate>
//一行行匹配
std::string MyXmlParser::getXmlValue2(std::string label, const std::string& tag)
{
    if(label.empty())
    {
        return "";
    }
    
    //改变字符串格式
    change_format(label, tag);
    // std::cout << "label: " << label << std::endl;
    
    std::ifstream xmlin(MyXmlParser::xml_path_file, std::ios::in);
    if(xmlin.is_open())
    {
        std::vector<std::string> label_v;
        label_v = strSplit(label, tag);
        std::string line = "";
        while(getline(xmlin, line))
        {
            std::string label_name = "";
            if(label_v.size() > 0)
            {
                label_name = label_v.front();
            }
            if((label_name != "") && (line.find(label_name) != std::string::npos))
            {
                auto k = label_v.begin();
                label_v.erase(k); // 删除第一个元素
                // std::cout << "label_name:" << label_name << std::endl;
                if(label_v.size() == 0)
                {
                    line = line.substr(line.find(label_name) + label_name.length(), std::string::npos);
                    xmlin.close();
                    return line.substr(0, line.find("</"));
                }
            }
        }
        xmlin.close();
        return "";
    }
    else
    {
        std::cout << "open "<< MyXmlParser::xml_path_file << " error" << std::endl;
        return "";
    }
}

//整个文件匹配
std::string MyXmlParser::getXmlValue3(std::string label, const std::string& tag)
{
    if(label.empty())
    {
        return "";
    }
    
    //改变字符串格式
    change_format(label, tag);
    // std::cout << "label: " << label << std::endl;
    
    std::ifstream xmlin(MyXmlParser::xml_path_file, std::ios::in);
    if(xmlin.is_open())
    {
        std::string content((std::istreambuf_iterator<char>(xmlin)), std::istreambuf_iterator<char>());
        // std::cout << content << std::endl;
        std::vector<std::string> label_v;
        label_v = strSplit(label, tag);
        auto offset = 0;
        for(auto label_name :label_v)
        {
            auto label_pos = content.find(label_name, offset);  //标签的位置
            if (label_pos != std::string::npos) 
            {
                offset = label_pos + label_name.length();
            }
            else
            {
                std::cout << "Not Found" << std::endl; 
                xmlin.close();
                return "";
            }
        }
        auto label_end_pos = content.find("</", offset);    //最后一个结束标签的位置
        std::string tmp = content.substr(offset, label_end_pos - offset);
        xmlin.close();
        return tmp;

    }
    else
    {
        std::cout << "open "<< MyXmlParser::xml_path_file << " error" << std::endl;
        return "";
    }
}

bool MyXmlParser::setXmlValue(const std::string& label, const std::string& value)
{
    if(label.empty() || value.empty())
    {
        return false;
    }
    bool write = false;
    std::ifstream xmlin(MyXmlParser::xml_path_file, std::ios::in);
    if(xmlin.is_open())
    {
        xmlin.seekg(0, std::ios::end);  //基于文件开始位置偏移文件大小的这么多
        int length = xmlin.tellg();
        xmlin.seekg(0, std::ios::beg);
        std::string content(length, 0);
        xmlin.read(const_cast<char*>(content.c_str()), length);
        auto pos = content.find(label);
        if(pos != std::string::npos)    //有相应标签就修改
        {
            std::string end_label = "</" + label.substr(1, std::string::npos);
            auto beg_pos = pos + label.length();
            auto end_pos = content.find(end_label);
            if(end_pos != std::string::npos)
            {
                content.replace(beg_pos, end_pos - beg_pos,value);
                write = true;
            }
        }
        else    //没有就添加
        {
            std::string new_line = label + value +  "</" + label.substr(1, std::string::npos);
            if(content.find(MyXmlParser::end_root_node) != std::string::npos)
            {
                content.insert(content.find(MyXmlParser::end_root_node), "\t" + new_line + "\n");
                write = true;
            }
        }
        xmlin.close();
        if(write)
        {
            std::ofstream outfile (MyXmlParser::xml_path_file, std::ios::out);
            if(outfile.is_open())
            {
                outfile.write(content.c_str(), content.length());
            }
            else
            {
                write = false;
            }
        }
    }
    return write;
}

//只支持单个修改不支持添加
bool MyXmlParser::setXmlValue2(std::string label, const std::string& tag, const std::string& value)
{
    if(label.empty() || value.empty() || tag.empty())
    {
        return false;
    }
    change_format(label, tag);

    bool write = false;
    std::ifstream xmlin(MyXmlParser::xml_path_file, std::ios::in);
    if(xmlin.is_open())
    {
        xmlin.seekg(0, std::ios::end);  //基于文件开始位置偏移文件大小的这么多
        int length = xmlin.tellg();
        xmlin.seekg(0, std::ios::beg);
        std::string content(length, 0);
        xmlin.read(const_cast<char*>(content.c_str()), length);

        std::vector<std::string> label_v;
        label_v = strSplit(label, tag);

        auto offset = 0;
        std::string last_label = "";
        for(auto label_name :label_v)
        {
            // std::cout << "label_name:" << label_name << std::endl;
            auto label_pos = content.find(label_name, offset);  //标签的位置
            if (label_pos != std::string::npos) 
            {
                offset = label_pos + label_name.length();
            }
            else
            {
                std::cout << "Not Found" << std::endl; 
                xmlin.close();
                return false;
            }
            last_label = label_name;
        }
        std::string end_label = "</" + last_label.substr(1, std::string::npos);
        auto beg_pos = offset;                                      //offset = label_pos + label_name.length();
        auto end_pos = content.find(end_label, offset);
        if(end_pos != std::string::npos)
        {
            content.replace(beg_pos, end_pos - beg_pos,value);
            // std::cout << "test:" << content.substr(beg_pos, end_pos - beg_pos) << std::endl;
            write = true;
        }
        xmlin.close();
        if(write)
        {
            std::ofstream outfile (MyXmlParser::xml_path_file, std::ios::out);
            if(outfile.is_open())
            {
                outfile.write(content.c_str(), content.length());
            }
            else
            {
                write = false;
            }
        }
    }
    return write;
}



原文地址:访问原文地址
快照地址: 访问文章快照