XML - XML学习/XML文件解析器(C++)实现

XML概述

​ XML是一套定义语义标记的规则,这些标记将文档分成许多部件并对这些部件加以标识。它也是元标记语言,用于定义其他与特定领域有关的,语义的,结构化的标记语言的句法语言。XML与HTML一样,都来自Standard Generalized Markup Language(标准通用标记语言,SGML)

​ SGML是一种用标记来描述文档资料的通用语言,它包含一系列的文档类型定义(Document Type Definition,DTD),DTD中定义了标记的含义,因而SGML的语法是可以拓展的。SGML十分庞大,不容易学习,也不容易使用,在计算机上实现也十分困难。

​ HTML只实现了SGML中很少的一部分标记,它的标记是固定的,语法也是不可拓展的,但是由于它语法的固定使得它简单易学,随着Web技术的发展而推广到全世界,但是由于HTML过于简单,且没有固定的格式,在发展的过程中遇到了一些问题,此时XML便应运而生。

XML的特点

  1. 简介有效

    • XML是一个精简的SGML,它将SGML的丰富功能与HTML的易用性结合到Web应用中,保留了SGML的可拓展功能,这使得XML从根本上区别于HTML
  2. 易学易用
  3. 开放的国际化标准
    • XML标准。W3C正式批准的标准,这意味着这个标准是稳定的,完全可用于Web和工具的开发
    • XML名域标准。
    • DOM(Document Object Model,文档对象模型)标准。为给结构化的数据编写脚本提供标准,这样,开发人员就能够与计算机在基于XML的数据上进行交互
    • XSL标准。XSL有两个模块:XSL转换语言和XSL格式化对象。
    • XLL标准和XML指针语言(XPointer)标准。
  4. 高效且可扩充
    • XML支持复用文档片断,使用者可以发明和使用自己的标签,也可与他人共享,可延伸性大。

总结:XML使用一个简单而又灵活的标准格式,为基于Web的应用提供一个描述数据和交换数据的有效手段。HTML描述了显示全球数据的通用方法,而XML提供了直接处理全球数据的通用方法。

XML的作用

​ XML让信息的提供者可以根据需要,自行定义标记及属性名,结构化地描述信息内容

  1. 使得搜索更加有意义
  2. 开发灵活的Web应用软件
    • XML的应用使得三层Web应用软件的开发更加简单,由于其能够有效地进行消息和数据标准的统一,从而设计,开发出更加灵活的Web应用软件
  3. 实现不同数据的集成
  4. 使用于多种应用环境
  5. 客户端数据处理与计算
  6. 数据显示多样化
  7. 局部数据更新
  8. 与现有Web发布机制相兼容
  9. 可升级性
  10. 压缩性能高
    • XML压缩性能很好,因为用于描述数据结构的标签可以重复使用。

XML的应用

  1. 应用于客户需要与不同的数据源进行交互时
  2. 应用于将大量运算负荷分布在客户端
  3. 应用于将同一数据以不同的面貌展现给不同的用户
  4. 应用于网络代理对所取得的信息进行编辑,增减以适应个人用户的需要

解析XML

​ 一个实用的XML文档必须满足两点,分别是 组织良好(Well-formed)有效(Valid)

XML文档

一个组织良好的XML文档,需要满足以下三项基本规则:

  1. 文档以XML定义 <? xml version = "1.0" ?> 开始
  2. 有一个包含所有其他内容的根元素
  3. 所有元素必须合理地嵌套,不允许交叉嵌套

实例XML文件

<?xml version="1.0" encoding="UTF-8"?>
<students><student><id>202021091138</id><name>wzh</name></student>
</students>

DOM解析

​ 文档对象模型为XML文档的解析版本定义了一组接口。解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用DOM接口来操作这个树结构。

