XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识。它也是元标记语言,用于定义其他与特定领域有关的,语义的,结构化的标记语言的句法语言。XML与HTML一样,都来自Standard Generalized Markup Language(标准通用标记语言,SGML)
SGML是一种用标记来描述文档资料的通用语言,它包含一系列的文档类型定义(Document Type Definition,DTD),DTD中定义了标记的含义,因而SGML的语法是可以拓展的。SGML十分庞大,不容易学习,也不容易使用,在计算机上实现也十分困难。
HTML只实现了SGML中很少的一部分标记,它的标记是固定的,语法也是不可拓展的,但是由于它语法的固定使得它简单易学,随着Web技术的发展而推广到全世界,但是由于HTML过于简单,且没有固定的格式,在发展的过程中遇到了一些问题,此时XML便应运而生。
总结:XML使用一个简单而又灵活的标准格式,为基于Web的应用提供一个描述数据和交换数据的有效手段。HTML描述了显示全球数据的通用方法,而XML提供了直接处理全球数据的通用方法。
XML让信息的提供者可以根据需要,自行定义标记及属性名,结构化地描述信息内容
一个实用的XML文档必须满足两点,分别是 组织良好(Well-formed) 和 有效(Valid)
一个组织良好的XML文档,需要满足以下三项基本规则:
xml version = "1.0" ?> 开始实例XML文件
<students>
<student>
<id>202021091138id>
<name>wzhname>
student>
students>
文档对象模型为XML文档的解析版本定义了一组接口。解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用DOM接口来操作这个树结构。
DOM提供了一组丰富的功能,用户可以使用这些功能来解释和操作XML文档,但是DOM解释XML文档也会遇到一些挑战和问题:
总结:除去以上的问题,DOM API是解析XML文档非常有用的方法
SAX接口的出现是为了解决DOM解析XML文件面临的一些问题,SAX接口有如下特征:
当然,SAX解析器也有一些不足点:
以上是解析XML文档主要使用的2种方法,DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点),可以遍历和修改节点,SAX解析器逐行扫描文档,一遍扫描一遍解析。相比于DOM,SAX可以在解析文档的任意时刻停止解析解析,是一种速度更快,更高效的方法。
JDOM是基于Java技术的开发源码项目,它试图遵循80/20原则:用DOM和SAX的20%的功能来满足80%的用户需求。JDOM的底层还是使用SAX和DOM解析器
JDOM的主要特征是它极大地减少了用户必须编写的代码数量,JDOM的应用程序的程度通常是DOM应用程序的1/3,大约是SAX应用程序的一半。JDOM并不做所有的事情,只满足大多数用户要做的解析需求
JAXP出现是SUN公司为了弥补JAVA在XML标准制定上的空白而制定的一套JAVA XML标准API。它并没有为JAVA解析XML提供任何新功能,但是它为在JAVA获取SAX与DOM解析器提供了更加直接的途径。
它封装了sax\dom两种接口,并在sax\dom的基础之上,作了一套比较简单的api以供开发。
造轮子!造轮子!
XML文件解析器实现代码参考来源:https://github.com/oldjun/yazi-xml
XML文件解析器具体实现取决于xml类和Parser类,在xml.h文件中,增加了一个Value数值转化类,方便于XML节点属性的自动转化
#pragma once
#include
#include
#include
#include "xml.h"
#include "Parser.h"
using namespace wzh::xml;
#include
#include
using namespace std;
Value::Value() {
}
Value::Value(bool value) {
*this = value;
}
Value::Value(int value) {
*this = value;
}
Value::Value(double value) {
*this = value;
}
Value::Value(const char * value) : m_value(value) {
}
Value::Value(const string & value) : m_value(value) {
}
Value::~Value() {
}
Value & Value::operator = (bool value) {
m_value = value ? "true" : "false";
return *this;
}
Value & Value::operator = (int value) {
stringstream ss;
ss << value;
m_value = ss.str();
return *this;
}
Value & Value::operator = (double value) {
stringstream ss;
ss << value;
m_value = ss.str();
return *this;
}
Value & Value::operator = (const char * value) {
m_value = value;
return *this;
}
Value & Value::operator = (const string & value) {
m_value = value;
return *this;
}
Value & Value::operator = (const Value & value) {
m_value = value.m_value;
return *this;
}
bool Value::operator == (const Value & other) {
return m_value == other.m_value;
}
bool Value::operator != (const Value & other) {
return !(m_value == other.m_value);
}
Value::operator bool() {
if (m_value == "true")
return true;
else if (m_value == "false")
return false;
return false;
}
Value::operator int() {
return std::atoi(m_value.c_str());
}
Value::operator double() {
return std::atof(m_value.c_str());
}
Value::operator string() {
return m_value;
}
XML::XML() : m_name(nullptr), m_text(nullptr), m_attrs(nullptr), m_child(nullptr) {
}
XML::XML(const char * name) : m_name(nullptr), m_text(nullptr), m_attrs(nullptr), m_child(nullptr) {
m_name = new string(name);
}
XML::XML(const string & name) : m_name(nullptr), m_text(nullptr), m_attrs(nullptr), m_child(nullptr) {
m_name = new string(name);
}
XML::XML(const XML & other) {
m_name = other.m_name;
m_text = other.m_text;
m_attrs = other.m_attrs;
m_child = other.m_child;
}
string XML::name() const {
if(m_name == nullptr) {
return "";
}
return *m_name;
}
void XML::setName(const string & name) {
if(m_name != nullptr) {
delete m_name;
m_name = nullptr;
}
m_name = new string(name);
}
string XML::text() const {
if(m_text == nullptr) {
return "";
}
return *m_text;
}
void XML::setText(const string & text) {
if(m_text != nullptr) {
delete m_text;
m_text = nullptr;
}
m_text = new string(text);
}
Value & XML::attr(const string & key) {
if(m_attrs == nullptr) {
m_attrs = new std::map();
}
return (*m_attrs)[key];
}
void XML::setAttr(const string & key, const Value & val) {
if(m_attrs == nullptr) {
m_attrs = new std::map();
}
(*m_attrs)[key] = val;
}
string XML::str() const {
if(m_name == nullptr) {
throw std::logic_error("element name is empty");
}
stringstream ss;
ss << "<";
ss << *m_name;
if(m_attrs != nullptr) {
for(auto it = m_attrs->begin(); it != m_attrs->end(); it++) {
ss << " " << it->first << "=\"" << (string)it->second << "\"";
}
}
ss << ">";
if(m_child != nullptr) {
for(auto it = m_child->begin(); it != m_child->end(); it++) {
ss << it->str();
}
}
if(m_text != nullptr) {
ss << *m_text;
}
ss << "" << *m_name << ">";
return ss.str();
}
void XML::clear() {
if(m_name != nullptr) {
delete m_name;
m_name = nullptr;
}
if(m_text != nullptr) {
delete m_text;
m_text = nullptr;
}
if(m_attrs != nullptr) {
delete m_attrs;
m_attrs = nullptr;
}
if(m_child != nullptr) {
for(auto it = m_child->begin(); it != m_child->end(); it++) {
it -> clear();
}
delete m_child;
m_child = nullptr;
}
}
void XML::append(const XML & child) {
if(m_child == nullptr) {
m_child = new std::list();
}
m_child->push_back(child);
}
XML & XML::operator [] (int index) {
if(index < 0) {
throw std::logic_error("index less than zero");
}
if(m_child == nullptr) {
m_child = new std::list();
}
int size = m_child->size();
if(index >= 0 && index < size) {
auto it = m_child->begin();
for(int i=0; i= size) {
for(int i=size; i<=index; i++)
m_child->push_back(XML());
}
return m_child->back();
}
XML & XML::operator [] (const char * name) {
return (*this)[string(name)];
}
XML & XML::operator [] (const string & name) {
if(m_child == nullptr) {
m_child = new std::list();
}
for(auto it = m_child->begin(); it != m_child->end(); it++) {
if(it->name() == name) {
return *it;
}
}
m_child->push_back(XML(name));
return m_child->back();
}
XML & XML::operator = (const XML & other) {
clear();
m_name = other.m_name;
m_text = other.m_text;
m_attrs = other.m_attrs;
m_child = other.m_child;
return *this;
}
void XML::remove(int index) {
if(m_child == nullptr) {
return;
}
int size = m_child->size();
if(index < 0 || index >= size) {
throw std::logic_error("index out of range");
return;
}
auto it = m_child->begin();
for(int i=0; iclear();
m_child->erase(it);
}
void XML::remove(const char * name) {
remove(string(name));
}
void XML::remove(const string & name) {
if(m_child == nullptr) {
return;
}
for(auto it = m_child->begin(); it != m_child->end();) {
if(it->name() == name) {
it->clear();
it = m_child->erase(it);
}
else {
it++;
}
}
}
bool XML::load(const string & filename)
{
Parser p;
if (!p.load_file(filename))
{
return false;
}
*this = p.parse();
return true;
}
bool XML::save(const string & filename)
{
ofstream fout(filename);
if (fout.fail())
{
return false;
}
fout << str();
fout.close();
return true;
}
bool XML::parse(const string & str)
{
Parser p;
if (!p.load_string(str))
{
return false;
}
*this = p.parse();
return true;
}
#pragma once
#include "xml.h"
#include
using namespace std;
namespace wzh {
namespace xml{
class Parser {
public:
Parser();
bool load_file(const string & file);
bool load_string(const string & str);
XML parse(); // 解析方法
private:
void skip_white_space(); // 忽略空白符
bool parse_declaration(); // 解析声明
bool parse_comment(); // 解析注释
XML parse_element(); // 解析主函数
string parse_element_name(); // 解析节点名称
string parse_element_text(); // 解析节点文本
string parse_element_attr_key(); // 解析节点属性
string parse_element_attr_val(); // 解析节点属性值
private:
string m_str;
int m_idx;
};
}
}
#include "Parser.h"
using namespace wzh::xml;
#include
#include
#include
using namespace std;
Parser::Parser() : m_str(""), m_idx(0) {
}
bool Parser::load_string(const string & str) {
m_str = str;
m_idx = 0;
return true;
}
bool Parser::load_file(const string & filename) {
ifstream fin(filename);
if(fin.fail()) {
return false;
}
stringstream ss;
ss << fin.rdbuf();
m_str = ss.str();
m_idx = 0;
return true;
}
void Parser::skip_white_space() {
while(m_str[m_idx] == ' ' || m_str[m_idx] == '\r' || m_str[m_idx] == '\n' || m_str[m_idx] == '\t') {
m_idx++;
}
}
XML Parser::parse() {
skip_white_space();
if(m_str.compare(m_idx, 5, "", m_idx);
if(pos == std::string::npos) {
return false;
}
m_idx = pos + 2;
return true;
}
bool Parser::parse_comment() {
if(m_str.compare(m_idx, 4, "", m_idx);
if(pos == std::string::npos) {
return false;
}
m_idx = pos + 3;
return true;
}
XML Parser::parse_element() {
XML elem;
m_idx++;
skip_white_space();
const string & name = parse_element_name();
elem.setName(name);
while(m_str[m_idx] != '\0') {
skip_white_space();
if(m_str[m_idx] == '/') {
if(m_str[m_idx+1] == '>') {
m_idx += 2;
break;
}
else {
throw logic_error("xml empty element is error");
}
}
else if(m_str[m_idx] == '>') {
m_idx++;
string text = parse_element_text();
if(text != "") {
elem.setText(text);
}
}
else if(m_str[m_idx] == '<') {
if(m_str[m_idx+1] == '/') {
// 标签
string end_tag = "" + name + ">";
size_t pos = m_str.find(end_tag, m_idx);
if (pos == std::string::npos) {
throw std::logic_error("xml element " + name + " end tag not found");
}
m_idx = (pos + end_tag.size());
break;
}
else if (m_str.compare(m_idx, 4, "