用cpp造了个简单的xml解析器

功能很简陋, 下面两个无法解析。

<?xml version="1.0" encoding="UTF-8"?>

<xxx/>

能解析的格式类似于下面:

<UI_head>

    <Button>Button1</Button>

    <Button>Button2</Button>

    <Grid>

        <Button color ="white" x = "234" y = "456" isShow = "true">Grid.Button1</Button>

        <Button>Grid.Button2</Button>

        <!-- 这是一个按钮 -->

    </Grid>

</UI_head>

效果:

bab6335a35214a8f88ca2f05336410b4.png

源码:

Value.h

#pragma once
#include <string>
#include <sstream>
namespace lakes {
	class Value
	{
	public:
		Value() { }
		Value(const std::string& value);
		Value(const char * value);
		Value(double value);
		Value(int value);
		Value& operator=(double value);
		Value& operator=(int value);
		Value& operator=(bool value);
		Value& operator=(const std::string& value);
		bool operator ==(const Value& other);
		bool operator !=(const Value& other);
		Value(bool value);
		operator bool();
		operator int();
		operator double();
		operator const char*();
		operator std::string();
		std::string& str() {
			return _str_value;
		}
	private:
		std::string _str_value;
	};
}

Value.cpp

#include "Value.h"

lakes::Value::Value(const std::string& value) {
	_str_value = value;
}

lakes::Value::Value(const char* value) {
	_str_value = value;
}

lakes::Value::Value(double value) {
	std::stringstream buf;
	buf << value;
	_str_value = buf.str();
}

lakes::Value::Value(int value) {
	_str_value = value;
}

lakes::Value& lakes::Value::operator=(double value) {
	std::stringstream buf;
	buf << value;
	_str_value = buf.str();
	return *this;
}

lakes::Value& lakes::Value::operator=(int value) {
	_str_value = value;
	return *this;
}

lakes::Value& lakes::Value::operator=(bool value) {
	_str_value = value;
	return *this;
}

lakes::Value& lakes::Value::operator=(std::string& value) {
	_str_value = value;
	return *this;
}

 bool lakes::Value::operator==(const Value& other) {
	return other._str_value == _str_value;
}

 bool lakes::Value::operator!=(const Value& other) {
	return other._str_value != _str_value;
}

 lakes::Value::Value(bool value) {
	*this = value;
}

 lakes::Value::operator bool() {
	return _str_value == "true";
}

 lakes::Value::operator int() {
	return std::atoi(_str_value.c_str());
}

 lakes::Value::operator double() {
	return std::atof(_str_value.c_str());
}

 lakes::Value::operator const char* () {
	return _str_value.c_str();
}

 lakes::Value::operator std::string() {
	return _str_value;
}

Xml.h

#pragma once
#include <string>
#include <list>
#include <map>
#include <stack>
#include <algorithm>
#include <fstream>
#include <sstream>  
#include "Value.h"
namespace lakes {

    /**
     * <Parent1>
     *      <Node1 xx_property = "xxx"> xxx_str </Node1>
     *      <Node2 xx_property = "xxx"> xxx_str </Node2>
     *      <Node3> <Node>xxx</Node> </Node3>
     * </Parent1>
     * ...
    */
    class Xml {
        using itor = std::list<Xml>::iterator;
    public:
        Xml() { }
        Xml(const std::string& path) {
            load(path.c_str());
        }
        void load(const char* path);
        bool save(const std::string& path);
        void parse(const std::string& str);
        std::string name() const;
        void name(const std::string& str);
        std::string text() const;
        void text(const std::string& str);
        Value attr(const std::string& str_name) const;        
        void attr(const std::string& str_name, const std::string& str_attr);
        Value operator[](const std::string& str_attr);
        Xml& find(const std::string& str);
        Xml& append(const Xml& xml_node);
        std::list<Xml>& childs();
        std::string to_string();
        itor begin();
        itor end();
        void clear();

    private:
        std::string _name;
        std::string _text;
        std::map<std::string, Value> _attrs;
        std::list<Xml> _childs;

        char _get_not_space_char(const std::string& str, int& index);
        void _parse_text(Xml* node, const std::string& str, int& index);
        void _parse_attr(Xml& node, const std::string& str, int& index);
        Xml _parse_node(const std::string& str, int& index);
        void _end_node(std::stack<Xml*>& node_stack, const std::string& str, int& index);
    };
} // namespace lake 

Xml.cpp

#include "Xml.h"

#define THROW_ERROR(...) do { \
    char str_err[256] { }; \
    sprintf_s(str_err, __VA_ARGS__); \
    throw std::logic_error(str_err); \
}while(0);


void lakes::Xml::load(const char* path) {
    std::ifstream file(path, std::ios_base::in);
    file.open(path);
    if (!file.is_open()) {
        THROW_ERROR("Open file error...");
    }
    std::stringstream str_stream;
    str_stream << file.rdbuf();
    parse(str_stream.str());
}


bool lakes::Xml::save(const std::string& path) {
    std::ofstream file(path, std::ios_base::out);
    file.open(path);
    if (!file.is_open()) {
        return false;
    }
    file << to_string();
    return true;
}