​ DOM提供了一组丰富的功能,用户可以使用这些功能来解释和操作XML文档,但是DOM解释XML文档也会遇到一些挑战和问题:

  1. DOM构建整个文档驻留内存的树。如果文档很大时,就会要求有极大的内存,这消耗的内存往往是XML文档的10~100倍左右
  2. DOM创建表示原始文档中每个东西的对象,包括元素,文本,属性和空格。如果用户只关注原始文档的一小部分,那么创建那些永远不被使用的对象是极其浪费的
  3. DOM解析器必须在代码取得控制权之前读取整个文档。对于非常大的文档,这会引起显著的延迟

总结:除去以上的问题,DOM API是解析XML文档非常有用的方法

SAX解析

​ SAX接口的出现是为了解决DOM解析XML文件面临的一些问题,SAX接口有如下特征:

  1. SAX解析器向代码发送事件。当解析器发现元素开始,元素结束,文本,文档的开始或结束时,它会告诉用户。
  2. SAX解析器根本不创建任何对象,它只是将事件传递给应用程序。如果希望基于哪些事件创建对象,这将由编程者自己来完成
  3. SAX解析器在解析开始的时候就开始发送事件。当解析器发现文档开始,元素开始和文本时,代码会收到一个事件。应用程序可以立即开始生成结果;不必一直等到整个文档被解析完毕。

​ 当然,SAX解析器也有一些不足点:

  1. SAX事件是无状态的。当SAX解析器在XML文档中发现文本时,它就向代码发送一个事件。该事件仅给用户发现的文本,它不告诉用户什么元素包含那个文本。如果想了解这一点,则用户必须自己编写状态管理代码
  2. SAX事件不是持久的。如果应用程序需要一个数据结构来对XML文档建模,则必须自己编写那样的代码。如果需要从SAX事件访问数据,并且没有把那个数据存储在代码中,那么用户不得不再次解析该文档

以上是解析XML文档主要使用的2种方法,DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点),可以遍历和修改节点,SAX解析器逐行扫描文档,一遍扫描一遍解析。相比于DOM,SAX可以在解析文档的任意时刻停止解析解析,是一种速度更快,更高效的方法。

JDOM解析

​ JDOM是基于Java技术的开发源码项目,它试图遵循80/20原则:用DOM和SAX的20%的功能来满足80%的用户需求。JDOM的底层还是使用SAX和DOM解析器

​ JDOM的主要特征是它极大地减少了用户必须编写的代码数量,JDOM的应用程序的程度通常是DOM应用程序的1/3,大约是SAX应用程序的一半。JDOM并不做所有的事情,只满足大多数用户要做的解析需求

JAXP解析

​ JAXP出现是SUN公司为了弥补JAVA在XML标准制定上的空白而制定的一套JAVA XML标准API。它并没有为JAVA解析XML提供任何新功能,但是它为在JAVA获取SAX与DOM解析器提供了更加直接的途径。

​ 它封装了sax\dom两种接口,并在sax\dom的基础之上,作了一套比较简单的api以供开发。

XML文件解析器设计与实现(C++)

​ 造轮子!造轮子!

​ XML文件解析器实现代码参考来源:https://github.com/oldjun/yazi-xml

XML文件解析器用法

  • 从文件加载XML
  • 从字符串加载XML
  • 访问节点:根据数组下标,节点名称
  • 遍历节点:数组,迭代器,for in
  • 添加节点
  • 删除节点
  • 获取,修改节点名称
  • 获取,删除节点属性
  • 获取,修改节点内容

XML解析器具体实现

XML文件解析器具体实现取决于xml类和Parser类,在xml.h文件中,增加了一个Value数值转化类,方便于XML节点属性的自动转化

