C++实现xml解析器示例详解

目录

  • xml格式简单介绍
  • xml格式解析过程浅析
  • 代码实现
    • 实现存储解析数据的类——Element
    • 关键代码1——实现整体的解析
    • 关键代码2——解析所有元素
  • 开发技巧
    • 有关C++的优化
      • 额外注意

    xml格式简单介绍

    我们来简单观察下上面的xml文件,xml格式和html格式十分类似,一般用于存储需要属性的配置或者需要多个嵌套关系的配置。
    xml一般使用于项目的配置文件,相比于其他的ini格式或者yaml格式,它的优势在于可以将一个标签拥有多个属性,比如上述xml文件格式是用于配置工作流的,其中有name属性和switch属性,且再work标签中又嵌套了plugin标签,相比较其他配置文件格式是要灵活很多的。
    具体的应用场景有很多,比如使用过Java中Mybatis的同学应该清楚,Mybatis的配置文件就是xml格式,而且也可以通过xml格式进行sql语句的编写,同样Java的maven项目的配置文件也是采用的xml文件进行配置。
    而我为什么要写一个xml解析器呢?很明显,我今后要写的C++项目需要用到。

    xml格式解析过程浅析 【C++实现xml解析器示例详解】同样回到之前的那段代码,实际上已经把xml文件格式的不同情况都列出来了。
    从整体上看,所有的xml标签分为:
    • xml声明(包含版本、编码等信息)
    • 注释
    • xml元素:1.单标签元素。 2.成对标签元素。
    其中xml声明和注释都是非必须的。 而xml元素,至少需要一个成对标签元素,而且在最外层有且只能有一个,它作为根元素。
    从xml元素来看,分为:
    • 名称
    • 属性
    • 内容
    • 子节点
    根据之前的例子,很明显,名称是必须要有的而且是唯一的,其他内容则是可选。 根据元素的结束形式,我们把他们分为单标签和双标签元素。

    代码实现 完整代码仓库:xml-parser

    实现存储解析数据的类——Element
    代码如下:
    namespace xml{using std::vector; using std::map; using std::string_view; using std::string; class Element{public:using children_t = vector; using attrs_t = map; using iterator = vector::iterator; using const_iterator = vector::const_iterator; string &Name(){return m_name; }string &Text(){return m_text; }//迭代器方便遍历子节点iterator begin(){return m_children.begin(); }[[nodiscard]] const_iterator begin() const{return m_children.begin(); }iterator end(){return m_children.end(); }[[nodiscard]] const_iterator end() const{return m_children.end(); }void push_back(Element const &element)//方便子节点的存入{m_children.push_back(element); }string &operator[](string const &key) //方便key-value的存取{return m_attrs[key]; }string to_string(){return _to_string(); }private:string _to_string(); private:string m_name; string m_text; children_t m_children; attrs_t m_attrs; }; }

    上述代码,我们主要看成员变量。
    • 我们用string类型表示元素的name和text
    • 用vector嵌套表示孩子节点
    • 用map表示key-value对的属性
    其余的方法要么是Getter/Setter,要么是方便操作孩子节点和属性。 当然还有一个to_string()方法这个待会讲。

    关键代码1——实现整体的解析
    关于整体结构我们分解为下面的情形:
    C++实现xml解析器示例详解
    文章图片

    代码如下:
    Element xml::Parser::Parse(){while (true){char t = _get_next_token(); if (t != '<'){THROW_ERROR("invalid format", m_str.substr(m_idx, detail_len)); }//解析版本号if (m_idx + 4 < m_str.size() && m_str.compare(m_idx, 5, "

      推荐阅读