void lakes::Xml::parse(const std::string& str) {
    size_t text_len = str.length();
    if (text_len == 0) {
        THROW_ERROR("string is empty...");
    }
    std::stack<Xml*> node_stack;
    int index = 0;
    while (index < text_len - 1) {
        char ch = _get_not_space_char(str, index);
        if (ch == '<') {
            index++;
            if (str[index] == '/') {
                index++;
                _end_node(node_stack, str, index);
            }
            else if (!str.compare(index, 3, "!--")) { //skip <!-- xxx -->
                int ind = (int)str.find("-->", index);
                if (ind == std::string::npos) {
                    THROW_ERROR("error: %d could not match -->", index);    
                }
                index = ind + 3;
            }
            else {
                auto node = _parse_node(str, index);
                if (node_stack.empty()) {
                    *this = node;
                    node_stack.push(this);
                }
                else {
                    node_stack.top()->append(node);
                    node_stack.push(&node_stack.top()->childs().back());
                }
            }
        }
        else {
            _parse_text(node_stack.top(), str, index);
        }
    }
    if (!node_stack.empty()) {
        THROW_ERROR("error: root node couldn't match...");
    }
}

std::string lakes::Xml::name() const {
    return _name;
}

void lakes::Xml::name(const std::string& str) {
    _name = str;
}

std::string lakes::Xml::text() const {
    return _text;
}

void lakes::Xml::text(const std::string& str) {
    _text = str;
}

lakes::Value lakes::Xml::attr(const std::string& str_name) const {
    if (_attrs.count(str_name) == 0) {
        return "None";
    }
    return _attrs.at(str_name);
}

void lakes::Xml::attr(const std::string& str_name, const std::string& str_attr) {
    _attrs[str_name] = str_attr;
}

lakes::Xml& lakes::Xml::find(const std::string& str) {
    const auto& node = std::find_if(_childs.begin(), _childs.end(), [&str](Xml& xml_node) {
        return (xml_node.name() == str);
        });
    if (_childs.end() == node) {
        THROW_ERROR("Not Find...");
    }
    return *node;
}

lakes::Value lakes::Xml::operator[](const std::string& str_attr) {
    return attr(str_attr);
}

lakes::Xml& lakes::Xml::append(const Xml& xml_node) {
    _childs.emplace_back(xml_node);
    return *this;
}

std::list<lakes::Xml>& lakes::Xml::childs() {
    return _childs;
}

std::string lakes::Xml::to_string() {
    std::string xml_str;
    xml_str = "<" + _name;
    for (auto& value : _attrs) {
        xml_str += (" " + value.first + "=\"" + value.second.str() + "\"");
    }
    xml_str += ">" + _text;
    for (auto& value : _childs) {
        xml_str += value.to_string();
    }
    xml_str += "</" + _name + ">";
    return xml_str;
}

lakes::Xml::itor lakes::Xml::begin() {
    return _childs.begin();
}

lakes::Xml::itor lakes::Xml::end() {
    return _childs.end();
}

void lakes::Xml::clear() {
    _attrs.clear();
    _childs.clear();
}

char lakes::Xml::_get_not_space_char(const std::string& str, int& index) {
    while (index < str.length() && (str[index] == ' ' || str[index] == '\n')) {
        index++;
    }
    return str[index];
}

void lakes::Xml::_parse_text(Xml* node, const std::string& str, int& index) {
    while (index < str.length() && str[index] != '<' && str[index] != '\n') {
        node->_text += str[index++];
    }
}

void lakes::Xml::_parse_attr(Xml& node, const std::string& str, int& index) {
    std::string attr_name;
    std::string attr_val;
    int flag = 1;
    while (index < str.length()) {
        char ch = str[index];
        if (ch == '>') {
            index++;
            break;
        }
        else if ((ch == '=' || ch == ' ') && flag == 1) {
            flag = -1;
            if (ch == ' ') {
                ch = _get_not_space_char(str, index);
                if (ch != '=') {
                    THROW_ERROR("error : %d not \'=\'...", index);         
                }
            }
            index++;
            ch = _get_not_space_char(str, index);
            if (ch != '\"') {
                THROW_ERROR("error: %d not \" ...", index);
            }
        }
        else if (ch == '\"') {
            flag = 1;
            node.attr(attr_name, attr_val);
            attr_name.clear();
            attr_val.clear();
            while (index + 1 < str.length() && (str[++index] == ' ' || str[index] == '\n' || str[index] == '\r')) {}
            continue;
        }
        else if (ch != '\n' && ch != '\r') {
            if (flag == 1) {
                attr_name += ch;
            }
            else {
                attr_val += ch;
            }
        }
        index++;
    }
}

lakes::Xml lakes::Xml::_parse_node(const std::string& str, int& index) {
    char ch = _get_not_space_char(str, index);
    Xml xml_node;
    std::string str_temp;
    while (++index < str.length()) {
        if (ch == '>' || ch == ' ' || ch == '\n')
            break;
        xml_node._name += ch;
        ch = str[index];
    }
    if (ch != '>') {
        _parse_attr(xml_node, str, index);
    }
    return xml_node;
}

void lakes::Xml::_end_node(std::stack<Xml*>& node_stack, const std::string& str, int& index) {
    char ch;
    std::string temp_buf;
    while (index < str.length()) {
        ch = _get_not_space_char(str, index);
        index++;
        if (ch == '>')
            break;
        temp_buf += ch;
    }
    if (temp_buf == node_stack.top()->name()) {
        node_stack.pop();
    }
    else {
        THROW_ERROR("error: %d : %s != %s", index, node_stack.top()->name().c_str(), temp_buf.c_str()); 
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值