xml.h文件
#pragma once#include <string>
#include <list>
#include <map>
using namespace std;namespace wzh {namespace xml {class Value {// 数值转化类public:Value();Value(bool value);Value(int value);Value(double value);Value(const char * value);Value(const string & value);~Value();Value & operator = (bool value);Value & operator = (int value);Value & operator = (double value);Value & operator = (const char * value);Value & operator = (const string & value);Value & operator = (const Value & value);bool operator == (const Value & other);bool operator != (const Value & other);operator bool();operator int();operator double();operator string();private:string m_value;};class XML {public:XML();XML(const char * name);XML(const string & name);XML(const XML & other);string name() const; // 获取节点名称void setName(const string & name); // 设置节点名称string text() const; // 获取节点内容void setText(const string & text); // 设置节点内容Value & attr(const string & key); // 获取节点属性void setAttr(const string & key, const Value & val); // 设置节点属性string str() const; // 返回属性序列化结果void clear(); // 释放内存void append(const XML & child); // 添加子节点XML & operator [] (int index); // 以数组下标方式获取子节点XML & operator [] (const char * name); // 通过节点名称获取子节点(支持C形式)XML & operator [] (const string & name); // 通过节点名称获取子节点(支持C++形式)XML & operator = (const XML & other);void remove(int index); // 以数组下标方式删除子节点void remove(const char * name); // 通过节点名称删除子节点(支持C形式)void remove(const string & name); // 通过节点名称删除子节点(支持C++形式)typedef std::list<XML>::iterator iterator;iterator begin() {return m_child->begin();}iterator end() {return m_child->end();}iterator erase(iterator it) {it->clear();return m_child->erase(it);}int size() const {return m_child->size();}bool load(const string & filename);bool save(const string & filename);bool parse(const string & str);private:// 使用指针加快数据的读取以及存储开销string* m_name; // 节点名称string* m_text; // 节点内容std::map<string, Value>* m_attrs; // 节点属性std::list<XML>* m_child; // 子节点};}
}
xml.cpp文件
#include "xml.h"
#include "Parser.h"
using namespace wzh::xml;#include <fstream>
#include <sstream>
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<string, Value>();}return (*m_attrs)[key];
}void XML::setAttr(const string & key, const Value & val) {if(m_attrs == nullptr) {m_attrs = new std::map<string, Value>();}(*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<XML>();}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<XML>();}int size = m_child->size();if(index >= 0 && index < size) {auto it = m_child->begin();for(int i=0; i<index; i++)it++;return *it;}if (index >= 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<XML>();}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; i<index; i++) {it++;}it->clear();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;
}
Parser.h文件
#pragma once#include "xml.h"
#include <string>
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;};}
}
Parser.cpp文件
#include "Parser.h"
using namespace wzh::xml;#include <iostream>
#include <fstream>
#include <sstream>
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, "<?xml") == 0) {if(!parse_declaration()) {throw std::logic_error("parse declaration error");}}skip_white_space();while(m_str.compare(m_idx, 4, "<!--") == 0) {if(!parse_comment()) {throw std::logic_error("parse comment error");}skip_white_space();}if (m_str[m_idx] == '<' && (isalpha(m_str[m_idx+1]) || m_str[m_idx+1] == '_')) {return parse_element();}throw std::logic_error("parse element error");
}bool Parser::parse_declaration() {if(m_str.compare(m_idx, 5, "<?xml") != 0) {return false;}m_idx += 5;size_t pos = m_str.find("?>", 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, "<!--") != 0) {return false;}m_idx += 4;size_t pos = m_str.find("-->", 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, "<!--") == 0) {// 注释if (!parse_comment()) {throw std::logic_error("xml comment is error");}}else {// 子节点elem.append(parse_element());}}else {// 节点属性string key = parse_element_attr_key();skip_white_space();if (m_str[m_idx] != '='){throw std::logic_error("xml element attr is error" + key);}m_idx++;skip_white_space();string val = parse_element_attr_val();elem.setAttr(key, val);}}return elem;
}string Parser::parse_element_name() {int pos = m_idx;if (isalpha(m_str[m_idx]) || (m_str[m_idx] == '_')) {m_idx++;while (isalnum(m_str[m_idx]) || (m_str[m_idx] == '_') || (m_str[m_idx] == '-') || (m_str[m_idx] == ':') || (m_str[m_idx] == '.')) {m_idx++;}}return m_str.substr(pos, m_idx - pos);
}string Parser::parse_element_text() {int pos = m_idx;while (m_str[m_idx] != '<') {m_idx++;}return m_str.substr(pos, m_idx - pos);
}string Parser::parse_element_attr_key() {int pos = m_idx;if (isalpha(m_str[m_idx]) || (m_str[m_idx] == '_')) {m_idx++;while (isalnum(m_str[m_idx]) || (m_str[m_idx] == '_') || (m_str[m_idx] == '-') || (m_str[m_idx] == ':')) {m_idx++;}}return m_str.substr(pos, m_idx - pos);
}string Parser::parse_element_attr_val() {if (m_str[m_idx] != '"') {throw std::logic_error("xml element attr value should be in double quotes");}m_idx++;int pos = m_idx;while (m_str[m_idx] != '"') {m_idx++;}m_idx++;return m_str.substr(pos, m_idx - pos - 1);
}
Makefile
#指定编译器
CC = g++#找出当前目录下,所有的源文件(以.cpp结尾)
SRCS := $(shell find ./* -type f | grep '\.cpp' | grep -v 'main\.cpp')
$(warning SRCS is ${SRCS})#确定cpp源文件对应的目标文件
OBJS := $(patsubst %.cpp, %.o, $(filter %.cpp, $(SRCS)))
$(warning OBJS is ${OBJS})#编译选项
CFLAGS = -g -O2 -Wall -Werror -Wno-unused -ldl -fPIC -std=c++11
$(warning CFLAGS is ${CFLAGS})#找出当前目录下所有的头文件
INCLUDE_TEMP = $(shell find ./* -type d)
INCLUDE = $(patsubst %,-I %, $(INCLUDE_TEMP))
$(warning INCLUDE is ${INCLUDE})SRC_MAIN = main.cpp
OBJ_MAIN = ${SRC_MAIN:%.cpp=%.o}
EXE_MAIN = maintarget: ${EXE_MAIN}$(EXE_MAIN): $(OBJ_MAIN) $(OBJS)$(CC) -o $@ $^ $(CFLAGS) $(INCLUDE)clean:rm -f ${OBJS} ${OBJ_MAIN} ${EXE_MAIN}%.o: %.cpp${CC} ${CFLAGS} ${INCLUDE} -c $< -o $@

附上xml测试文件

test1.xml(Maven配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.item</groupId><artifactId>servlet_mybatis</artifactId><version>1.0-SNAPSHOT</version><name>servlet_mybatis</name><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.target>1.8</maven.compiler.target><maven.compiler.source>1.8</maven.compiler.source><junit.version>5.7.1</junit.version></properties><dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>${junit.version}</version><scope>test</scope></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.10</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.13</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-war-plugin</artifactId><version>3.3.1</version></plugin></plugins><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources></build>
</project>
test2.xml
<?xml version="1.0" encoding="UTF-8"?>
<students><student id="1" class="101"><name>Jack</name><age>21</age><gender>male</gender></student><student id="2" class="102"><name>Lucy</name><age>22</age><gender>female</gender></student><student id="3" class="103"><name>Lily</name><age>23</age><gender>female</gender></student>
</students>

测试结果如下:

XML - XML学习/XML文件解析器(C++)实现相关推荐

  1. Glib学习(17) Key-value文件解析器 Key-value file parser

    glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/ glib帮助文档:https://developer.gnome.org/glib/ 本节主 ...

  2. [翻译]运用文件解析器在任意文件中使用虚拟应用路径(~)

    原文出处:http://www.codeproject.com    Using the FileResolver to allow virtual application paths ( ~ ) i ...

  3. 使用springMVC提供的CommonsMultipartResolver文件解析器,实现文件轻松上传

    springMVC提供的前端控制器,可以拦截所有请求,指挥调度所有后台逻辑资源. 使用传统方式进行文件上传,需要我们手动解析request对象,获取文件上传项,再进行文件的上传. springMVC框 ...

  4. torrent文件解析器

    第二步工作是解析torrent文件,有了bencoding编码解析器 解析torrent文件当然是易如反掌的任务了. 实现的封装类CTorrentParser,完成的主要任务有: 1.判断torren ...

  5. 【glib】Key-value文件解析器

    1 头文件 2 描述 3 API 4 实例 4.1 本文Key-value文件解析器如下: 4.2 在准备一个Key-value文件示例文件 tt.txt 4.3 编译: 4.4 运行: 4.5 运行 ...

  6. 工具——XML文件解析器

        编程中经常用到XML文件作配置方式,但是常用的解析方法过于繁锁,XML的解析过程是有非常固定的套路的.     也就是说,对XML文件的解析程序,存在很多"制式代码"能否做 ...

  7. Boost学习之语法解析器--Spirit

    Boost.Spirit能使我们轻松地编写出一个简单脚本的语法解析器,它巧妙利用了元编程并重载了大量的C++操作符使得我们能够在C++里直接使用类似EBNF的语法构造出一个完整的语法解析器(同时也把C ...

  8. 学习笔记文件解析漏洞

    一.概念 文件解析漏洞主要由于网站管理员操作不当或者web服务器自身的漏洞,导致一些特殊文件被IIS.apache.nginx或其他web服务器在某种情况下解释成脚本文件执行 比如网站管理员配置不当, ...

  9. 网络编程学习笔记(RES_USE_INET6解析器选项)

    通过这个选项来通知解析器让gethostbyname返回IPv6地址而不是IPv4地址 1.应用 程序本身可以设置此选项,首先调用解析器的res_init函数,然后打开该选项: #include &l ...

最新文章

  1. linux shell sed 在一个文件中插入另一个文件
  2. ABP Framework:移除 EF Core Migrations 项目,统一数据上下文
  3. 浅谈Opencl四大模型之Memory Model
  4. 接口请求(get、post、head等)详解
  5. 你的GAN再不听话,就把它暴力肢解了吧,有用 | Demo · 代码
  6. VS快速定位文件、代码插件——DPack
  7. 利用PDM实现机械制造业的信息集成
  8. Less颜色混合函数(14)
  9. 移动硬盘访问错误 - 磁盘结构损坏且无法读取、拒绝访问
  10. 鸡啄米:C++编程入门系列之目录和总结http://www.jizhuomi.com/software/129.html
  11. 蓝牙mesh- Features和设备类型
  12. Nevron 3DChart创建有吸引力的3D和2D图表
  13. 如何用Jupyter中文集成版画一个图表
  14. isalpha() / isupper() / islower()函数
  15. 谁再瞧不起搬砖的我。。
  16. Go语言 rand(随机数)包
  17. Java编程思想笔记——并发3
  18. 华硕服务器主板型号命名规则,装机指南 华硕主板新命名规则解读
  19. 24个提高你的知识和技能极限的数据科学(机器学习)项目(免费)
  20. maven依赖asm_maven 导入asm的依赖 、 简单入门

热门文章

  1. Java面试题 java高级
  2. 为什么宝宝做错事被骂哭后,还要求抱抱?家长早知道早受益
  3. 算法——指定日期的星期推算
  4. 关于File()中的pathname的路径
  5. 国外数藏动态:7月6日至10日即将发售的藏品
  6. 如何提升网站关键词的优化排名?
  7. Alpine-Linux:仅5MB的Linux
  8. 使用双重while循环求百钱百鸡问题
  9. winform 学习笔记
  10. Facenet 原理介绍