xml格式简单介绍
"1.0"?>
name="1" switch="on">
name="echoplugin.so" switch="on" />
复制代码
我们来简单观察下上面的xml文件,xml格式和html格式十分类似,一般用于存储需要属性的配置或者需要多个嵌套关系的配置。
xml一般使用于项目的配置文件,相比于其他的ini格式或者yaml格式,它的优势在于可以将一个标签拥有多个属性,比如上述xml文件格式是用于配置工作流的,其中有name属性和switch属性,且再work标签中又嵌套了plugin标签,相比较其他配置文件格式是要灵活很多的。
具体的应用场景有很多,比如使用过Java中Mybatis的同学应该清楚,Mybatis的配置文件就是xml格式,而且也可以通过xml格式进行sql语句的编写,同样Java的maven项目的配置文件也是采用的xml文件进行配置。
而我为什么要写一个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——实现整体的解析
关于整体结构我们分解为下面的情形:
代码如下:
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, ") == 0)
{
if (!_parse_version())
{
THROW_ERROR("version parse error", m_str.substr(m_idx, detail_len));
}
continue;
}
//解析注释
if (m_idx + 3 < m_str.size() && m_str.compare(m_idx, 4, "
领取专属 10元无门槛券
私享最新 技术干货